Skip to content

Conversation

@konstin
Copy link
Member

@konstin konstin commented Feb 12, 2025

uv itself is a large package with many dependencies and lots of features. To build a package using the uv build backend, you shouldn't have to download and install the entirety of uv. For platform where we don't provide wheels, it should be possible and fast to compile the uv build backend. To that end, we're introducing a python package that contains a trimmed down version of uv that only contains the build backend, with a minimal dependency tree in rust.

The uv_build package is publish from CI just like uv itself. It is part of the workspace, but has much less dependencies for its own binary. We're using cargo deny to enforce that the network stack is not part of the dependencies. A new build profile ensure we're getting the minimum possible binary size for a rust binary.

@konstin konstin force-pushed the konsti/standalone-build-backend-package branch from 5aadae4 to 6123fe0 Compare February 12, 2025 15:20
@konstin konstin force-pushed the konsti/standalone-build-backend-package branch 5 times, most recently from 72875c8 to 6fff5b2 Compare February 13, 2025 12:46
@konstin konstin force-pushed the konsti/standalone-build-backend-package branch from 6fff5b2 to b62aa08 Compare February 13, 2025 13:07
@konstin konstin changed the base branch from main to konsti/refactor-build-binaries February 13, 2025 13:07
@konstin konstin changed the title CI: uv-build A minimal build backend for uv: uv_build Feb 13, 2025
Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

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

looked over everything but the python

Cargo.toml Outdated
Comment on lines 282 to 287
# Profile for uv-build
[profile.minimal-size]
inherits = "release"
opt-level = "z"

Copy link
Contributor

Choose a reason for hiding this comment

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

panic = "abort" may also reduce size if we're desperate for every byte: https://doc.rust-lang.org/cargo/reference/profiles.html#panic

Copy link
Member

Choose a reason for hiding this comment

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

Probably worth at least checking how much it saves us

Copy link
Member Author

Choose a reason for hiding this comment

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

I've added it for, it gets us down to 1217927 bytes on linux. I'm not sure with we want to deploy that, we've had very few panics in the past but if the happen the panic message is the only indication we get.

@@ -0,0 +1,92 @@
#![allow(clippy::print_stdout)]
Copy link
Contributor

Choose a reason for hiding this comment

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

I would love to have a comment here explaining why we are doing this. just to produce an anyhow error instead of panic when stdout is closed?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've mostly done it for consistency with writeln!(printer.stdout(), ...) we're using everywhere else, i don't feel strongly about.

Comment on lines +39 to +42
[build-system]
requires = ["maturin>=1.0,<2.0"]
build-backend = "maturin"

Copy link
Contributor

Choose a reason for hiding this comment

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

i don't know why but this is incredibly funny to me (it makes sense)

Comment on lines +1 to +8
[bans]
multiple-versions = "allow"
deny = [
{ crate = "rustls", reason = "The build backend does not need network access" },
{ crate = "openssl", reason = "The build backend does not need network access" },
{ crate = "reqwest", reason = "The build backend does not need network access" },
{ crate = "schemars", reason = "JSON Schema generation is a development feature, not a runtime feature" },
]
Copy link
Contributor

Choose a reason for hiding this comment

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

rad

Comment on lines +130 to +145
# uv-build
- name: "Build wheels uv-build - x86_64"
uses: PyO3/maturin-action@v1
with:
target: x86_64
args: --profile minimal-size --locked --out crates/uv-build/dist -m crates/uv-build/Cargo.toml
- name: "Upload wheels uv-build"
uses: actions/upload-artifact@v4
with:
name: wheels_uv_build-macos-x86_64
path: crates/uv-build/dist

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm I was gonna say this will slow down releases a lot if it's serial but in theory this thing should build super fast so it's fine?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's 22s on a fresh target directory for me locally. I had initially put them in succession to reuse the target dir, but that mostly doesn't apply anymore with the different opt mode.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah basically nothing to share

Copy link
Contributor

@T-256 T-256 left a comment

Choose a reason for hiding this comment

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

IIUC, to configure backend, we should use tool.uv.build-backend, but since uv_build is now standalone package could expect it to be changed?

IMO, tool.uv.build or tool.uv-build is closer to uv_build, the package name.

zanieb pushed a commit that referenced this pull request Feb 18, 2025
For uv-build, we need to duplicate a lot of the `build-binaries.yml`
logic to build another source distribution and wheel. In preparation for
that I tried to make the invocations more consistent, to make it easier
to review the changes when adding the `uv-build` builds on top.

Split out from #11446

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
Base automatically changed from konsti/refactor-build-binaries to main February 18, 2025 17:36
@konstin konstin force-pushed the konsti/standalone-build-backend-package branch from 9c7623f to e71da8f Compare February 19, 2025 10:11
@konstin konstin added the preview Experimental behavior label Feb 19, 2025
@konstin konstin force-pushed the konsti/standalone-build-backend-package branch 2 times, most recently from de5cd0d to 956b4e2 Compare February 19, 2025 10:53
@konstin konstin marked this pull request as ready for review February 19, 2025 10:54
@konstin konstin mentioned this pull request Feb 26, 2025
Comment on lines 41 to 44
# Handles both `uv` and `uv-build`
uv_binary = sys.modules[__name__].__name__.replace("_", "-")
# Unlike `find_uv_bin`, this mechanism must work according to PEP 517
uv_bin = shutil.which("uv")
uv_bin = shutil.which(uv_binary)
Copy link
Contributor

Choose a reason for hiding this comment

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

IMO, at least by uv-build we could use it as library instead of calling it through binary's cli.
do we want still to support build-system.build-backend = "uv"? If no, the call function could be entirely removed and directly use uv_build_backend methods.

@konstin
Copy link
Member Author

