diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68f0e58..d8fea12 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,16 +18,16 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - name: Checkout pymcu-rp2040 + - name: Checkout pymcu-arm uses: actions/checkout@v4 with: - path: pymcu-rp2040 + path: pymcu-arm - name: Checkout pymcu monorepo uses: actions/checkout@v4 with: repository: PyMCU/PyMCU - ref: development # TODO: remove after PR #34 is merged to main + ref: main path: pymcu submodules: false @@ -39,16 +39,16 @@ jobs: - name: Build pymcuc compiler shell: bash working-directory: pymcu - run: dotnet publish src/compiler/PyMCU.csproj -c Release -o ../pymcu-rp2040/build/bin --nologo + run: dotnet publish src/compiler/PyMCU.csproj -c Release -o ../pymcu-arm/build/bin --nologo - - name: Build pymcuc-rp2040 backend CLI + - name: Build pymcuc-arm backend CLI shell: bash - working-directory: pymcu-rp2040 - run: dotnet publish src/csharp/cli/PyMCU.Backend.RP2040.Cli.csproj -c Release -o build/bin --nologo + working-directory: pymcu-arm + run: dotnet publish src/csharp/cli/PyMCU.Backend.ARM.Cli.csproj -c Release -o build/bin --nologo # --------------------------------------------------------------------------- # Full integration tests (RP2040 LLVM pipeline). Linux only — uses native - # LLVM tools downloaded by pymcu-rp2040-toolchain for the linux-x64 platform. + # LLVM tools downloaded by pymcu-arm-toolchain for the linux-x64 platform. # --------------------------------------------------------------------------- integration: name: Integration Tests (RP2040) @@ -57,10 +57,10 @@ jobs: contents: read steps: - - name: Checkout pymcu-rp2040 + - name: Checkout pymcu-arm uses: actions/checkout@v4 with: - path: pymcu-rp2040 + path: pymcu-arm # Checkout monorepo to build pymcuc (compiler binary). # TODO: replace with `pip install pymcu-compiler` once published to PyPI. @@ -68,7 +68,7 @@ jobs: uses: actions/checkout@v4 with: repository: PyMCU/PyMCU - ref: development # TODO: remove after PR #34 is merged to main + ref: main path: pymcu submodules: recursive @@ -91,51 +91,51 @@ jobs: working-directory: pymcu run: | dotnet publish src/compiler/PyMCU.csproj \ - -c Release -o ../pymcu-rp2040/build/bin --nologo + -c Release -o ../pymcu-arm/build/bin --nologo - - name: Build pymcuc-rp2040 backend CLI - working-directory: pymcu-rp2040 + - name: Build pymcuc-arm backend CLI + working-directory: pymcu-arm run: | - dotnet publish src/csharp/cli/PyMCU.Backend.RP2040.Cli.csproj \ + dotnet publish src/csharp/cli/PyMCU.Backend.ARM.Cli.csproj \ -c Release -o build/bin --nologo - name: Install Python dependencies - working-directory: pymcu-rp2040 + working-directory: pymcu-arm run: | uv venv .venv uv pip install --python .venv pymcu-sdk uv pip install --python .venv -e ../pymcu/lib # development stdlib - uv pip install --python .venv pymcu-rp2040-toolchain + uv pip install --python .venv pymcu-arm-toolchain uv pip install --python .venv -e ../pymcu uv pip install --python .venv -e . --no-deps uv pip install --python .venv -e ../pymcu/external/pymcu-micropython uv pip install --python .venv -e ../pymcu/external/pymcu-circuitpython - name: Configure environment - working-directory: pymcu-rp2040 + working-directory: pymcu-arm run: | - echo "$GITHUB_WORKSPACE/pymcu-rp2040/.venv/bin" >> $GITHUB_PATH - echo "$GITHUB_WORKSPACE/pymcu-rp2040/build/bin" >> $GITHUB_PATH - echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/pymcu-rp2040/.venv" >> $GITHUB_ENV + echo "$GITHUB_WORKSPACE/pymcu-arm/.venv/bin" >> $GITHUB_PATH + echo "$GITHUB_WORKSPACE/pymcu-arm/build/bin" >> $GITHUB_PATH + echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/pymcu-arm/.venv" >> $GITHUB_ENV - - name: Pre-seed RP2040 toolchain cache + - name: Pre-seed ARM toolchain cache # get_tool() downloads 300+ MB from GitHub Releases on first call. # Run it here (outside the 120s test timeout) so the tools are cached # before the integration tests trigger them via Rp2040LlvmToolchain. - working-directory: pymcu-rp2040 + working-directory: pymcu-arm run: | - "$GITHUB_WORKSPACE/pymcu-rp2040/.venv/bin/python3" -c " - import pymcu_rp2040_toolchain as tc + "$GITHUB_WORKSPACE/pymcu-arm/.venv/bin/python3" -c " + import pymcu_arm_toolchain as tc for name in tc.TOOLS: print(name, '->', tc.get_tool(name)) " - name: Restore integration test packages - working-directory: pymcu-rp2040 + working-directory: pymcu-arm run: dotnet restore tests/integration/PyMCU.IntegrationTests.csproj --nologo - name: Run integration tests - working-directory: pymcu-rp2040 + working-directory: pymcu-arm run: | dotnet test tests/integration/PyMCU.IntegrationTests.csproj \ --no-restore \ @@ -151,5 +151,5 @@ jobs: uses: actions/upload-artifact@v4 with: name: integration-test-results - path: pymcu-rp2040/test-results/ + path: pymcu-arm/test-results/ retention-days: 15 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0da64c7..4dc9466 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -28,8 +28,13 @@ jobs: os: windows-latest steps: - - name: Checkout pymcu-rp2040 + # Both repos checked out as siblings so the relative csproj path + # ../../../../pymcu/extensions/pymcu-sdk/csharp/PyMCU.Backend.SDK.csproj + # resolves correctly from src/csharp/lib/ inside pymcu-arm/. + - name: Checkout pymcu-arm uses: actions/checkout@v4 + with: + path: pymcu-arm - name: Checkout pymcu monorepo (SDK dependency) uses: actions/checkout@v4 @@ -39,16 +44,18 @@ jobs: path: pymcu sparse-checkout: | extensions/pymcu-sdk/csharp + global.json - name: Set up .NET 10 uses: actions/setup-dotnet@v4 with: - dotnet-version: "10.x" + global-json-file: pymcu/global.json - name: Set up uv uses: astral-sh/setup-uv@v5 - name: Build wheel + working-directory: pymcu-arm env: DOTNET_RID: ${{ matrix.dotnet_rid }} WHEEL_PLATFORM_TAG: ${{ matrix.wheel_platform_tag }} @@ -58,7 +65,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: dist-${{ matrix.name }} - path: dist/*.whl + path: pymcu-arm/dist/*.whl retention-days: 15 publish-pypi: @@ -82,36 +89,3 @@ jobs: - name: Publish to PyPI run: uv publish dist/* - - publish-gitea: - name: Publish to Gitea (private index) - needs: [build-wheels] - if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - environment: gitea - permissions: - contents: read - - steps: - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: dist - merge-multiple: true - - - name: Connect to Headscale network - uses: tailscale/github-action@v4 - with: - authkey: ${{ secrets.HEADSCALE_AUTH_KEY }} - args: --login-server ${{ secrets.HEADSCALE_URL }} - - - name: Set up uv - uses: astral-sh/setup-uv@v5 - - - name: Publish to Gitea - run: | - uv publish \ - --publish-url "${{ secrets.PRIVATE_PYPI_URL }}" \ - --username "${{ secrets.PRIVATE_PYPI_USERNAME }}" \ - --password "${{ secrets.PRIVATE_PYPI_TOKEN }}" \ - dist/* diff --git a/README.md b/README.md index 68fbdbb..0b281ed 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,49 @@ -# pymcu-rp2040 +# pymcu-arm -RP2040 (Raspberry Pi Pico, dual ARM Cortex-M0+) support for the PyMCU compiler. +ARM (Cortex-M) support for the PyMCU compiler: LLVM-IR codegen backend + LLVM toolchain driver. -Unlike the AVR/PIC/RISC-V backends, this backend does **not** emit assembly -directly. It lowers the architecture-agnostic PyMCU IR (`.mir`) to **LLVM IR -text (`.ll`)** and hands it to LLVM, so register allocation, instruction -selection, the AAPCS calling convention and all optimization passes are done by -LLVM targeting `thumbv6m-none-eabi` (`-mcpu=cortex-m0plus`). +Unlike the AVR/PIC/RISC-V backends, this backend does **not** emit assembly directly. It lowers PyMCU's architecture-agnostic IR (`.mir`) to **LLVM IR text (`.ll`)** and hands it to LLVM — so register allocation, instruction selection, the AAPCS calling convention, and all optimization passes are done by LLVM. + +Currently supported targets: + +| Target | Triple | CPU | +|---|---|---| +| RP2040 (Raspberry Pi Pico) | `thumbv6m-none-eabi` | `cortex-m0plus` | + +The codegen is chip-agnostic: only `-mtriple`/`-mcpu` change per target. ## Pipeline ``` -pymcuc --emit-ir -> firmware.mir (target-agnostic IR, 32-bit pointers) -pymcuc-rp2040 (this pkg) -> firmware.ll (LLVM IR text) -LLVM toolchain -> opt -> llc -> ld.lld -> llvm-objcopy - + generic boot2 (crc32) + crt0 -> firmware.bin +pymcuc --emit-ir → firmware.mir (target-agnostic IR, 32-bit pointers) +pymcuc-arm (this pkg) → firmware.ll (LLVM IR text) +LLVM toolchain → opt → llc → ld.lld → llvm-objcopy + + generic boot2 (crc32) + crt0 → firmware.bin ``` The flat flash image (`firmware.bin`, boot2 at offset 0) is what the RP2040Sharp emulator's `PicoSimulation.LoadFlash(...)` consumes in the integration tests. +## Installation + +```bash +pip install pymcu-arm +``` + +LLVM tools are resolved (in order) from the `pymcu-arm-toolchain` wheel cache, +common system install paths (`/opt/homebrew/opt/llvm/bin`, `/usr/lib/llvm/bin`), +or `PATH`. A system LLVM (`brew install llvm lld` / `apt install llvm lld`) also +works with no extra package. + ## Layout -- `src/python/pymcu/backend/rp2040/` - backend plugin (wraps the AOT binary) -- `src/csharp/lib/` - `Rp2040BackendProvider` + `Targets/RP2040/Rp2040LlvmCodeGen` -- `src/csharp/cli/` - `pymcuc-rp2040` runner CLI -- `src/runtime/` - generic boot2, crt0 startup, linker script +``` +src/python/pymcu/backend/rp2040/ backend plugin — wraps pymcuc-arm +src/python/pymcu/toolchain/rp2040/ LLVM toolchain driver (opt → firmware.bin) +src/csharp/lib/ Rp2040BackendProvider + Targets/RP2040/Rp2040LlvmCodeGen +src/csharp/cli/ pymcuc-arm runner CLI +src/runtime/ generic boot2 (crc32), crt0, rp2040.ld linker script +``` ## Status diff --git a/hatch_build.py b/hatch_build.py index bb884c2..ca998d7 100644 --- a/hatch_build.py +++ b/hatch_build.py @@ -1,10 +1,10 @@ # hatch_build.py -# Custom hatchling build hook: compiles the pymcuc-rp2040 AOT binary and places -# it at src/python/pymcu/backend/rp2040/pymcuc-rp2040 before wheel packaging. +# Custom hatchling build hook: compiles the pymcuc-arm AOT binary and places +# it at src/python/pymcu/backend/rp2040/pymcuc-arm before wheel packaging. # # Environment variables: # PYMCU_SKIP_DOTNET_BUILD=1 -# Skip dotnet publish and use an existing binary at build/bin/pymcuc-rp2040. +# Skip dotnet publish and use an existing binary at build/bin/pymcuc-arm. # When no binary exists there (e.g. sdist-only builds), the hook returns # early and produces a source-only package. # DOTNET_RID @@ -30,7 +30,7 @@ class CustomBuildHook(BuildHookInterface): def initialize(self, version: str, build_data: dict) -> None: root = Path(self.root) - binary_name = "pymcuc-rp2040.exe" if sys.platform == "win32" else "pymcuc-rp2040" + binary_name = "pymcuc-arm.exe" if sys.platform == "win32" else "pymcuc-arm" dst = root / "src" / "python" / "pymcu" / "backend" / "rp2040" / binary_name src = root / "build" / "bin" / binary_name @@ -49,7 +49,7 @@ def initialize(self, version: str, build_data: dict) -> None: return else: csproj = ( - root / "src" / "csharp" / "cli" / "PyMCU.Backend.RP2040.Cli.csproj" + root / "src" / "csharp" / "cli" / "PyMCU.Backend.ARM.Cli.csproj" ) publish_dir = root / "build" / "bin" publish_dir.mkdir(parents=True, exist_ok=True) diff --git a/pyproject.toml b/pyproject.toml index 3b06ea5..98fe273 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,9 @@ requires = ["hatchling>=1.25.0"] build-backend = "hatchling.build" [project] -name = "pymcu-rp2040" +name = "pymcu-arm" version = "0.1.0a1" -description = "RP2040 (Cortex-M0+) support for pymcu-compiler: LLVM-IR codegen backend + LLVM toolchain driver" +description = "ARM (Cortex-M) support for pymcu-compiler: LLVM-IR codegen backend + LLVM toolchain driver" readme = "README.md" authors = [ { name = "Iván Montiel Cardona", email = "contact@pymcu.org" } @@ -15,14 +15,14 @@ license = { text = "MIT" } dependencies = [ "pymcu-sdk>=0.1.0a1", # The vendored LLVM toolchain lives in its own repository - # (~/Repos/pymcu-rp2040-toolchain, published to PyPI as - # pymcu-rp2040-toolchain, analogous to avr-gcc-build -> pymcu-avr-toolchain). + # (~/Repos/pymcu-arm-toolchain, published to PyPI as + # pymcu-arm-toolchain, analogous to avr-gcc-build -> pymcu-avr-toolchain). # It bundles opt/llc/llvm-mc/ld.lld/llvm-objcopy and Rp2040LlvmToolchain - # prefers it via `import pymcu_rp2040_toolchain`. Until the wheel is on PyPI + # prefers it via `import pymcu_arm_toolchain`. Until the wheel is on PyPI # the driver falls back to a system LLVM on PATH (e.g. `brew install llvm - # lld`). Once published, add the gated dependency so the rp2040 extra is + # lld`). Once published, add the gated dependency so the arm extra is # self-contained: - # "pymcu-rp2040-toolchain>=19.1.7; (sys_platform == 'linux' and platform_machine == 'x86_64') or (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'darwin' and platform_machine == 'arm64')", + # "pymcu-arm-toolchain>=19.1.7; (sys_platform == 'linux' and platform_machine == 'x86_64') or (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'darwin' and platform_machine == 'arm64')", ] [project.entry-points."pymcu.backends"] @@ -36,13 +36,13 @@ pymcu-sdk = {git = "https://github.com/PyMCU/pymcu", subdirectory = "extensions/ [project.urls] -Homepage = "https://github.com/PyMCU/pymcu-rp2040" -Repository = "https://github.com/PyMCU/pymcu-rp2040" -"Bug Tracker" = "https://github.com/PyMCU/pymcu-rp2040/issues" +Homepage = "https://github.com/PyMCU/pymcu-arm" +Repository = "https://github.com/PyMCU/pymcu-arm" +"Bug Tracker" = "https://github.com/PyMCU/pymcu-arm/issues" [tool.hatch.build.hooks.custom] path = "hatch_build.py" [tool.hatch.build.targets.wheel] packages = ["src/python/pymcu"] -artifacts = ["src/python/pymcu/backend/rp2040/pymcuc-rp2040*"] +artifacts = ["src/python/pymcu/backend/rp2040/pymcuc-arm*"] diff --git a/src/csharp/cli/Program.cs b/src/csharp/cli/Program.cs index 7e09cb0..2d6e704 100644 --- a/src/csharp/cli/Program.cs +++ b/src/csharp/cli/Program.cs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT -// pymcuc-rp2040 - AOT-compiled RP2040 backend runner. +// pymcuc-arm - AOT-compiled RP2040 backend runner. // // Usage: -// pymcuc-rp2040 --output --target --freq +// pymcuc-arm --output --target --freq // [--config KEY=VALUE]... [--reset-vector N] // [--interrupt-vector N] [--verbose] // @@ -69,7 +69,7 @@ DefaultValueFactory = _ => false }; -var rootCmd = new RootCommand("pymcuc-rp2040 - PyMCU RP2040 (LLVM IR) backend runner"); +var rootCmd = new RootCommand("pymcuc-arm - PyMCU RP2040 (LLVM IR) backend runner"); rootCmd.Arguments.Add(irFileArg); rootCmd.Options.Add(outputOpt); rootCmd.Options.Add(targetOpt); @@ -112,7 +112,7 @@ } catch (Exception ex) { - Console.Error.WriteLine($"[pymcuc-rp2040] Failed to read IR file '{irFile}': {ex.Message}"); + Console.Error.WriteLine($"[pymcuc-arm] Failed to read IR file '{irFile}': {ex.Message}"); Environment.ExitCode = 1; return; } @@ -142,7 +142,7 @@ } catch (Exception ex) { - Console.Error.WriteLine($"[pymcuc-rp2040] Codegen failed: {ex.Message}"); + Console.Error.WriteLine($"[pymcuc-arm] Codegen failed: {ex.Message}"); if (verbose) Console.Error.WriteLine(ex.StackTrace); Environment.ExitCode = 1; } diff --git a/src/csharp/cli/PyMCU.Backend.RP2040.Cli.csproj b/src/csharp/cli/PyMCU.Backend.ARM.Cli.csproj similarity index 65% rename from src/csharp/cli/PyMCU.Backend.RP2040.Cli.csproj rename to src/csharp/cli/PyMCU.Backend.ARM.Cli.csproj index e4342b7..7992a06 100644 --- a/src/csharp/cli/PyMCU.Backend.RP2040.Cli.csproj +++ b/src/csharp/cli/PyMCU.Backend.ARM.Cli.csproj @@ -2,9 +2,9 @@ Exe - PyMCU.Backend.RP2040.Cli - pymcuc-rp2040 - + PyMCU.Backend.ARM.Cli + pymcuc-arm + true true @@ -12,7 +12,7 @@ - + diff --git a/src/csharp/lib/PyMCU.Backend.RP2040.csproj b/src/csharp/lib/PyMCU.Backend.ARM.csproj similarity index 76% rename from src/csharp/lib/PyMCU.Backend.RP2040.csproj rename to src/csharp/lib/PyMCU.Backend.ARM.csproj index 4454146..6541021 100644 --- a/src/csharp/lib/PyMCU.Backend.RP2040.csproj +++ b/src/csharp/lib/PyMCU.Backend.ARM.csproj @@ -3,14 +3,14 @@ Library PyMCU - PyMCU.Backend.RP2040 - + PyMCU.Backend.ARM + + Expects both repos checked out as siblings: ../pymcu/ next to ../pymcu-arm/ --> diff --git a/src/python/pymcu/backend/rp2040/plugin.py b/src/python/pymcu/backend/rp2040/plugin.py index 1cc9be1..b0705af 100644 --- a/src/python/pymcu/backend/rp2040/plugin.py +++ b/src/python/pymcu/backend/rp2040/plugin.py @@ -14,7 +14,7 @@ """ Rp2040BackendPlugin -- PyMCU RP2040 (Cortex-M0+) codegen backend. -Wraps the ``pymcuc-rp2040`` AOT-compiled binary bundled inside this wheel. The +Wraps the ``pymcuc-arm`` AOT-compiled binary bundled inside this wheel. The binary reads a ``.mir`` IR file produced by ``pymcuc --emit-ir`` and emits an LLVM IR text file (``.ll``); the rp2040 toolchain plugin then drives LLVM to turn it into a flashable image. @@ -38,10 +38,10 @@ class Rp2040BackendPlugin(BackendPlugin): @classmethod def get_backend_binary(cls) -> Path: - """Return the path to the bundled ``pymcuc-rp2040`` binary.""" + """Return the path to the bundled ``pymcuc-arm`` binary.""" package_dir = Path(__file__).parent - binary_name = "pymcuc-rp2040.exe" if sys.platform == "win32" else "pymcuc-rp2040" + binary_name = "pymcuc-arm.exe" if sys.platform == "win32" else "pymcuc-arm" # 1. Wheel layout: binary sits next to this Python module. adjacent = package_dir / binary_name @@ -50,15 +50,15 @@ def get_backend_binary(cls) -> Path: return adjacent # 2. Development fallback: dotnet publish output (build/bin). - # package_dir = .../extensions/pymcu-rp2040/src/python/pymcu/backend/rp2040 + # package_dir = .../extensions/pymcu-arm/src/python/pymcu/backend/rp2040 repo_root = package_dir.parents[6] dev_path = repo_root / "build" / "bin" / binary_name if dev_path.exists(): cls._ensure_signed(dev_path) return dev_path - # 3. extensions/pymcu-rp2040/src/csharp/cli built output (dev shortcut). - backend_root = package_dir.parents[4] # .../extensions/pymcu-rp2040 + # 3. extensions/pymcu-arm/src/csharp/cli built output (dev shortcut). + backend_root = package_dir.parents[4] # .../extensions/pymcu-arm runner_debug = ( backend_root / "src" / "csharp" / "cli" / "bin" / "Debug" / "net10.0" / binary_name @@ -69,7 +69,7 @@ def get_backend_binary(cls) -> Path: # 4. System PATH. import shutil - which_result = shutil.which("pymcuc-rp2040") + which_result = shutil.which("pymcuc-arm") if which_result: return Path(which_result) diff --git a/src/python/pymcu/toolchain/rp2040/llvm.py b/src/python/pymcu/toolchain/rp2040/llvm.py index e9a9ad3..5a68a92 100644 --- a/src/python/pymcu/toolchain/rp2040/llvm.py +++ b/src/python/pymcu/toolchain/rp2040/llvm.py @@ -77,7 +77,7 @@ def is_cached(self) -> bool: return False def install(self) -> None: - # The vendored pymcu-rp2040-toolchain wheel (or a system LLVM) provides + # The vendored pymcu-arm-toolchain wheel (or a system LLVM) provides # the binaries. If the wheel is installed but its binaries have not been # staged yet, stage them now (download the pinned LLVM into the cache). if not self.is_cached(): @@ -93,14 +93,14 @@ def install(self) -> None: raise RuntimeError( "LLVM tools not found: " + ", ".join(missing) + ".\n" "Install the vendored toolchain (pip install pymcu[rp2040]) and run\n" - " python -m pymcu_rp2040_toolchain fetch --cache\n" + " python -m pymcu_arm_toolchain fetch --cache\n" "or provide a system LLVM (e.g. `brew install llvm lld`)." ) def _try_stage_wheel(self) -> None: """Ask the vendored wheel to stage its LLVM tools into the cache.""" try: - from pymcu_rp2040_toolchain._fetch import fetch # noqa: PLC0415 + from pymcu_arm_toolchain._fetch import fetch # noqa: PLC0415 fetch(target="cache", console=self.console) except Exception: # Wheel absent or staging failed; _find_bin falls back to PATH and @@ -110,14 +110,14 @@ def _try_stage_wheel(self) -> None: # ── binary / runtime resolution ────────────────────────────────────────── def _find_bin_from_wheel(self, name: str) -> Optional[str]: - """Resolve *name* via the vendored pymcu-rp2040-toolchain wheel, if present. + """Resolve *name* via the vendored pymcu-arm-toolchain wheel, if present. The wheel (analogue of pymcu-avr-toolchain) bundles the LLVM tools or stages them into the shared cache and exposes get_tool(). It is the authoritative, reproducible source; system LLVM is only a fallback. """ try: - import pymcu_rp2040_toolchain as _whl # noqa: PLC0415 + import pymcu_arm_toolchain as _whl # noqa: PLC0415 return str(_whl.get_tool(name)) except (ImportError, FileNotFoundError): return None @@ -143,7 +143,7 @@ def _find_bin(self, name: str) -> str: if found: return found raise FileNotFoundError( - f"Required LLVM tool '{name}' not found (pymcu-rp2040-toolchain " + f"Required LLVM tool '{name}' not found (pymcu-arm-toolchain " f"wheel, cache, {', '.join(_LLVM_SEARCH_DIRS)}, or PATH)." ) @@ -153,9 +153,9 @@ def _runtime_dir(self) -> Path: bundled = Path(__file__).parent / "runtime" if (bundled / "rp2040.ld").exists(): return bundled - # 2. Development checkout: extensions/pymcu-rp2040/src/runtime. + # 2. Development checkout: extensions/pymcu-arm/src/runtime. # __file__ = .../src/python/pymcu/toolchain/rp2040/llvm.py - ext_root = Path(__file__).parents[5] # .../extensions/pymcu-rp2040 + ext_root = Path(__file__).parents[5] # .../extensions/pymcu-arm dev = ext_root / "src" / "runtime" if (dev / "rp2040.ld").exists(): return dev diff --git a/tests/integration/PymcuCompiler.cs b/tests/integration/PymcuCompiler.cs index 3330e89..e230c6f 100644 --- a/tests/integration/PymcuCompiler.cs +++ b/tests/integration/PymcuCompiler.cs @@ -44,6 +44,10 @@ private static byte[] CompileBin(string projectDir, string name) return File.ReadAllBytes(binFile); } + private static readonly bool Verbose = + Environment.GetEnvironmentVariable("PYMCU_VERBOSE") == "1" || + Environment.GetEnvironmentVariable("RUNNER_DEBUG") == "1"; + private static void RunPymcuBuild(string projectDir, string name) { if (!Directory.Exists(projectDir)) @@ -60,7 +64,8 @@ private static void RunPymcuBuild(string projectDir, string name) RedirectStandardError = true, UseShellExecute = false, }; - psi.Environment["PYMCU_VERBOSE"] = "1"; + if (Verbose) + psi.Environment["PYMCU_VERBOSE"] = "1"; psi.Environment["PATH"] = venvBin + Path.PathSeparator + psi.Environment["PATH"]; using var proc = Process.Start(psi) @@ -71,6 +76,21 @@ private static void RunPymcuBuild(string projectDir, string name) var stdout = stdoutTask.GetAwaiter().GetResult(); var stderr = stderrTask.GetAwaiter().GetResult(); + var failed = !finished || proc.ExitCode != 0; + if (failed || Verbose) + { + if (failed) + { + Console.WriteLine($"[PymcuCompiler] Build failed: {name}"); + Console.WriteLine($"[PymcuCompiler] RepoRoot : {RepoRoot}"); + Console.WriteLine($"[PymcuCompiler] ProjectDir : {projectDir}"); + Console.WriteLine($"[PymcuCompiler] PATH : {psi.Environment["PATH"]}"); + } + Console.WriteLine($"[PymcuCompiler] Exit: {(finished ? proc.ExitCode.ToString() : "TIMEOUT")}"); + if (!string.IsNullOrWhiteSpace(stdout)) Console.WriteLine($"stdout:\n{stdout}"); + if (!string.IsNullOrWhiteSpace(stderr)) Console.WriteLine($"stderr:\n{stderr}"); + } + if (!finished) { proc.Kill(); throw new TimeoutException($"pymcu build timed out for '{name}'.\n{stdout}\n{stderr}"); } if (proc.ExitCode != 0) throw new InvalidOperationException($"pymcu build failed for '{name}' (exit {proc.ExitCode}):\n{stdout}\n{stderr}"); @@ -87,6 +107,6 @@ private static string FindRepoRoot() dir = Directory.GetParent(dir)?.FullName; } throw new DirectoryNotFoundException( - "Cannot locate pymcu-rp2040 repo root (no hatch_build.py + examples/ found)."); + "Cannot locate pymcu-arm repo root (no hatch_build.py + examples/ found)."); } }