Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions bin/generate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,23 @@
type: string_array
build-frontend:
default: default
description: Set the tool to use to build, either "build" (default), "build[uv]", or "pip"
description: Set the tool to use to build, either "build" (default), "build[uv]", "uv", or "pip"
oneOf:
- enum: [pip, build, "build[uv]", default]
- enum: [pip, build, "build[uv]", uv, default]
- type: string
pattern: '^pip; ?args:'
- type: string
pattern: '^build; ?args:'
- type: string
pattern: '^build\\[uv\\]; ?args:'
- type: string
pattern: '^uv; ?args:'
- type: object
additionalProperties: false
required: [name]
properties:
name:
enum: [pip, build, "build[uv]"]
enum: [pip, build, "build[uv]", uv]
args:
type: array
items:
Expand Down
2 changes: 1 addition & 1 deletion cibuildwheel/frontend.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .logger import log
from .util.helpers import parse_key_value_string

BuildFrontendName = Literal["pip", "build", "build[uv]"]
BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"]


@dataclasses.dataclass(frozen=True)
Expand Down
4 changes: 2 additions & 2 deletions cibuildwheel/platforms/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def setup_python(
build_frontend: BuildFrontendName,
xbuild_tools: Sequence[str] | None,
) -> tuple[Path, dict[str, str]]:
if build_frontend == "build[uv]":
if build_frontend == "build[uv]" or build_frontend == "uv":
msg = "uv doesn't support iOS"
raise errors.FatalError(msg)

Expand Down Expand Up @@ -439,7 +439,7 @@ def build(options: Options, tmp_path: Path) -> None:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend
# uv doesn't support iOS
if build_frontend.name == "build[uv]":
if build_frontend.name == "build[uv]" or build_frontend.name == "uv":
msg = "uv doesn't support iOS"
raise errors.FatalError(msg)

Expand Down
15 changes: 14 additions & 1 deletion cibuildwheel/platforms/linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def build_in_container(
local_identifier_tmp_dir = local_tmp_dir / config.identifier
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "build[uv]"
use_uv = build_frontend.name in {"build[uv]", "uv"}
pip = ["uv", "pip"] if use_uv else ["pip"]

log.step("Setting up build environment...")
Expand Down Expand Up @@ -305,6 +305,19 @@ def build_in_container(
],
env=env,
)
case "uv":
container.call(
[
"uv",
"build",
"--python=python",
container_package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
],
env=env,
)
case _:
assert_never(build_frontend)

Expand Down
26 changes: 24 additions & 2 deletions cibuildwheel/platforms/macos.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def setup_python(
build_frontend: BuildFrontendName,
) -> tuple[Path, dict[str, str]]:
uv_path = find_uv()
use_uv = build_frontend == "build[uv]"
use_uv = build_frontend in {"build[uv]", "uv"}

tmp.mkdir()
implementation_id = python_configuration.identifier.split("-")[0]
Expand Down Expand Up @@ -377,6 +377,17 @@ def setup_python(
*constraint_flags(dependency_constraint),
env=env,
)
case "uv":
assert uv_path is not None
call(
uv_path,
"pip",
"install",
"--upgrade",
"delocate",
*constraint_flags(dependency_constraint),
env=env,
)
case _:
assert_never(build_frontend)

Expand Down Expand Up @@ -409,7 +420,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend
use_uv = build_frontend.name == "build[uv]"
use_uv = build_frontend.name in {"build[uv]", "uv"}
uv_path = find_uv()
if use_uv and uv_path is None:
msg = "uv not found"
Expand Down Expand Up @@ -500,6 +511,17 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags,
env=build_env,
)
case "uv":
call(
"uv",
"build",
"--python=python",
build_options.package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
env=build_env,
)
case _:
assert_never(build_frontend)

Expand Down
18 changes: 14 additions & 4 deletions cibuildwheel/platforms/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,10 @@ def setup_python(
raise ValueError(msg)
assert base_python.exists()

if build_frontend == "build[uv]" and not can_use_uv(python_configuration):
if build_frontend in {"build[uv]", "uv"} and not can_use_uv(python_configuration):
build_frontend = "build"

use_uv = build_frontend == "build[uv]"
use_uv = build_frontend in {"build[uv]", "uv"}
uv_path = find_uv()

log.step("Setting up build environment...")
Expand Down Expand Up @@ -396,8 +396,7 @@ def build(options: Options, tmp_path: Path) -> None:
for config in python_configurations:
build_options = options.build_options(config.identifier)
build_frontend = build_options.build_frontend

use_uv = build_frontend.name == "build[uv]" and can_use_uv(config)
use_uv = build_frontend.name in {"build[uv]", "uv"} and can_use_uv(config)
log.build_start(config.identifier)

identifier_tmp_dir = tmp_path / config.identifier
Expand Down Expand Up @@ -501,6 +500,17 @@ def build(options: Options, tmp_path: Path) -> None:
*extra_flags,
env=build_env,
)
case "uv":
call(
"uv",
"build",
"--python=python",
build_options.package_dir,
"--wheel",
f"--out-dir={built_wheel_dir}",
*extra_flags,
env=build_env,
)
case _:
assert_never(build_frontend)

Expand Down
2 changes: 1 addition & 1 deletion cibuildwheel/util/packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,6 @@ def combine_constraints(

user_constraints = env.get("PIP_CONSTRAINT")

env["UV_CONSTRAINT"] = env["PIP_CONSTRAINT"] = " ".join(
env["UV_BUILD_CONSTRAINT"] = env["UV_CONSTRAINT"] = env["PIP_CONSTRAINT"] = " ".join(
c for c in [our_constraints, user_constraints] if c
)
8 changes: 5 additions & 3 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ def docker_warmup_fixture(
return None


@pytest.fixture(params=["pip", "build"])
@pytest.fixture(params=["pip", "build", "uv"])
def build_frontend_env_nouv(request: pytest.FixtureRequest) -> dict[str, str]:
frontend = request.param
if get_platform() == "pyodide" and frontend == "pip":
pytest.skip("Can't use pip as build frontend for pyodide platform")
if get_platform() == "pyodide" and frontend in {"pip", "uv"}:
pytest.skip("Can't use pip or uv as build frontend for pyodide platform")
if frontend == "uv" and find_uv() is None:
pytest.skip("Can't find uv")

return {"CIBW_BUILD_FRONTEND": frontend}

Expand Down
7 changes: 7 additions & 0 deletions test/test_troubleshooting.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@

SO_FILE_WARNING = "NOTE: Shared object (.so) files found in this project."

PYPROJECT_TOML = """
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta:__legacy__"
"""


@pytest.mark.parametrize("project_contains_so_files", [False, True])
def test_failed_build_with_so_files(tmp_path, capfd, build_frontend_env, project_contains_so_files):
project = TestProject()
project.files["setup.py"] = "raise Exception('this build will fail')\n"
project.files["pyproject.toml"] = PYPROJECT_TOML
if project_contains_so_files:
project.files["libnothing.so"] = ""

Expand Down
5 changes: 5 additions & 0 deletions unit_test/options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ def test_environment_pass_references():
"build",
[],
),
(
'build-frontend = "uv"',
"uv",
[],
),
(
'build-frontend = {name = "build"}',
"build",
Expand Down
Loading