konstin commented Feb 28, 2025

While I agree with

requires = ["uv-build>=0.4.15,<5"]
build-backend = "uv.build"

being better looking, I see two aspects that drew me towards uv_build: With uv.build, every action (such as from uv.build import build_wheel) has to first import uv/__init__.py, too. This couples uv's own uv/__init__.py to uv-build across all versions (since they don't depend on each other, any version combination is possible). As separation from uv through build-backend = "uv-build" future proofs the module import. The other aspect is that I regularly have to help with user questions where the problem turns out to be two packages that overwrite each other partially or fully being in the dependency tree, so I'm biased against packages that ship modules of a different name.

To also mention a discarded alternative, there was also an option of having build-backend = "uv.build" because both uv and uv-build would ship the build backend, or similarly allowing build-backend = "uv", but I couldn't find an option to make those work without the risk of two different versions of uv and uv-build conflicting on installed files (and overwriting in a way that breaks something).

@konstin konstin force-pushed the konsti/standalone-build-backend-package branch from 5662a8a to 325baeb Compare February 28, 2025 18:09
loic-lescoat pushed a commit to loic-lescoat/uv that referenced this pull request Mar 2, 2025
For uv-build, we need to duplicate a lot of the `build-binaries.yml`
logic to build another source distribution and wheel. In preparation for
that I tried to make the invocations more consistent, to make it easier
to review the changes when adding the `uv-build` builds on top.

Split out from astral-sh#11446

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
@zanieb
Copy link
Member

zanieb commented Mar 3, 2025

On the package collision / overwriting note: this should be quite rare, right? Since the build backend is usually installed in an isolated build environment?

@notatallshaw
Copy link
Collaborator

On the package collision / overwriting note: this should be quite rare, right? Since the build backend is usually installed in an isolated build environment?

While less common there are various legitimate reasons to build in a non-isolated environment. The first one that comes to mind is having pinned build dependencies, which has somewhat limited tooling support outside manually doing it.

@zanieb
Copy link
Member

zanieb commented Mar 3, 2025

The first one that comes to mind is having pinned build dependencies, which has somewhat limited tooling support outside manually doing it.

We definitely intend to fix this though. (but I understand that doesn't mean this isn't a problem for people using other build frontends). I still see that as a niche or advanced use-case where it's fine if the packages overlap.

@zanieb
Copy link
Member

zanieb commented Mar 4, 2025

(I'm not attached to a particular outcome here. I think uv_build is probably simpler — but I want to poke at our motivations a bit)

@konstin
Copy link
Member Author

konstin commented Mar 4, 2025

Currently, it's always just requires = ["uv_build..."], but expect that to change in the future as the build backend becomes more powerful and people want to add other packages, too, for additional functionality.

Overall my experience is that when used correctly, namespace packages/packages with renaming and isolated packages work equally well. Even though, users are regularly hitting broken installs with cases where two packages conflict on a filesystem level, and then it's hard to figure out what and why even broke. uv.build also puts an implicit constraint on uv/__init__.py because it always gets imported for uv.build no matter the uv version.

@zanieb zanieb force-pushed the konsti/standalone-build-backend-package branch from d2c1c22 to 5ea23ce Compare March 6, 2025 19:11
@zanieb zanieb temporarily deployed to uv-test-publish March 6, 2025 19:14 — with GitHub Actions Inactive
@zanieb zanieb merged commit bf4c7af into main Mar 6, 2025
97 checks passed
@zanieb zanieb deleted the konsti/standalone-build-backend-package branch March 6, 2025 19:27
@konstin konstin mentioned this pull request Mar 10, 2025
32 tasks
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Mar 10, 2025
This MR contains the following updates:

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

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.6.5`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#065)

[Compare Source](astral-sh/uv@0.6.4...0.6.5)

##### Enhancements

-   Allow `--constraints` and `--overrides` in `uvx` ([#&#8203;10207](astral-sh/uv#10207))
-   Allow overrides in `satisfies` check for `uv tool run` ([#&#8203;11994](astral-sh/uv#11994))
-   Allow users to set `package = true` on `tool.uv.sources` ([#&#8203;12014](astral-sh/uv#12014))
-   Add support for Windows legacy scripts via `uv run` ([#&#8203;11888](astral-sh/uv#11888))
-   Return error when running uvx with a `.py` script ([#&#8203;11623](astral-sh/uv#11623))
-   Warn user on use of `uvx run` ([#&#8203;11992](astral-sh/uv#11992))

##### Configuration

-   Add `NO_BUILD` and `NO_BUILD_PACKAGE` environment variables ([#&#8203;11968](astral-sh/uv#11968))

##### Performance

-   Allow overrides in all satisfies checks ([#&#8203;11995](astral-sh/uv#11995))
-   Respect markers on constraints when validating current environment ([#&#8203;11976](astral-sh/uv#11976))

##### Bug fixes

-   Compare major-minor specifiers when filtering interpreters ([#&#8203;11952](astral-sh/uv#11952))
-   Fix system site packages detection default ([#&#8203;11956](astral-sh/uv#11956))
-   Invalidate lockfile when empty dependency groups are added or removed ([#&#8203;12010](astral-sh/uv#12010))
-   Remove prepended sys.path ([#&#8203;11954](astral-sh/uv#11954))
-   Fix PyPy Python version label ([#&#8203;11965](astral-sh/uv#11965))
-   Fix error message suggesting `--user` instead of `--username` ([#&#8203;11947](astral-sh/uv#11947))

##### Preview

-   Move the uv build backend into a separate, minimal `uv_build` package ([#&#8203;11446](astral-sh/uv#11446))

</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:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODguMyIsInVwZGF0ZWRJblZlciI6IjM5LjE4OC4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Experimental behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants