SDK: nRF Connect SDK v3.1.1 (Zephyr 4.1.99)
Build type: Out-of-tree (custom board `goride_centralstationen/nrf9160/ns`, external hw-conf, external modules)
Platform: macOS (Apple Silicon), but affects any OS with a system Python that doesn't allow pip installs
The Problem
Homebrew-installed Python 3.14 is the system `python3`. Per PEP 668, system-wide pip installs are blocked:
python3 -m pip install west
error: externally-managed-environment
Nordic/Zephyr docs instruct users to install west in a Python virtual environment. We have `venv-3.1.1` with Python 3.11 and west 1.5.0. Activating it and running `west build` works for the parent CMake — it finds the venv's Python 3.11 with west.
But sysbuild child images (mcuboot) ignore the venv entirely. They run `find_program("python3")` in a fresh subprocess, which finds the system Python 3.14 — which has no west and cannot have west installed. This causes a cascade failure:
1. `python.cmake` finds system Python 3.14 (no west)
2. `west.cmake` fails to import west from that Python
3. `zephyr_module.cmake:51` — `if(WEST ...)` is false → module discovery skipped
4. `ZEPHYR_NRF_MODULE_DIR` never set
5. `mcuboot/boot/zephyr/Kconfig:12` — `source "$(ZEPHYR_NRF_MODULE_DIR)/..."` fails
There is no user-side fix. The system Python cannot have west (PEP 668). The venv Python is correctly set up. Sysbuild just doesn't propagate it to child images.
Root Cause
`basic_settings.cmake:24-39` loads the sysbuild cache into **CMake target properties**:
```cmake
set_property(TARGET sysbuild_cache PROPERTY "${CMAKE_MATCH_1}" "${variable_value}")
```
`python.cmake:16` reads **CMake variables**:
```cmake
if(NOT DEFINED Python3_EXECUTABLE AND DEFINED WEST_PYTHON)
```
Target properties and CMake variables are separate namespaces. They never meet. The sysbuild cache correctly contains `Python3_EXECUTABLE:FILEPATH=.../venv-3.1.1/bin/python3` but child images never see it — they run `find_program()` fresh and get the system Python.
The `shared_cmake_variables_list` in `sysbuild_extensions.cmake:319` only passes `CMAKE_BUILD_TYPE` and `CMAKE_VERBOSE_MAKEFILE` as `-D` flags to child CMake. Python variables go through the broken target-property mechanism.
Steps to Reproduce
1. macOS with Homebrew Python (any version ≥ 3.12 with PEP 668)
2. Create a venv with an older Python that has west: `python3.11 -m venv venv && source venv/bin/activate && pip install west`
3. Any out-of-tree NCS project with sysbuild (mcuboot enabled): `SB_CONFIG_BOOTLOADER_MCUBOOT=y`
4. Build: `source venv/bin/activate && west build -b <custom-board>`
5. Parent CMake uses venv Python 3.11 (correct). Child mcuboot CMake uses system Python 3.14 (no west). Build fails.
Verified on reference `nrf9160dk/nrf9160/ns` board too — not board-specific.
Workarounds
None that don't involve breaking system package management or patching NCS:
- `--break-system-packages` to force west into system Python — violates PEP 668, Homebrew warns against it
- `brew unlink [email protected] && brew link [email protected] --force` — fragile, `brew upgrade` relinks newer Python
- Patch `basic_settings.cmake` (see below) — works but shouldn't be necessary
Proposed Fix
After line 39 in `zephyr/cmake/modules/basic_settings.cmake`, promote Python variables from target properties to CMake variables so `python.cmake` can see them:
```cmake
if(SYSBUILD)
get_property(_sb_python3 TARGET sysbuild_cache PROPERTY Python3_EXECUTABLE)
if(_sb_python3)
set(Python3_EXECUTABLE "${_sb_python3}")
endif()
get_property(_sb_west_python TARGET sysbuild_cache PROPERTY WEST_PYTHON)
if(_sb_west_python)
set(WEST_PYTHON "${_sb_west_python}")
endif()
get_property(_sb_python TARGET sysbuild_cache PROPERTY PYTHON_EXECUTABLE)
if(_sb_python)
set(PYTHON_EXECUTABLE "${_sb_python}")
endif()
unset(_sb_python3)
unset(_sb_west_python)
unset(_sb_python)
endif()
```
Files
- `zephyr/cmake/modules/basic_settings.cmake` — stores sysbuild cache as target properties (broken)
- `zephyr/cmake/modules/python.cmake:16-44` — reads CMake variables (never sees cache)
- `zephyr/cmake/modules/west.cmake:34-59` — tries `PYTHON_EXECUTABLE -c "import west"`, fails
- `zephyr/cmake/modules/zephyr_module.cmake:51` — `if(WEST OR ZEPHYR_MODULES)` gates module discovery
- `sysbuild_extensions.cmake:319-323` — `shared_cmake_variables_list` (too narrow)
- `mcuboot/boot/zephyr/Kconfig:12` — the failing source line
Related
- github.com/.../70258 — same class of bug, different trigger