Skip to content

Conversation

rimathia
Copy link
Contributor

@rimathia rimathia commented Sep 6, 2025

Summary

This change extends the default initialized projects with scikit and maturin build backends to ensure that the rust or C++ build gets invoked when a source file changes.

Test Plan

cargo run init cppextension-test --build-backend=scikit followed by manual testing of the behaviour of the resulting project under uv run --with jupyter jupyter lab and changes to the source file of the extension.
Analogous for cargo run init maturin-test --build-backend=maturin .

Relevant Issues

The question of why the python extension is not rebuilt on source changes has been discussed in #15701 (comment).

@rimathia
Copy link
Contributor Author

rimathia commented Sep 6, 2025

It is of course a judgement call whether the rebuild on rust or C++ source file changes is more likely to meet developer expectations than the rebuild on --reinstall. Just decline the PR if you disagree with my premise.

@zanieb
Copy link
Member

zanieb commented Sep 8, 2025

cc @charliermarsh / @konstin

I don't have strong feelings here.

@konstin
Copy link
Member

konstin commented Sep 8, 2025

I think this is a good idea, but we should change the cache keys to something that captures all Rust/C/C++ source files, such as:

cache-keys = [{ file = "pyproject.toml" }, { file = "src/**/*.rs" }, { file = "Cargo.toml" }, { file = "Cargo.lock" }]

@rimathia
Copy link
Contributor Author

rimathia commented Sep 8, 2025

Thanks for the suggestion, I was deterred by the documentation mentioning that glob patterns can be costly to check, but in a source directory it definitely makes sense. Unfortunately, C++ doesn't have a strong filename convention, so I just went with {cpp,h}, hoping that people will become aware of that line in the pyproject.toml before wondering why a change to their .hpp file doesn't trigger recompilation.

@konstin
Copy link
Member

konstin commented Sep 9, 2025

We can do {h,c,hpp,cpp}. The costly part of the glob is traversing many files, the regex part of it is really fast. For each directory we look, we need to make a syscall, and for each syscall, there needs to be a random IO read. These are still fast for most source tree, but it's easy to misconfigure the glob and e.g. traverse an entire venv or data or cache directory with tenthousands of small files, where it becomes slow, hence the warning.

@konstin konstin added the enhancement New feature or improvement to existing functionality label Sep 9, 2025
@Ravencentric
Copy link

Ravencentric commented Sep 9, 2025

Should pyproject.toml and requirements.txt be a part of the cache-key by default in this case? I don't think adding/removing/updating a python dependency or changing the configuration of a completely unrelated tool should rebuild the expensive native code.

@konstin
Copy link
Member

konstin commented Sep 9, 2025

Speaking from a maturin perspective, pyproject.toml should be included, settings can be defined in this file, but requirements.txt isn't used.

CC @henryiii Do you have thoughts about which files should cause a scikit-build-core project to be rebuilt?

build-dir = "build/{wheel_tag}"
[tool.uv]
cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }, { file = "src/**/*.cpp" }, { file = "src/**/*.h" }, { file = "CMakeLists.txt" }]
Copy link
Member

Choose a reason for hiding this comment

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

Don't we need the double {{ and }} here also?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It turns out that at present, the Scikit project string does not use format! like the Maturin project string does. As a result, {wheel_tag} is still present in the resulting pyproject.toml. I'll have to investigate why this even works.

Copy link
Contributor

@henryiii henryiii Sep 10, 2025

Choose a reason for hiding this comment

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

That's correct, scikit-build-core has to inject the wheel tag there when it builds, since you don't know the wheel tag before you start building a wheel. You want {wheel_tag} in the pyproject.toml.

@henryiii
Copy link
Contributor

henryiii commented Sep 9, 2025

pyproject.toml (at least some tables, like project, build-system, and tool.scikit-build) makes sense for scikit-build-core as well. **/CMakeLists.txt, **.cmake would make sense too. We don't have dedicated support for presets yet, but CMakePreset.json and CMakeUserPreset.json also can affect the builds (and we'll have better support at some point). I've also seen the .C convention for C++ (pretty rare, but was somewhat common in the early nineties, so still pops up occasionally, especially with ROOT in HEP). I've also seen .inc for includes that aren't headers.

@henryiii
Copy link
Contributor

henryiii commented Sep 9, 2025

Oh, also the fortran extensions (.f, .f90, .F90, .F), and cuda (.cu, .cuh). I think those are the most common languages, though CMake also supports others, like Swift.

@konstin
Copy link
Member

konstin commented Sep 9, 2025

Thanks @henryiii!

For the PR, further file extensions are cheap to support, we can cover as many of them as we want. I would avoid **/CMakeLists.txt and **.cmake as the require traversing everything, we need to limit those more if we want to include them.

@henryiii
Copy link
Contributor

henryiii commented Sep 9, 2025

How is that different from source file extensions? At least .cmake literally is an extension.

@henryiii
Copy link
Contributor

henryiii commented Sep 9, 2025

Oh, I think I see. Hadn’t looked at the code. src/**/{*.h,*.c,*.hpp,*.cpp,*.cmake,CMakeLists.txt} might work?

@zanieb
Copy link
Member

zanieb commented Sep 10, 2025

I'm sort of wary to go far beyond the files types that we're generating in the initial template.

@henryiii
Copy link
Contributor

henryiii commented Sep 10, 2025

I think a nice minimal set then might be ..., "{ file = "src/**/*.{h,c,hpp,cpp}" }, { file = "CMakeLists.txt" }]", then? Since it's part of the template, that seems fine to have it minimal.

@rimathia
Copy link
Contributor Author

Thanks for giving me specifics, I hope I've understood the emerging consensus.

@konstin konstin changed the title Add source files of python extension to tool.uv cache-keys when initializing projects with build backend maturin or scikit Better defaults for native build backend cache keys Sep 12, 2025
@konstin
Copy link
Member

konstin commented Sep 12, 2025

Let's start with these cache keys and see how it goes.

Copy link
Member

@konstin konstin left a comment

Choose a reason for hiding this comment

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

Thank you!

