initial commit
This commit is contained in:
196
libraries/FastLED/ci/compiler/build_dynamic_lib.py
Normal file
196
libraries/FastLED/ci/compiler/build_dynamic_lib.py
Normal file
@@ -0,0 +1,196 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
FastLED Dynamic Library Builder
|
||||
Builds FastLED as a shared/dynamic library for unit testing
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from ci.compiler.clang_compiler import (
|
||||
BuildFlags,
|
||||
Compiler,
|
||||
CompilerOptions,
|
||||
Result,
|
||||
)
|
||||
from ci.util.paths import PROJECT_ROOT
|
||||
|
||||
|
||||
def build_fastled_dynamic_library(build_dir: Path) -> Path:
|
||||
"""Build FastLED as a dynamic library"""
|
||||
print("Building FastLED dynamic library...")
|
||||
|
||||
# Define library path with appropriate extension
|
||||
if sys.platform == "win32":
|
||||
fastled_lib_path = build_dir / "fastled.dll"
|
||||
else:
|
||||
fastled_lib_path = build_dir / "libfastled.so"
|
||||
|
||||
# Configure compiler with shared library flags
|
||||
settings = CompilerOptions(
|
||||
include_path=str(Path(PROJECT_ROOT) / "src"),
|
||||
defines=[
|
||||
"STUB_PLATFORM",
|
||||
"ARDUINO=10808",
|
||||
"FASTLED_USE_STUB_ARDUINO",
|
||||
"SKETCH_HAS_LOTS_OF_MEMORY=1",
|
||||
"FASTLED_STUB_IMPL",
|
||||
"FASTLED_FORCE_NAMESPACE=1",
|
||||
"FASTLED_TESTING",
|
||||
"FASTLED_NO_AUTO_NAMESPACE",
|
||||
"FASTLED_NO_PINMAP",
|
||||
"HAS_HARDWARE_PIN_SUPPORT",
|
||||
# "FASTLED_DEBUG_LEVEL=1",
|
||||
# "BUILDING_FASTLED_DLL", # New define for DLL exports
|
||||
# "FASTLED_EXPORT=__declspec(dllexport)" if sys.platform == "win32" else "FASTLED_EXPORT=", # DLL exports for Windows
|
||||
],
|
||||
std_version="c++17",
|
||||
compiler="clang++",
|
||||
compiler_args=[
|
||||
# NOTE: All compiler flags should come from build_unit.toml
|
||||
# Keep only platform-specific include paths and shared library flags
|
||||
"-I" + str(Path(PROJECT_ROOT) / "src/platforms/stub"),
|
||||
"-I" + str(Path(PROJECT_ROOT) / "tests"),
|
||||
# Add shared library flags - platform specific
|
||||
"-shared" if sys.platform != "win32" else "/DLL",
|
||||
"-fPIC" if sys.platform != "win32" else "",
|
||||
],
|
||||
use_pch=True,
|
||||
parallel=True,
|
||||
)
|
||||
|
||||
# Load build flags from TOML
|
||||
build_flags_path = Path(PROJECT_ROOT) / "ci" / "build_unit.toml"
|
||||
build_flags = BuildFlags.parse(
|
||||
build_flags_path, quick_build=False, strict_mode=False
|
||||
)
|
||||
|
||||
compiler = Compiler(settings, build_flags)
|
||||
|
||||
# Compile all FastLED source files
|
||||
fastled_src_dir = Path(PROJECT_ROOT) / "src"
|
||||
all_cpp_files = list(fastled_src_dir.rglob("*.cpp"))
|
||||
|
||||
print(f"Found {len(all_cpp_files)} FastLED source files")
|
||||
|
||||
# Compile to object files
|
||||
object_files: List[Path] = []
|
||||
for src_file in all_cpp_files:
|
||||
relative_path = src_file.relative_to(fastled_src_dir)
|
||||
safe_name = (
|
||||
str(relative_path.with_suffix("")).replace("/", "_").replace("\\", "_")
|
||||
)
|
||||
obj_path = build_dir / f"{safe_name}_fastled.o"
|
||||
|
||||
future = compiler.compile_cpp_file(
|
||||
src_file,
|
||||
output_path=obj_path,
|
||||
additional_flags=[
|
||||
"-c",
|
||||
"-DFASTLED_STUB_IMPL",
|
||||
"-DFASTLED_FORCE_NAMESPACE=1",
|
||||
"-DFASTLED_NO_AUTO_NAMESPACE",
|
||||
"-DFASTLED_NO_PINMAP",
|
||||
"-DPROGMEM=",
|
||||
"-DHAS_HARDWARE_PIN_SUPPORT",
|
||||
"-DFASTLED_ENABLE_JSON=1",
|
||||
"-fno-exceptions",
|
||||
"-fno-rtti",
|
||||
"-fPIC", # Position Independent Code for shared library
|
||||
],
|
||||
)
|
||||
result: Result = future.result()
|
||||
if not result.ok:
|
||||
print(f"ERROR: Failed to compile {src_file}: {result.stderr}")
|
||||
continue
|
||||
|
||||
object_files.append(obj_path)
|
||||
|
||||
print(f"Linking {len(object_files)} object files into dynamic library...")
|
||||
|
||||
# Link as shared library
|
||||
if sys.platform == "win32":
|
||||
# Use lld-link for Windows DLL creation
|
||||
link_cmd = [
|
||||
"lld-link",
|
||||
"/DLL",
|
||||
"/NOLOGO",
|
||||
"/OUT:" + str(fastled_lib_path),
|
||||
"/LIBPATH:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.19041.0/um/x64",
|
||||
"/LIBPATH:C:/Program Files (x86)/Windows Kits/10/Lib/10.0.19041.0/ucrt/x64",
|
||||
"/LIBPATH:C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.37.32822/lib/x64",
|
||||
*[str(obj) for obj in object_files],
|
||||
"msvcrt.lib",
|
||||
"legacy_stdio_definitions.lib",
|
||||
"kernel32.lib",
|
||||
"user32.lib",
|
||||
]
|
||||
else:
|
||||
link_cmd = [
|
||||
"clang++",
|
||||
"-shared",
|
||||
"-o",
|
||||
str(fastled_lib_path),
|
||||
*[str(obj) for obj in object_files],
|
||||
]
|
||||
|
||||
try:
|
||||
# Use streaming to prevent buffer overflow
|
||||
process = subprocess.Popen(
|
||||
link_cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
)
|
||||
|
||||
stdout_lines: list[str] = []
|
||||
stderr_lines: list[str] = []
|
||||
|
||||
while True:
|
||||
stdout_line = process.stdout.readline() if process.stdout else ""
|
||||
stderr_line = process.stderr.readline() if process.stderr else ""
|
||||
|
||||
if stdout_line:
|
||||
stdout_lines.append(stdout_line.rstrip())
|
||||
if stderr_line:
|
||||
stderr_lines.append(stderr_line.rstrip())
|
||||
|
||||
if process.poll() is not None:
|
||||
remaining_stdout = process.stdout.read() if process.stdout else ""
|
||||
remaining_stderr = process.stderr.read() if process.stderr else ""
|
||||
|
||||
if remaining_stdout:
|
||||
for line in remaining_stdout.splitlines():
|
||||
stdout_lines.append(line.rstrip())
|
||||
if remaining_stderr:
|
||||
for line in remaining_stderr.splitlines():
|
||||
stderr_lines.append(line.rstrip())
|
||||
break
|
||||
|
||||
stderr_result = "\n".join(stderr_lines)
|
||||
if process.returncode != 0:
|
||||
raise Exception(f"Failed to create dynamic library: {stderr_result}")
|
||||
|
||||
print(f"Successfully created dynamic library: {fastled_lib_path}")
|
||||
return fastled_lib_path
|
||||
|
||||
except Exception as e:
|
||||
print(f"ERROR: Exception during library creation: {e}")
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create build directory in temp
|
||||
import tempfile
|
||||
|
||||
build_dir = Path(tempfile.gettempdir()) / "fastled_test_build"
|
||||
build_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Build the dynamic library
|
||||
build_fastled_dynamic_library(build_dir)
|
||||
Reference in New Issue
Block a user