Started Raspberry Pi Pico build target
This commit is contained in:
parent
3a57fd7373
commit
c89acbbdfb
|
|
@ -1,4 +1,6 @@
|
|||
obj/
|
||||
bin/
|
||||
build_pico/
|
||||
*.o
|
||||
*.pdb
|
||||
CMakeLists.txt
|
||||
|
|
|
|||
252
SLS_C/build.py
252
SLS_C/build.py
|
|
@ -4,6 +4,7 @@ import sys
|
|||
import subprocess
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import platform
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# CONFIG
|
||||
|
|
@ -16,22 +17,101 @@ BIN_DIR = Path("bin")
|
|||
TARGET = BIN_DIR / "sls"
|
||||
TEST_TARGET = BIN_DIR / "sls_tests"
|
||||
|
||||
# Platform-specific settings
|
||||
PICO_SDK_PATH = os.environ.get("PICO_SDK_PATH", Path.home() / "pico/pico-sdk")
|
||||
PICO_BUILD_DIR = Path("build_pico")
|
||||
|
||||
# Unix gcc/clang flags
|
||||
COMMON_FLAGS = ["-std=c99", "-Wall", "-Wextra", "-Werror", "-Iinclude", "-g"]
|
||||
TEST_FLAGS = ["-std=c99", "-Wall", "-Wextra", "-Wno-unused-function", "-Werror",
|
||||
"-Iinclude", "-g", "-O0"]
|
||||
|
||||
# macOS-specific flags (for cross-compilation if needed)
|
||||
MACOS_FLAGS = ["-std=c99", "-Wall", "-Wextra", "-Werror", "-Iinclude", "-g",
|
||||
"-mmacosx-version-min=10.13"]
|
||||
|
||||
# Windows MSVC flags
|
||||
MSVC_FLAGS = ["/std:c11", "/Zi", "/Iinclude"]
|
||||
MSVC_TEST_FLAGS = MSVC_FLAGS + []
|
||||
|
||||
# RP2040 settings
|
||||
RP2040_CMAKE_TEMPLATE = """cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# Pico SDK initialization
|
||||
include($ENV{{PICO_SDK_PATH}}/external/pico_sdk_import.cmake)
|
||||
|
||||
project({project_name} C CXX ASM)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
# Main executable
|
||||
add_executable({project_name}
|
||||
{source_files}
|
||||
)
|
||||
|
||||
# Add include directories
|
||||
target_include_directories({project_name} PRIVATE
|
||||
${{CMAKE_CURRENT_LIST_DIR}}/include
|
||||
)
|
||||
|
||||
# Add compile definitions
|
||||
target_compile_definitions({project_name} PRIVATE
|
||||
PICO_BUILD=1
|
||||
GIT_COMMIT_HASH="{git_hash}"
|
||||
)
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries({project_name}
|
||||
pico_stdlib
|
||||
hardware_uart
|
||||
hardware_gpio
|
||||
)
|
||||
|
||||
# Enable USB/UART output
|
||||
pico_enable_stdio_usb({project_name} 1)
|
||||
pico_enable_stdio_uart({project_name} 1)
|
||||
|
||||
# Create map/bin/hex/uf2 files
|
||||
pico_add_extra_outputs({project_name})
|
||||
"""
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# PLATFORM DETECTION
|
||||
# ---------------------------------------------------------------------
|
||||
def detect_platform():
|
||||
"""Detect the current operating system"""
|
||||
system = platform.system()
|
||||
if system == "Darwin":
|
||||
return "macos"
|
||||
elif system == "Windows":
|
||||
return "windows"
|
||||
elif system == "Linux":
|
||||
return "linux"
|
||||
return "unknown"
|
||||
|
||||
PLATFORM = detect_platform()
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# COMPILER DETECTION
|
||||
# ---------------------------------------------------------------------
|
||||
def detect_compiler():
|
||||
if os.name == "nt":
|
||||
def detect_compiler(target_platform=None):
|
||||
"""Detect appropriate compiler for the target platform"""
|
||||
if target_platform == "rp2040":
|
||||
return ("arm-none-eabi-gcc", "gcc")
|
||||
|
||||
target = target_platform or PLATFORM
|
||||
|
||||
if target == "windows" or os.name == "nt":
|
||||
return ("cl", "msvc")
|
||||
return ("gcc", "gcc")
|
||||
elif target == "macos":
|
||||
# Prefer clang on macOS
|
||||
if shutil.which("clang"):
|
||||
return ("clang", "gcc")
|
||||
return ("gcc", "gcc")
|
||||
else:
|
||||
return ("gcc", "gcc")
|
||||
|
||||
CC, CC_KIND = detect_compiler()
|
||||
|
||||
|
|
@ -79,7 +159,7 @@ def mkdir(p: Path):
|
|||
|
||||
|
||||
def run(cmd):
|
||||
print(">>", " ".join(cmd))
|
||||
print(">>", " ".join(str(c) for c in cmd))
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
|
|
@ -96,7 +176,7 @@ def is_up_to_date(src, obj, dep):
|
|||
# ---------------------------------------------------------------------
|
||||
# BUILD RULES
|
||||
# ---------------------------------------------------------------------
|
||||
def compile_source(src: Path, is_test=False):
|
||||
def compile_source(src: Path, is_test=False, target_platform=None):
|
||||
mkdir(OBJ_DIR)
|
||||
obj = OBJ_DIR / (src.stem + ".o")
|
||||
dep = OBJ_DIR / (src.stem + ".d")
|
||||
|
|
@ -104,13 +184,19 @@ def compile_source(src: Path, is_test=False):
|
|||
if is_up_to_date(src, obj, dep):
|
||||
return obj
|
||||
|
||||
if CC_KIND == "msvc":
|
||||
compiler, kind = detect_compiler(target_platform)
|
||||
|
||||
if kind == "msvc":
|
||||
flags = MSVC_TEST_FLAGS if is_test else MSVC_FLAGS
|
||||
cmd = [CC] + flags + ["/Fo" + str(obj), "/c", str(src),
|
||||
cmd = [compiler] + flags + ["/Fo" + str(obj), "/c", str(src),
|
||||
f"/DGIT_COMMIT_HASH=\"{GIT_HASH}\""]
|
||||
else:
|
||||
flags = TEST_FLAGS if is_test else COMMON_FLAGS
|
||||
cmd = [CC] + flags + [
|
||||
if target_platform == "macos":
|
||||
flags = MACOS_FLAGS if not is_test else TEST_FLAGS + ["-mmacosx-version-min=10.13"]
|
||||
else:
|
||||
flags = TEST_FLAGS if is_test else COMMON_FLAGS
|
||||
|
||||
cmd = [compiler] + flags + [
|
||||
f"-DGIT_COMMIT_HASH=\"{GIT_HASH}\"",
|
||||
"-MMD", "-MP",
|
||||
"-c", str(src), "-o", str(obj)
|
||||
|
|
@ -120,12 +206,14 @@ def compile_source(src: Path, is_test=False):
|
|||
return obj
|
||||
|
||||
|
||||
def link_executable(objects, output: Path):
|
||||
def link_executable(objects, output: Path, target_platform=None):
|
||||
mkdir(BIN_DIR)
|
||||
if CC_KIND == "msvc":
|
||||
cmd = [CC] + list(map(str, objects)) + ["/Fe" + str(output)]
|
||||
compiler, kind = detect_compiler(target_platform)
|
||||
|
||||
if kind == "msvc":
|
||||
cmd = [compiler] + list(map(str, objects)) + ["/Fe" + str(output)]
|
||||
else:
|
||||
cmd = [CC] + list(map(str, objects)) + ["-lm", "-o", str(output)]
|
||||
cmd = [compiler] + list(map(str, objects)) + ["-lm", "-o", str(output)]
|
||||
run(cmd)
|
||||
|
||||
|
||||
|
|
@ -148,6 +236,96 @@ def generate_tests():
|
|||
return True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# RP2040 BUILD
|
||||
# ---------------------------------------------------------------------
|
||||
def check_pico_sdk():
|
||||
"""Check if Pico SDK is available"""
|
||||
sdk_path = Path(PICO_SDK_PATH)
|
||||
if not sdk_path.exists():
|
||||
print(f"ERROR: Pico SDK not found at {sdk_path}")
|
||||
print("Please set PICO_SDK_PATH environment variable or install SDK at ~/pico/pico-sdk")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def generate_pico_cmake(project_name="sls"):
|
||||
"""Generate CMakeLists.txt for RP2040 build"""
|
||||
sources = list(SRC_DIR.glob("*.c"))
|
||||
# Exclude test runner if present
|
||||
sources = [s for s in sources if "test" not in s.stem.lower()]
|
||||
|
||||
source_files = "\n".join(f" {s}" for s in sources)
|
||||
|
||||
cmake_content = RP2040_CMAKE_TEMPLATE.format(
|
||||
project_name=project_name,
|
||||
source_files=source_files,
|
||||
git_hash=GIT_HASH
|
||||
)
|
||||
|
||||
cmake_file = Path("CMakeLists.txt")
|
||||
with open(cmake_file, "w") as f:
|
||||
f.write(cmake_content)
|
||||
|
||||
print(f"Generated {cmake_file}")
|
||||
|
||||
|
||||
def build_rp2040():
|
||||
"""Build for RP2040 using CMake"""
|
||||
if not check_pico_sdk():
|
||||
return False
|
||||
|
||||
print("\n=== Building for RP2040 ===\n")
|
||||
|
||||
# Generate CMakeLists.txt
|
||||
generate_pico_cmake()
|
||||
|
||||
# Create build directory
|
||||
mkdir(PICO_BUILD_DIR)
|
||||
|
||||
# Run CMake
|
||||
cmake_cmd = [
|
||||
"cmake",
|
||||
"-B", str(PICO_BUILD_DIR),
|
||||
"-S", ".",
|
||||
f"-DPICO_SDK_PATH={PICO_SDK_PATH}"
|
||||
]
|
||||
run(cmake_cmd)
|
||||
|
||||
# Build
|
||||
build_cmd = ["cmake", "--build", str(PICO_BUILD_DIR), "-j4"]
|
||||
run(build_cmd)
|
||||
|
||||
# Show output files
|
||||
uf2_file = PICO_BUILD_DIR / "sls.uf2"
|
||||
if uf2_file.exists():
|
||||
print(f"\nBuild successful! UF2 file: {uf2_file}")
|
||||
print("To flash: Copy this file to your Pico in BOOTSEL mode")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# MACOS BUILD
|
||||
# ---------------------------------------------------------------------
|
||||
def build_macos():
|
||||
"""Build for macOS (can be run on macOS or cross-compile on Linux)"""
|
||||
print("\n=== Building for macOS ===\n")
|
||||
|
||||
if PLATFORM != "macos" and PLATFORM != "linux":
|
||||
print("ERROR: macOS builds require macOS or Linux with osxcross")
|
||||
return False
|
||||
|
||||
sources = list(SRC_DIR.glob("*.c"))
|
||||
objects = [compile_source(s, is_test=False, target_platform="macos") for s in sources]
|
||||
|
||||
macos_target = BIN_DIR / "sls_macos"
|
||||
link_executable(objects, macos_target, target_platform="macos")
|
||||
|
||||
print(f"\nBuild successful! Binary: {macos_target}")
|
||||
return True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# TARGETS
|
||||
# ---------------------------------------------------------------------
|
||||
|
|
@ -171,6 +349,10 @@ def build_tests():
|
|||
def clean():
|
||||
shutil.rmtree(OBJ_DIR, ignore_errors=True)
|
||||
shutil.rmtree(BIN_DIR, ignore_errors=True)
|
||||
shutil.rmtree(PICO_BUILD_DIR, ignore_errors=True)
|
||||
cmake_file = Path("CMakeLists.txt")
|
||||
if cmake_file.exists():
|
||||
cmake_file.unlink()
|
||||
print("Cleaned.")
|
||||
|
||||
|
||||
|
|
@ -194,20 +376,49 @@ def debug_tests():
|
|||
subprocess.call(["gdb", str(TEST_TARGET)])
|
||||
|
||||
|
||||
def show_help():
|
||||
help_text = """
|
||||
Build Script for Multi-Platform Compilation
|
||||
============================================
|
||||
|
||||
Usage: python3 build.py [command]
|
||||
|
||||
Commands:
|
||||
all, main, build Build for current platform
|
||||
run Build and run program
|
||||
test Build and run tests
|
||||
debug Build tests and run debugger
|
||||
clean Remove build artifacts
|
||||
|
||||
macos Build for macOS
|
||||
pico, rp2040 Build for RP2040 (Raspberry Pi Pico)
|
||||
|
||||
help Show this help message
|
||||
|
||||
Environment Variables:
|
||||
PICO_SDK_PATH Path to Pico SDK (default: ~/pico/pico-sdk)
|
||||
|
||||
Examples:
|
||||
python3 build.py build # Build for current platform
|
||||
python3 build.py pico # Build for RP2040
|
||||
python3 build.py macos # Build for macOS
|
||||
python3 build.py clean # Clean all build files
|
||||
"""
|
||||
print(help_text)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# ENTRY POINT
|
||||
# ---------------------------------------------------------------------
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 build.py [all|build|test|run|debug|clean]")
|
||||
show_help()
|
||||
return
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
match cmd:
|
||||
case "all" | "main":
|
||||
build_main()
|
||||
case "build":
|
||||
case "all" | "main" | "build":
|
||||
build_main()
|
||||
case "run":
|
||||
run_main()
|
||||
|
|
@ -217,8 +428,15 @@ def main():
|
|||
debug_tests()
|
||||
case "clean":
|
||||
clean()
|
||||
case "macos":
|
||||
build_macos()
|
||||
case "pico" | "rp2040":
|
||||
build_rp2040()
|
||||
case "help" | "-h" | "--help":
|
||||
show_help()
|
||||
case _:
|
||||
print(f"Unknown target: {cmd}")
|
||||
print("Run 'python3 build.py help' for usage information")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Reference in New Issue