first commit

This commit is contained in:
stuce-bot 2025-06-30 20:47:33 +02:00
commit 5893b00dd2
1669 changed files with 1982740 additions and 0 deletions

View file

@ -0,0 +1,293 @@
import argparse
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
from typing import Tuple
from ci.paths import PROJECT_ROOT
from ci.running_process import RunningProcess
BUILD_DIR = PROJECT_ROOT / "tests" / ".build"
BUILD_DIR.mkdir(parents=True, exist_ok=True)
def clean_build_directory():
print("Cleaning build directory...")
shutil.rmtree(BUILD_DIR, ignore_errors=True)
BUILD_DIR.mkdir(parents=True, exist_ok=True)
print("Build directory cleaned.")
HERE = Path(__file__).resolve().parent
WASM_BUILD = False
USE_ZIG = False
USE_CLANG = False
def _has_system_clang_compiler() -> bool:
CLANG = shutil.which("clang")
CLANGPP = shutil.which("clang++")
LLVM_AR = shutil.which("llvm-ar")
return CLANG is not None and CLANGPP is not None and LLVM_AR is not None
def use_clang_compiler() -> Tuple[Path, Path, Path]:
assert _has_system_clang_compiler(), "Clang system compiler not found"
CLANG = shutil.which("clang")
CLANGPP = shutil.which("clang++")
LLVM_AR = shutil.which("llvm-ar")
assert CLANG is not None, "clang compiler not found"
assert CLANGPP is not None, "clang++ compiler not found"
assert LLVM_AR is not None, "llvm-ar not found"
# Set environment variables for C and C++ compilers
os.environ["CC"] = CLANG
os.environ["CXX"] = CLANGPP
os.environ["AR"] = LLVM_AR
os.environ["CXXFLAGS"] = os.environ.get("CXXFLAGS", "") + " -ferror-limit=1"
os.environ["CFLAGS"] = os.environ.get("CFLAGS", "") + " -ferror-limit=1"
if WASM_BUILD:
wasm_flags = [
"--target=wasm32",
"-O3",
"-flto",
# "-nostdlib",
# "-Wl,--no-entry",
# "-Wl,--export-all",
# "-Wl,--lto-O3",
# "-Wl,-z,stack-size=8388608", # 8 * 1024 * 1024 (8MiB)
]
os.environ["CFLAGS"] = " ".join(wasm_flags)
os.environ["CXXFLAGS"] = " ".join(wasm_flags)
print(f"CC: {CLANG}")
print(f"CXX: {CLANGPP}")
print(f"AR: {LLVM_AR}")
return Path(CLANG), Path(CLANGPP), Path(LLVM_AR)
def use_zig_compiler() -> Tuple[Path, Path, Path]:
assert 0 == os.system(
"uv run python -m ziglang version"
), "Zig-clang compiler not found"
uv_path_str: str | None = shutil.which("uv")
assert uv_path_str is not None, "uv not found in PATH"
uv_path = Path(uv_path_str).resolve()
zig_command = f'"{uv_path}" run python -m ziglang'
# We are going to build up shell scripts that look like cc, c++, and ar. It will contain the actual build command.
CC_PATH = BUILD_DIR / "cc"
CXX_PATH = BUILD_DIR / "c++"
AR_PATH = BUILD_DIR / "ar"
if sys.platform == "win32":
CC_PATH = CC_PATH.with_suffix(".cmd")
CXX_PATH = CXX_PATH.with_suffix(".cmd")
AR_PATH = AR_PATH.with_suffix(".cmd")
CC_PATH.write_text(f"@echo off\n{zig_command} cc %* 2>&1\n")
CXX_PATH.write_text(f"@echo off\n{zig_command} c++ %* 2>&1\n")
AR_PATH.write_text(f"@echo off\n{zig_command} ar %* 2>&1\n")
else:
cc_cmd = f'#!/bin/bash\n{zig_command} cc "$@"\n'
cxx_cmd = f'#!/bin/bash\n{zig_command} c++ "$@"\n'
ar_cmd = f'#!/bin/bash\n{zig_command} ar "$@"\n'
CC_PATH.write_text(cc_cmd)
CXX_PATH.write_text(cxx_cmd)
AR_PATH.write_text(ar_cmd)
CC_PATH.chmod(0o755)
CXX_PATH.chmod(0o755)
AR_PATH.chmod(0o755)
# if WASM_BUILD:
# wasm_flags = [
# # "--target=wasm32",
# # "-O3",
# # "-flto",
# # "-nostdlib",
# "-Wl,--no-entry",
# # "-Wl,--export-all",
# # "-Wl,--lto-O3",
# "-Wl,-z,stack-size=8388608", # 8 * 1024 * 1024 (8MiB)
# ]
# os.environ["CFLAGS"] = " ".join(wasm_flags)
# os.environ["CXXFLAGS"] = " ".join(wasm_flags)
cc, cxx = CC_PATH, CXX_PATH
# use the system path, so on windows this looks like "C:\Program Files\Zig\zig.exe"
cc_path: Path | str = cc.resolve()
cxx_path: Path | str = cxx.resolve()
if sys.platform == "win32":
cc_path = str(cc_path).replace("/", "\\")
cxx_path = str(cxx_path).replace("/", "\\")
# print out the paths
print(f"CC: {cc_path}")
print(f"CXX: {cxx_path}")
print(f"AR: {AR_PATH}")
# sys.exit(1)
# Set environment variables for C and C++ compilers
os.environ["CC"] = str(cc_path)
os.environ["CXX"] = str(cxx_path)
os.environ["AR"] = str(AR_PATH)
return CC_PATH, CXX_PATH, AR_PATH
def run_command(command: str, cwd: Path | None = None) -> None:
process = RunningProcess(command, cwd=cwd)
process.wait()
if process.returncode != 0:
print(f"{Path(__file__).name}: Error executing command: {command}")
sys.exit(1)
def compile_fastled(specific_test: str | None = None) -> None:
if USE_ZIG:
print("USING ZIG COMPILER")
rtn = subprocess.run(
"python -m ziglang version", shell=True, capture_output=True
).returncode
zig_is_installed = rtn == 0
assert (
zig_is_installed
), 'Zig compiler not when using "python -m ziglang version" command'
use_zig_compiler()
elif USE_CLANG:
print("USING CLANG COMPILER")
use_clang_compiler()
cmake_configure_command_list: list[str] = [
"cmake",
"-S",
str(PROJECT_ROOT / "tests"),
"-B",
str(BUILD_DIR),
"-G",
"Ninja",
"-DCMAKE_VERBOSE_MAKEFILE=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
]
if WASM_BUILD:
cmake_configure_command_list.extend(
[
"-DCMAKE_C_COMPILER_TARGET=wasm32-wasi",
"-DCMAKE_CXX_COMPILER_TARGET=wasm32-wasi",
"-DCMAKE_C_COMPILER_WORKS=TRUE",
"-DCMAKE_CXX_COMPILER_WORKS=TRUE",
"-DCMAKE_SYSTEM_NAME=Generic",
"-DCMAKE_CROSSCOMPILING=TRUE",
"-DCMAKE_EXE_LINKER_FLAGS=-Wl,--no-entry -Wl,--export-all -Wl,--lto-O3 -Wl,-z,stack-size=8388608",
]
)
cmake_configure_command = subprocess.list2cmdline(cmake_configure_command_list)
run_command(cmake_configure_command, cwd=BUILD_DIR)
# Build the project
if specific_test:
cmake_build_command = f"cmake --build {BUILD_DIR} --target test_{specific_test}"
else:
cmake_build_command = f"cmake --build {BUILD_DIR}"
run_command(cmake_build_command)
print("FastLED library compiled successfully.")
def parse_arguments():
parser = argparse.ArgumentParser(
description="Compile FastLED library with different compiler options."
)
parser.add_argument("--use-zig", action="store_true", help="Use Zig compiler")
parser.add_argument("--use-clang", action="store_true", help="Use Clang compiler")
parser.add_argument("--wasm", action="store_true", help="Build for WebAssembly")
parser.add_argument(
"--clean",
action="store_true",
help="Clean the build directory before compiling",
)
parser.add_argument(
"--test",
help="Specific test to compile (without test_ prefix)",
)
return parser.parse_args()
def get_build_info(args: argparse.Namespace) -> dict[str, str | dict[str, str]]:
return {
"USE_ZIG": str(USE_ZIG),
"USE_CLANG": str(USE_CLANG),
"WASM_BUILD": str(WASM_BUILD),
"CC": os.environ.get("CC", ""),
"CXX": os.environ.get("CXX", ""),
"AR": os.environ.get("AR", ""),
"CFLAGS": os.environ.get("CFLAGS", ""),
"CXXFLAGS": os.environ.get("CXXFLAGS", ""),
"ARGS": {
"use_zig": str(args.use_zig),
"use_clang": str(args.use_clang),
"wasm": str(args.wasm),
},
}
def should_clean_build(build_info: dict[str, str | dict[str, str]]) -> bool:
build_info_file = BUILD_DIR / "build_info.json"
if not build_info_file.exists():
return True
with open(build_info_file, "r") as f:
old_build_info = json.load(f)
return old_build_info != build_info
def update_build_info(build_info: dict[str, str | dict[str, str]]):
build_info_file = BUILD_DIR / "build_info.json"
with open(build_info_file, "w") as f:
json.dump(build_info, f, indent=2)
def main() -> None:
global USE_ZIG, USE_CLANG, WASM_BUILD
args = parse_arguments()
USE_ZIG = args.use_zig # use Zig's clang compiler
USE_CLANG = args.use_clang # Use pure Clang for WASM builds
WASM_BUILD = args.wasm
using_gcc = not USE_ZIG and not USE_CLANG and not WASM_BUILD
if using_gcc:
if not shutil.which("g++"):
print(
"gcc compiler not found in PATH, falling back zig's built in clang compiler"
)
USE_ZIG = True
USE_CLANG = False
if USE_CLANG:
if not _has_system_clang_compiler():
print(
"Clang compiler not found in PATH, falling back to Zig-clang compiler"
)
USE_ZIG = True
USE_CLANG = False
os.chdir(str(HERE))
print(f"Current directory: {Path('.').absolute()}")
build_info = get_build_info(args)
if args.clean or should_clean_build(build_info):
clean_build_directory()
compile_fastled(args.test)
update_build_info(build_info)
print("FastLED library compiled successfully.")
if __name__ == "__main__":
main()