@konstin konstin merged commit 3081557 into astral-sh:main Sep 12, 2025
98 checks passed
hkant27008 added a commit to hkant27008/uv-package-manager that referenced this pull request Sep 12, 2025
Better defaults for native build backend cache keys (astral-sh#15705)
@zanieb
Copy link
Member

zanieb commented Sep 12, 2025

I think this is missing a docs update in https://docs.astral.sh/uv/concepts/projects/init/#projects-with-extension-modules where we say you'll need to use --reinstall when main.cpp changes

konstin added a commit that referenced this pull request Sep 14, 2025
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Sep 24, 2025
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.8.17` -> `0.8.22` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (astral-sh/uv)</summary>

### [`v0.8.22`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0822)

[Compare Source](astral-sh/uv@0.8.21...0.8.22)

Released on 2025-09-23.

##### Python

- Upgrade Pyodide to 0.28.3 ([#&#8203;15999](astral-sh/uv#15999))

##### Security

- Upgrade `astral-tokio-tar` to 0.5.5 which [hardens tar archive extraction](GHSA-3wgq-wrwc-vqmv) ([#&#8203;16004](astral-sh/uv#16004))

### [`v0.8.21`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0821)

[Compare Source](astral-sh/uv@0.8.20...0.8.21)

Released on 2025-09-23.

##### Enhancements

- Refresh lockfile when `--refresh` is provided ([#&#8203;15994](astral-sh/uv#15994))

##### Preview features

Add support for S3 request signing ([#&#8203;15925](astral-sh/uv#15925))

### [`v0.8.20`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0820)

[Compare Source](astral-sh/uv@0.8.19...0.8.20)

Released on 2025-09-22.

##### Enhancements

- Add `--force` flag for `uv cache clean` ([#&#8203;15992](astral-sh/uv#15992))
- Improve resolution errors with proxied packages ([#&#8203;15200](astral-sh/uv#15200))

##### Preview features

- Allow upgrading pre-release versions of the same minor Python version ([#&#8203;15959](astral-sh/uv#15959))

##### Bug fixes

- Hide `freethreaded+debug` Python downloads in `uv python list` ([#&#8203;15985](astral-sh/uv#15985))
- Retain the cache lock and temporary caches during `uv run` and `uvx` ([#&#8203;15990](astral-sh/uv#15990))

##### Documentation

- Add `package` level conflicts to the conflicting dependencies docs ([#&#8203;15963](astral-sh/uv#15963))
- Document pyodide support ([#&#8203;15962](astral-sh/uv#15962))
- Document support for free-threaded and debug Python versions ([#&#8203;15961](astral-sh/uv#15961))
- Expand the contribution docs on issue selection ([#&#8203;15966](astral-sh/uv#15966))
- Tweak title for viewing version in project guide ([#&#8203;15964](astral-sh/uv#15964))

### [`v0.8.19`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0819)

[Compare Source](astral-sh/uv@0.8.18...0.8.19)

Released on 2025-09-19.

##### Python

- Add CPython 3.14.0rc3
- Upgrade OpenSSL to 3.5.3

See the [python-build-standalone release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250918) for more details.

##### Bug fixes

- Make `uv cache clean` parallel process safe ([#&#8203;15888](astral-sh/uv#15888))
- Fix implied `platform_machine` marker for `win_arm64` platform tag ([#&#8203;15921](astral-sh/uv#15921))

### [`v0.8.18`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0818)

[Compare Source](astral-sh/uv@0.8.17...0.8.18)

Released on 2025-09-17.

##### Enhancements

- Add PyG packages to torch backend ([#&#8203;15911](astral-sh/uv#15911))
- Add handling for unnamed conda environments in base environment detection ([#&#8203;15681](astral-sh/uv#15681))
- Allow selection of debug build interpreters ([#&#8203;11520](astral-sh/uv#11520))
- Improve `uv init` defaults for native build backend cache keys ([#&#8203;15705](astral-sh/uv#15705))
- Error when `pyproject.toml` target does not exist for dependency groups ([#&#8203;15831](astral-sh/uv#15831))
- Infer check URL from publish URL when known ([#&#8203;15886](astral-sh/uv#15886))
- Support Gitlab CI/CD as a trusted publisher ([#&#8203;15583](astral-sh/uv#15583))
- Add GraalPy 25.0.0 with support for Python 3.12 ([#&#8203;15900](astral-sh/uv#15900))
- Add `--no-clear` to `uv venv` to disable removal prompts ([#&#8203;15795](astral-sh/uv#15795))
- Add conflict detection between `--only-group` and `--extra` flags ([#&#8203;15788](astral-sh/uv#15788))
- Allow `[project]` to be missing from a `pyproject.toml` ([#&#8203;14113](astral-sh/uv#14113))
- Always treat conda environments named `base` and `root` as base environments ([#&#8203;15682](astral-sh/uv#15682))
- Improve log message when direct build for `uv_build` is skipped ([#&#8203;15898](astral-sh/uv#15898))
- Log when the cache is disabled ([#&#8203;15828](astral-sh/uv#15828))
- Show pyx organization name after authenticating ([#&#8203;15823](astral-sh/uv#15823))
- Use `_CONDA_ROOT` to detect Conda base environments ([#&#8203;15680](astral-sh/uv#15680))
- Include blake2b hash in `uv publish` upload form ([#&#8203;15794](astral-sh/uv#15794))
- Fix misleading debug message when removing environments in `uv sync` ([#&#8203;15881](astral-sh/uv#15881))

##### Deprecations

- Deprecate `tool.uv.dev-dependencies` ([#&#8203;15469](astral-sh/uv#15469))
- Revert "feat(ci): build loongarch64 binaries in CI ([#&#8203;15387](astral-sh/uv#15387))" ([#&#8203;15820](astral-sh/uv#15820))

##### Preview features

- Propagate preview flag to client for `native-auth` feature ([#&#8203;15872](astral-sh/uv#15872))
- Store native credentials for realms with the https scheme stripped ([#&#8203;15879](astral-sh/uv#15879))
- Use the root index URL when retrieving credentials from the native store ([#&#8203;15873](astral-sh/uv#15873))

##### Bug fixes

- Fix `uv sync --no-sources` not switching from editable to registry installations ([#&#8203;15234](astral-sh/uv#15234))
- Avoid display of an empty string when a path is the working directory ([#&#8203;15897](astral-sh/uv#15897))
- Allow cached environment reuse with `@latest` ([#&#8203;15827](astral-sh/uv#15827))
- Allow escaping spaces in --env-file handling ([#&#8203;15815](astral-sh/uv#15815))
- Avoid ANSI codes in debug! messages ([#&#8203;15843](astral-sh/uv#15843))
- Improve BSD tag construction ([#&#8203;15829](astral-sh/uv#15829))
- Include SHA when listing lockfile changes ([#&#8203;15817](astral-sh/uv#15817))
- Invert the logic for determining if a path is a base conda environment ([#&#8203;15679](astral-sh/uv#15679))
- Load credentials for explicit members when lowering ([#&#8203;15844](astral-sh/uv#15844))
- Re-add `triton` as a torch backend package ([#&#8203;15910](astral-sh/uv#15910))
- Respect `UV_INSECURE_NO_ZIP_VALIDATION=1` in duplicate header errors ([#&#8203;15912](astral-sh/uv#15912))

##### Documentation

- Add GitHub Actions to PyPI trusted publishing example ([#&#8203;15753](astral-sh/uv#15753))
- Add Coiled integration documentation ([#&#8203;14430](astral-sh/uv#14430))
- Add verbose output to the getting help section ([#&#8203;15915](astral-sh/uv#15915))
- Document `NO_PROXY` support ([#&#8203;15816](astral-sh/uv#15816))
- Document cache-keys for native build backends ([#&#8203;15811](astral-sh/uv#15811))
- Add documentation for dependency group `requires-python` ([#&#8203;14282](astral-sh/uv#14282))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xMTUuNiIsInVwZGF0ZWRJblZlciI6IjQxLjEyNS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improvement to existing functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants