Skip to content

Keep cargo build artifact at original path after staging#3054

Merged
messense merged 1 commit into
PyO3:mainfrom
messense:reflink-stage-artifact
Mar 1, 2026
Merged

Keep cargo build artifact at original path after staging#3054
messense merged 1 commit into
PyO3:mainfrom
messense:reflink-stage-artifact

Conversation

@messense

@messense messense commented Mar 1, 2026

Copy link
Copy Markdown
Member

Previously stage_artifact() used fs::rename to move the artifact from the cargo output directory (e.g. target/release/) to a private staging directory (target/maturin/). This meant users could no longer find the built .so/.dylib/.dll at the standard cargo output location.

Now stage_artifact() still uses an atomic fs::rename into the staging directory (protecting against concurrent modification by cargo or rust-analyzer), then copies the staged file back to the original location via reflink (copy-on-write) when the filesystem supports it, falling back to a regular fs::copy otherwise. The copy-back is best-effort and does not fail the build. When fs::rename itself fails (e.g. cross-device), we fall back to reflink-or-copy directly.

On Linux, ioctl_ficlone does not preserve file permissions, so we explicitly copy them after the reflink. On macOS, clonefile preserves all metadata natively. This approach is adapted from uv's reflink_with_permissions implementation.

Refs: https://github.com/astral-sh/uv/blob/main/crates/uv-fs/src/link.rs
Refs: astral-sh/uv#18181

Fixes #2950 (comment)

@messense messense requested a review from Copilot March 1, 2026 11:34
@messense messense force-pushed the reflink-stage-artifact branch from 5f4ee4b to 40126d1 Compare March 1, 2026 11:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates artifact staging so the compiled library remains available at the original Cargo output path, while still staging into a private directory for safe mmap / in-place modification.

Changes:

  • Change stage_artifact() to rename into a private staging dir, then best-effort reflink/copy back to the original path.
  • Add reflink-or-copy helpers (with Linux permission fix-up) to support near-zero-cost copy-back.
  • Add reflink-copy dependency and tweak related safety documentation.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/compile.rs Updates SAFETY comment to reflect new staging behavior.
src/build_context/mod.rs Implements rename-then-copy-back staging and adds reflink/copy helpers.
Cargo.toml Adds reflink-copy dependency needed for reflink support.

Comment thread src/compile.rs Outdated
Comment thread src/build_context/mod.rs Outdated
Comment thread src/build_context/mod.rs Outdated
Comment thread src/build_context/mod.rs
Previously `stage_artifact()` used `fs::rename` to move the artifact
from the cargo output directory (e.g. `target/release/`) to a private
staging directory (`target/maturin/`). This meant users could no
longer find the built `.so`/`.dylib`/`.dll` at the standard cargo
output location.

Now `stage_artifact()` still uses an atomic `fs::rename` into the
staging directory (protecting against concurrent modification by cargo
or rust-analyzer), then copies the staged file back to the original
location via reflink (copy-on-write) when the filesystem supports it,
falling back to a regular `fs::copy` otherwise. The copy-back is
best-effort and does not fail the build. When `fs::rename` itself
fails (e.g. cross-device), we fall back to `reflink_or_copy` directly.

On Linux, `ioctl_ficlone` does not preserve file permissions, so we
explicitly copy them after the reflink. On macOS, `clonefile`
preserves all metadata natively. This approach is adapted from uv's
`reflink_with_permissions` implementation.

Refs: https://github.com/astral-sh/uv/blob/main/crates/uv-fs/src/link.rs
Refs: astral-sh/uv#18181
@messense messense force-pushed the reflink-stage-artifact branch from 40126d1 to 2970fd1 Compare March 1, 2026 11:45
@messense messense enabled auto-merge (squash) March 1, 2026 11:48
@messense messense merged commit 477ba1a into PyO3:main Mar 1, 2026
62 checks passed
@messense messense deleted the reflink-stage-artifact branch March 1, 2026 12:40
@konstin

konstin commented Mar 1, 2026

Copy link
Copy Markdown
Member

Thanks for fixing this!

bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Mar 31, 2026
https://build.opensuse.org/request/show/1343551
by user mia + anag_factory
- Drop CVE-2026-25727.patch (handled in _service)
- Update to 1.12.6
  * Sync legacy_py.rs with upstream PyPI warehouse legacy.py
    gh#PyO3/maturin#3053
  * Keep cargo build artifact at original path after staging
    gh#PyO3/maturin#3054
- Update to 1.12.5
  * feat: include debug info files (.pdb, .dSYM, .dwp) in wheels
    gh#PyO3/maturin#3024
  * Fix wrong abi3 tag for conditional cargo features enabled pyo3
    abi3 feature
    gh#PyO3/maturin#3029
  * fix: maturin build --sdist wheel name/layout for excluded
    workspace crates
    gh#PyO3/maturin#3031
  * fix: preserve wheel output dir when building from unpacked
    sdist
    gh#PyO3/maturin#3036
  * feat: add python-implementation condition to conditional
    features
    gh#PyO3/maturin#3038
  * Fix non-existent comment tag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants