From 8eb5822a3c43ad0cf7df9905501931cfe6bb8a3d Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Mon, 27 Apr 2026 18:47:56 -0400 Subject: [PATCH 1/2] feat: config settings placeholders Assisted-by: Copilot:GPT-5.4 Signed-off-by: Henry Schreiner --- cibuildwheel/frontend.py | 7 ++++++- cibuildwheel/platforms/android.py | 18 +++++++++++++++--- cibuildwheel/platforms/ios.py | 12 ++++++++++-- cibuildwheel/platforms/linux.py | 8 ++++++-- cibuildwheel/platforms/macos.py | 12 ++++++++++-- cibuildwheel/platforms/pyodide.py | 8 ++++++-- cibuildwheel/platforms/windows.py | 12 ++++++++++-- docs/options.md | 11 +++++++++++ unit_test/options_test.py | 26 +++++++++++++++++++++++++- 9 files changed, 99 insertions(+), 15 deletions(-) diff --git a/cibuildwheel/frontend.py b/cibuildwheel/frontend.py index eb55f4f64..e6808c0f6 100644 --- a/cibuildwheel/frontend.py +++ b/cibuildwheel/frontend.py @@ -5,7 +5,8 @@ from typing import Literal, Self, get_args from cibuildwheel.logger import log -from cibuildwheel.util.helpers import parse_key_value_string +from cibuildwheel.typing import PathOrStr +from cibuildwheel.util.helpers import parse_key_value_string, prepare_command BuildFrontendName = Literal["pip", "build", "build[uv]", "uv"] @@ -58,6 +59,10 @@ def _split_config_settings(config_settings: str) -> list[str]: return [f"-C{setting}" for setting in config_settings_list] +def prepare_config_settings(config_settings: str, *, project: PathOrStr, package: PathOrStr) -> str: + return prepare_command(config_settings, project=project, package=package) + + # Based on build.__main__.main. def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str]]: config_settings: dict[str, str | list[str]] = {} diff --git a/cibuildwheel/platforms/android.py b/cibuildwheel/platforms/android.py index 50b07884c..46d299602 100644 --- a/cibuildwheel/platforms/android.py +++ b/cibuildwheel/platforms/android.py @@ -24,7 +24,11 @@ from cibuildwheel import errors, platforms # pylint: disable=cyclic-import from cibuildwheel.architecture import Architecture, arch_synonym -from cibuildwheel.frontend import get_build_frontend_extra_flags, parse_config_settings +from cibuildwheel.frontend import ( + get_build_frontend_extra_flags, + parse_config_settings, + prepare_config_settings, +) from cibuildwheel.logger import log from cibuildwheel.options import BuildOptions, Options from cibuildwheel.selector import BuildSelector @@ -463,7 +467,11 @@ def build_wheel(state: BuildState) -> Path: *get_build_frontend_extra_flags( state.options.build_frontend, state.options.build_verbosity, - state.options.config_settings, + prepare_config_settings( + state.options.config_settings, + project=".", + package=state.options.package_dir, + ), py38=False, ), env=state.android_env, @@ -481,7 +489,11 @@ def build_wheel(state: BuildState) -> Path: *get_build_frontend_extra_flags( state.options.build_frontend, state.options.build_verbosity, - state.options.config_settings, + prepare_config_settings( + state.options.config_settings, + project=".", + package=state.options.package_dir, + ), py38=False, ), env=state.android_env, diff --git a/cibuildwheel/platforms/ios.py b/cibuildwheel/platforms/ios.py index 9e2474483..f157f5836 100644 --- a/cibuildwheel/platforms/ios.py +++ b/cibuildwheel/platforms/ios.py @@ -15,7 +15,11 @@ from cibuildwheel import errors from cibuildwheel.architecture import Architecture from cibuildwheel.environment import ParsedEnvironment -from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags +from cibuildwheel.frontend import ( + BuildFrontendName, + get_build_frontend_extra_flags, + prepare_config_settings, +) from cibuildwheel.logger import log from cibuildwheel.options import Options from cibuildwheel.platforms.macos import install_cpython as install_build_cpython @@ -477,7 +481,11 @@ def build(options: Options, tmp_path: Path) -> None: extra_flags = get_build_frontend_extra_flags( build_frontend, build_options.build_verbosity, - build_options.config_settings, + prepare_config_settings( + build_options.config_settings, + project=".", + package=build_options.package_dir, + ), py38=False, ) diff --git a/cibuildwheel/platforms/linux.py b/cibuildwheel/platforms/linux.py index d5d9366b7..7ac6d6345 100644 --- a/cibuildwheel/platforms/linux.py +++ b/cibuildwheel/platforms/linux.py @@ -10,7 +10,7 @@ from cibuildwheel import errors from cibuildwheel.architecture import Architecture -from cibuildwheel.frontend import get_build_frontend_extra_flags +from cibuildwheel.frontend import get_build_frontend_extra_flags, prepare_config_settings from cibuildwheel.logger import log from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform from cibuildwheel.options import BuildOptions, Options @@ -276,7 +276,11 @@ def build_in_container( extra_flags = get_build_frontend_extra_flags( build_frontend, build_options.build_verbosity, - build_options.config_settings, + prepare_config_settings( + build_options.config_settings, + project=container_project_path, + package=container_package_dir, + ), py38=config.identifier[1:].startswith("p38"), ) diff --git a/cibuildwheel/platforms/macos.py b/cibuildwheel/platforms/macos.py index 37c3d799c..4c6aecc09 100644 --- a/cibuildwheel/platforms/macos.py +++ b/cibuildwheel/platforms/macos.py @@ -19,7 +19,11 @@ from cibuildwheel.architecture import Architecture from cibuildwheel.ci import detect_ci_provider from cibuildwheel.environment import ParsedEnvironment -from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags +from cibuildwheel.frontend import ( + BuildFrontendName, + get_build_frontend_extra_flags, + prepare_config_settings, +) from cibuildwheel.logger import log from cibuildwheel.options import Options from cibuildwheel.selector import BuildSelector @@ -477,7 +481,11 @@ def build(options: Options, tmp_path: Path) -> None: extra_flags = get_build_frontend_extra_flags( build_frontend, build_options.build_verbosity, - build_options.config_settings, + prepare_config_settings( + build_options.config_settings, + project=".", + package=build_options.package_dir, + ), py38=config.identifier[1:].startswith("p38"), ) diff --git a/cibuildwheel/platforms/pyodide.py b/cibuildwheel/platforms/pyodide.py index e0560b4a0..371c7029b 100644 --- a/cibuildwheel/platforms/pyodide.py +++ b/cibuildwheel/platforms/pyodide.py @@ -17,7 +17,7 @@ from cibuildwheel import errors from cibuildwheel.architecture import Architecture from cibuildwheel.environment import ParsedEnvironment -from cibuildwheel.frontend import get_build_frontend_extra_flags +from cibuildwheel.frontend import get_build_frontend_extra_flags, prepare_config_settings from cibuildwheel.logger import log from cibuildwheel.options import Options from cibuildwheel.selector import BuildSelector @@ -424,7 +424,11 @@ def build(options: Options, tmp_path: Path) -> None: extra_flags = get_build_frontend_extra_flags( build_frontend, build_options.build_verbosity, - build_options.config_settings, + prepare_config_settings( + build_options.config_settings, + project=".", + package=build_options.package_dir, + ), py38=False, ) diff --git a/cibuildwheel/platforms/windows.py b/cibuildwheel/platforms/windows.py index 3bb9e86f7..ccf2075fc 100644 --- a/cibuildwheel/platforms/windows.py +++ b/cibuildwheel/platforms/windows.py @@ -15,7 +15,11 @@ from cibuildwheel import errors from cibuildwheel.architecture import Architecture from cibuildwheel.environment import ParsedEnvironment -from cibuildwheel.frontend import BuildFrontendName, get_build_frontend_extra_flags +from cibuildwheel.frontend import ( + BuildFrontendName, + get_build_frontend_extra_flags, + prepare_config_settings, +) from cibuildwheel.logger import log from cibuildwheel.options import Options from cibuildwheel.selector import BuildSelector @@ -462,7 +466,11 @@ def build(options: Options, tmp_path: Path) -> None: extra_flags = get_build_frontend_extra_flags( build_frontend, build_options.build_verbosity, - build_options.config_settings, + prepare_config_settings( + build_options.config_settings, + project=".", + package=options.globals.package_dir, + ), py38=config.identifier[1:].startswith("p38"), ) diff --git a/docs/options.md b/docs/options.md index fd84d83c0..5111bac63 100644 --- a/docs/options.md +++ b/docs/options.md @@ -552,6 +552,9 @@ Specify config settings for the build backend. Each space separated item will be passed via `--config-setting`. In TOML, you can specify a table of items, including arrays. +You can use the `{project}` or `{package}` placeholders in `config-settings` +to refer to the project root or package being built, respectively. + !!! tip Currently, "build" supports arrays for options, but "pip" only supports single values. @@ -575,6 +578,14 @@ Platform-specific environment variables also available:
CIBW_CONFIG_SETTINGS: "--build-option=--use-mypyc" ``` + ```yaml + CIBW_CONFIG_SETTINGS_WINDOWS: "setup-args=--cross-file={project}/meson_cross_files/windows-386.ini" + ``` + + ```yaml + CIBW_CONFIG_SETTINGS: "editable-verbose=true source-dir={package}" + ``` + diff --git a/unit_test/options_test.py b/unit_test/options_test.py index 0c42b1f9a..05995a013 100644 --- a/unit_test/options_test.py +++ b/unit_test/options_test.py @@ -10,7 +10,11 @@ from cibuildwheel import errors from cibuildwheel.bashlex_eval import local_environment_executor -from cibuildwheel.frontend import BuildFrontendConfig, get_build_frontend_extra_flags +from cibuildwheel.frontend import ( + BuildFrontendConfig, + get_build_frontend_extra_flags, + prepare_config_settings, +) from cibuildwheel.logger import Logger from cibuildwheel.options import ( CommandLineArguments, @@ -638,6 +642,26 @@ def test_get_build_frontend_extra_flags_warning( mock_warning.assert_called_once() +@pytest.mark.parametrize( + ("config_settings", "expected"), + [ + ( + "setup-args=--cross-file={project}/meson_cross_files/windows-386.ini", + "setup-args=--cross-file=C:/project/meson_cross_files/windows-386.ini", + ), + ( + "setup-args=--cross-file={package}/meson_cross_files/windows-386.ini", + "setup-args=--cross-file=C:/project/pkg/meson_cross_files/windows-386.ini", + ), + ], +) +def test_prepare_config_settings(config_settings: str, expected: str) -> None: + assert ( + prepare_config_settings(config_settings, project="C:/project", package="C:/project/pkg") + == expected + ) + + @pytest.mark.parametrize( ("definition", "expected_args"), [ From 5c3512b3c3bf26b1a7c8f31fcf0e9b092b01b387 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 30 Apr 2026 09:10:26 -0400 Subject: [PATCH 2/2] Update docs/options.md Co-authored-by: agriya khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> --- docs/options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/options.md b/docs/options.md index 5111bac63..6217d8bb2 100644 --- a/docs/options.md +++ b/docs/options.md @@ -579,7 +579,7 @@ Platform-specific environment variables also available:
``` ```yaml - CIBW_CONFIG_SETTINGS_WINDOWS: "setup-args=--cross-file={project}/meson_cross_files/windows-386.ini" + CIBW_CONFIG_SETTINGS_LINUX: "setup-args=--cross-file={project}/cross_file.txt" ``` ```yaml