diff --git a/cibuildwheel/__main__.py b/cibuildwheel/__main__.py index 9208f5d45..4e5b9a00b 100644 --- a/cibuildwheel/__main__.py +++ b/cibuildwheel/__main__.py @@ -27,7 +27,6 @@ Unbuffered, detect_ci_provider, resources_dir, - strtobool, ) MANYLINUX_ARCHS = ( @@ -41,6 +40,8 @@ "pypy_i686", ) +BUILD_FRONTENDS = {"pip", "build"} + def main() -> None: platform: PlatformName @@ -182,10 +183,10 @@ def main() -> None: build_config = options("build", env_plat=False, sep=" ") or "*" skip_config = options("skip", env_plat=False, sep=" ") test_skip = options("test-skip", env_plat=False, sep=" ") - pypa_build = strtobool(os.environ.get("CIBW_PYPA_BUILD", "0")) archs_config_str = args.archs or options("archs", sep=" ") + build_frontend = options("build-frontend", env_plat=False) environment_config = options("environment", table={"item": '{k}="{v}"', "sep": " "}) before_all = options("before-all", sep=" && ") before_build = options("before-build", sep=" && ") @@ -202,6 +203,11 @@ def main() -> None: os.environ.get("CIBW_PRERELEASE_PYTHONS", "0") ) + if build_frontend not in BUILD_FRONTENDS: + msg = f"cibuildwheel: Unrecognised build front end '{build_frontend}', only {BUILD_FRONTENDS} supported" + print(msg, file=sys.stderr) + sys.exit(2) + package_files = {"setup.py", "setup.cfg", "pyproject.toml"} if not any(package_dir.joinpath(name).exists() for name in package_files): @@ -310,7 +316,7 @@ def main() -> None: environment=environment, dependency_constraints=dependency_constraints, manylinux_images=manylinux_images or None, - pypa_build=pypa_build, + build_frontend=build_frontend, ) # Python is buffering by default when running on the CI platforms, giving problems interleaving subprocess call output with unflushed calls to 'print' diff --git a/cibuildwheel/linux.py b/cibuildwheel/linux.py index 9b6a60799..d2bf56ab9 100644 --- a/cibuildwheel/linux.py +++ b/cibuildwheel/linux.py @@ -182,34 +182,38 @@ def build(options: BuildOptions) -> None: verbosity_flags = get_build_verbosity_extra_flags(options.build_verbosity) - if options.pypa_build: - config_setting = " ".join(verbosity_flags) + if options.build_frontend == "pip": docker.call( [ "python", "-m", - "build", + "pip", + "wheel", container_package_dir, - "--wheel", - f"--outdir={built_wheel_dir}", - f"--config-setting={config_setting}", + f"--wheel-dir={built_wheel_dir}", + "--no-deps", + *verbosity_flags, ], env=env, ) - else: + elif options.build_frontend == "build": + config_setting = " ".join(verbosity_flags) docker.call( [ "python", "-m", - "pip", - "wheel", + "build", container_package_dir, - f"--wheel-dir={built_wheel_dir}", - "--no-deps", - *verbosity_flags, + "--wheel", + f"--outdir={built_wheel_dir}", + f"--config-setting={config_setting}", ], env=env, ) + else: + raise RuntimeError( + f"build_frontend {options.build_frontend!r} not understood" + ) built_wheel = docker.glob(built_wheel_dir, "*.whl")[0] diff --git a/cibuildwheel/macos.py b/cibuildwheel/macos.py index 4a055f75c..5c94b34d5 100644 --- a/cibuildwheel/macos.py +++ b/cibuildwheel/macos.py @@ -179,7 +179,7 @@ def setup_python( python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment, - pypa_build: bool, + build_frontend: str, ) -> Dict[str, str]: implementation_id = python_configuration.identifier.split("-")[0] @@ -311,31 +311,33 @@ def setup_python( env.setdefault("SDKROOT", arm64_compatible_sdks[0]) log.step("Installing build tools...") - if pypa_build: + if build_frontend == "pip": call( [ "pip", "install", "--upgrade", + "setuptools", + "wheel", "delocate", - "build[virtualenv]", *dependency_constraint_flags, ], env=env, ) - else: + elif build_frontend == "build": call( [ "pip", "install", "--upgrade", - "setuptools", - "wheel", "delocate", + "build[virtualenv]", *dependency_constraint_flags, ], env=env, ) + else: + raise RuntimeError(f"build_frontend {build_frontend!r} not understood") return env @@ -376,7 +378,7 @@ def build(options: BuildOptions) -> None: config, dependency_constraint_flags, options.environment, - options.pypa_build, + options.build_frontend, ) if options.before_build: @@ -393,7 +395,23 @@ def build(options: BuildOptions) -> None: verbosity_flags = get_build_verbosity_extra_flags(options.build_verbosity) - if options.pypa_build: + if options.build_frontend == "pip": + # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org + # see https://github.com/pypa/cibuildwheel/pull/369 + call( + [ + "python", + "-m", + "pip", + "wheel", + options.package_dir.resolve(), + f"--wheel-dir={built_wheel_dir}", + "--no-deps", + *verbosity_flags, + ], + env=env, + ) + elif options.build_frontend == "build": config_setting = " ".join(verbosity_flags) build_env = dict(env) if options.dependency_constraints: @@ -414,21 +432,7 @@ def build(options: BuildOptions) -> None: env=build_env, ) else: - # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org - # see https://github.com/pypa/cibuildwheel/pull/369 - call( - [ - "python", - "-m", - "pip", - "wheel", - options.package_dir.resolve(), - f"--wheel-dir={built_wheel_dir}", - "--no-deps", - *verbosity_flags, - ], - env=env, - ) + raise RuntimeError(f"build_frontend {options.build_frontend!r} not understood") built_wheel = next(built_wheel_dir.glob("*.whl")) diff --git a/cibuildwheel/resources/defaults.toml b/cibuildwheel/resources/defaults.toml index a9ecff021..5bf179c89 100644 --- a/cibuildwheel/resources/defaults.toml +++ b/cibuildwheel/resources/defaults.toml @@ -4,6 +4,7 @@ skip = "" test-skip = "" archs = ["auto"] +build-frontend = "pip" dependency-versions = "pinned" environment = {} build-verbosity = "" diff --git a/cibuildwheel/util.py b/cibuildwheel/util.py index f751956ce..e7e5a675a 100644 --- a/cibuildwheel/util.py +++ b/cibuildwheel/util.py @@ -220,7 +220,7 @@ class BuildOptions(NamedTuple): test_requires: List[str] test_extras: str build_verbosity: int - pypa_build: bool + build_frontend: str class NonPlatformWheelError(Exception): @@ -312,9 +312,9 @@ def get_pip_version(env: Dict[str, str]) -> str: versions_output_text = subprocess.check_output( ["python", "-m", "pip", "freeze", "--all"], universal_newlines=True, shell=shell, env=env ) - (pip_version,) = [ + (pip_version,) = ( version[5:] for version in versions_output_text.strip().splitlines() if version.startswith("pip==") - ] + ) return pip_version diff --git a/cibuildwheel/windows.py b/cibuildwheel/windows.py index 3cc4c0cef..188efd805 100644 --- a/cibuildwheel/windows.py +++ b/cibuildwheel/windows.py @@ -115,7 +115,7 @@ def setup_python( python_configuration: PythonConfiguration, dependency_constraint_flags: Sequence[PathOrStr], environment: ParsedEnvironment, - pypa_build: bool, + build_frontend: str, ) -> Dict[str, str]: nuget = Path("C:\\cibw\\nuget.exe") @@ -218,12 +218,7 @@ def setup_python( call(["pip", "--version"], env=env) - if pypa_build: - call( - ["pip", "install", "--upgrade", "build[virtualenv]", *dependency_constraint_flags], - env=env, - ) - else: + if build_frontend == "pip": call( [ "pip", @@ -235,6 +230,13 @@ def setup_python( ], env=env, ) + elif build_frontend == "build": + call( + ["pip", "install", "--upgrade", "build[virtualenv]", *dependency_constraint_flags], + env=env, + ) + else: + raise RuntimeError(f"build_frontend {build_frontend!r} not understood") return env @@ -272,7 +274,7 @@ def build(options: BuildOptions) -> None: config, dependency_constraint_flags, options.environment, - options.pypa_build, + options.build_frontend, ) # run the before_build command @@ -290,7 +292,23 @@ def build(options: BuildOptions) -> None: verbosity_flags = get_build_verbosity_extra_flags(options.build_verbosity) - if options.pypa_build: + if options.build_frontend == "pip": + # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org + # see https://github.com/pypa/cibuildwheel/pull/369 + call( + [ + "python", + "-m", + "pip", + "wheel", + options.package_dir.resolve(), + f"--wheel-dir={built_wheel_dir}", + "--no-deps", + *get_build_verbosity_extra_flags(options.build_verbosity), + ], + env=env, + ) + elif options.build_frontend == "build": config_setting = " ".join(verbosity_flags) build_env = dict(env) if options.dependency_constraints: @@ -311,21 +329,7 @@ def build(options: BuildOptions) -> None: env=build_env, ) else: - # Path.resolve() is needed. Without it pip wheel may try to fetch package from pypi.org - # see https://github.com/pypa/cibuildwheel/pull/369 - call( - [ - "python", - "-m", - "pip", - "wheel", - options.package_dir.resolve(), - f"--wheel-dir={built_wheel_dir}", - "--no-deps", - *get_build_verbosity_extra_flags(options.build_verbosity), - ], - env=env, - ) + raise RuntimeError(f"build_frontend {options.build_frontend!r} not understood") built_wheel = next(built_wheel_dir.glob("*.whl")) diff --git a/test/conftest.py b/test/conftest.py index ce433b8a0..06cb577c5 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -23,6 +23,8 @@ def pytest_collection_modifyitems(config, items) -> None: item.add_marker(skip_emulation) -@pytest.fixture(params=[{"CIBW_PYPA_BUILD": "0"}, {"CIBW_PYPA_BUILD": "1"}], ids=["pip", "pypa"]) +@pytest.fixture( + params=[{"CIBW_BUILD_FRONTEND": "pip"}, {"CIBW_BUILD_FRONTEND": "build"}], ids=["pip", "build"] +) def build_mode(request) -> Dict[str, str]: - return request.param + return request.param # type: ignore