Skip to content

fix(install): stage fbuild._native during source/editable install (#829)#887

Merged
zackees merged 1 commit into
mainfrom
fix/829-stage-fbuild-native-in-editable-install
Jun 30, 2026
Merged

fix(install): stage fbuild._native during source/editable install (#829)#887
zackees merged 1 commit into
mainfrom
fix/829-stage-fbuild-native-in-editable-install

Conversation

@zackees

@zackees zackees commented Jun 30, 2026

Copy link
Copy Markdown
Member

Problem

uv pip install -e . (or any source install) left from fbuild import ... broken with ModuleNotFoundError: No module named 'fbuild._native'. Root cause: setup.py's BuildWithCargo only built fbuild-cli — the PyO3 extension produced by crates/fbuild-python (cdylib _native) was a separate manual step nobody knew to run.

Fix

Extend BuildWithCargo.run to also build fbuild-python with the extension-module feature and stage the resulting cdylib into python/fbuild/_native.{pyd,so}. The CLI build path is unchanged; the new cdylib step mirrors it exactly.

  • _build_fbuild_python() — invoke soldr cargo build -p fbuild-python --features extension-module --message-format=json-render-diagnostics and collect the cdylib path from cargo's JSON artifact stream.
  • _find_native_cdylib_from_json / _find_native_cdylib_by_search fallback — match on target.name == "_native" + target.kind contains "cdylib", pick the .dll / .so / .dylib filename from cargo's filenames array (cdylibs aren't exposed via the executable field).
  • STAGED_NATIVE_EXT_PATH.pyd on Windows, .so on Linux/macOS, matching CPython's extension search order. Strip the lib prefix on Unix implicitly by writing _native.so not lib_native.so.
  • _staged_native_ext_is_up_to_date — mtime fast-path companion to the existing CLI check. Both artifacts must be fresh to skip cargo entirely.

pyproject.toml's existing [tool.setuptools.package-data] fbuild = ["_native.pyd", "_native.so"] already pulls the staged file into the wheel; no pyproject change needed.

Verification

  • python -c "import ast; ast.parse(open('setup.py').read())" — syntax clean
  • Local cargo build of the cdylib couldn't run end-to-end due to a pre-existing MSVC SDK env issue on this machine (lld can't find cfgmgr32) — orthogonal to this PR. CI on Linux/macOS will exercise both paths.

Closes #829

`uv pip install -e .` (or any source install) left `from fbuild import ...`
broken with `ModuleNotFoundError: No module named 'fbuild._native'`.
Root cause: setup.py's `BuildWithCargo` only built `fbuild-cli` — the
PyO3 extension produced by `crates/fbuild-python` (cdylib `_native`)
was a separate manual step nobody knew to run.

Extend `BuildWithCargo.run` to also build `fbuild-python` with the
`extension-module` feature and stage the resulting cdylib into
`python/fbuild/_native.{pyd,so}`. The CLI build path is unchanged; the
new cdylib step mirrors it exactly:

- `_build_fbuild_python()` — invoke
  `soldr cargo build -p fbuild-python --features extension-module
  --message-format=json-render-diagnostics` and collect the cdylib path
  from cargo's JSON artifact stream.
- `_find_native_cdylib_from_json` / `_find_native_cdylib_by_search`
  fallback — same selection rules as the CLI helpers, but match on
  `target.name == "_native"` + `target.kind contains "cdylib"`, and
  pick the `.dll` / `.so` / `.dylib` filename from cargo's `filenames`
  array (cdylibs aren't exposed via the `executable` field).
- `STAGED_NATIVE_EXT_PATH` — `.pyd` on Windows, `.so` on Linux/macOS,
  matching CPython's extension search order. Stripping the `lib`
  prefix on Unix happens implicitly (we write `_native.so`, not
  `lib_native.so`).
- `_staged_native_ext_is_up_to_date` — mtime fast-path companion to
  the existing CLI check. Both staged artifacts must be fresh to skip
  the cargo invocation entirely.

`pyproject.toml`'s existing `[tool.setuptools.package-data]
fbuild = ["_native.pyd", "_native.so"]` already pulls the staged file
into the wheel; no pyproject change needed.

Closes #829
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@zackees, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 43 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 999a6273-9afd-4db0-84ef-91babc7a1d6b

📥 Commits

Reviewing files that changed from the base of the PR and between 582594b and 68114a1.

📒 Files selected for processing (1)
  • setup.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/829-stage-fbuild-native-in-editable-install

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zackees
zackees merged commit 2f52510 into main Jun 30, 2026
9 of 14 checks passed
@zackees
zackees deleted the fix/829-stage-fbuild-native-in-editable-install branch June 30, 2026 18:19
zackees added a commit that referenced this pull request Jun 30, 2026
Rolls up the fixes shipped since 2.3.14:

- #855 (#883) — drop stale standalone-zccache CI/Docker/docs references
  after the soldr embedded-zccache transition (soldr#977/#980/#1081)
- #865 (#884) — write daemon status via sync write_atomic; unblocks
  fbuild-daemon unit tests on macOS/Windows by eliminating the
  block_in_place panic in current-thread tokio runtimes
- #875 (#885) — pin TMP/TEMP for compiler subprocess on Windows; ESP32
  compile no longer fails with 'Cannot create temporary file in
  C:\Windows\' on the very first TU
- #720 (#886) — record anti-removal policy for dump_usb_ids example
- #829 (#887) — stage fbuild._native cdylib during source/editable
  install so 'from fbuild import ...' works after 'uv pip install -e .'

Plus all prior #664 platform_packages audit work, the #826 testing
followups, and the build cancellation fix from earlier in the cycle.
@fastled-project-sync fastled-project-sync Bot moved this to Triage in FastLED Tracker Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

Editable source install does not stage fbuild._native

1 participant