feat: config settings placeholders (#2827)

* feat: config settings placeholders

Assisted-by: Copilot:GPT-5.4
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>

* Update docs/options.md

Co-authored-by: agriya khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>

---------

Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: agriya khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
This commit is contained in:
Henry Schreiner
2026-05-09 14:11:40 -04:00
committed by GitHub
co-authored by agriya khetarpal
parent aed06ac94d
commit cbef1e8b89
9 changed files with 99 additions and 15 deletions
+6 -1
View File
@@ -5,7 +5,8 @@ from collections.abc import Sequence
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]] = {}
+15 -3
View File
@@ -24,7 +24,11 @@ from filelock import FileLock
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
@@ -466,7 +470,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,
@@ -484,7 +492,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,
+10 -2
View File
@@ -15,7 +15,11 @@ from filelock import FileLock
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,
)
+6 -2
View File
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, assert_never
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
@@ -286,7 +286,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"),
)
+10 -2
View File
@@ -19,7 +19,11 @@ from cibuildwheel import errors
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
@@ -474,7 +478,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"),
)
+6 -2
View File
@@ -17,7 +17,7 @@ from filelock import FileLock
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
@@ -423,7 +423,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,
)
+10 -2
View File
@@ -15,7 +15,11 @@ from filelock import FileLock
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"),
)
+11
View File
@@ -543,6 +543,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.
@@ -566,6 +569,14 @@ Platform-specific environment variables also available:<br/>
CIBW_CONFIG_SETTINGS: "--build-option=--use-mypyc"
```
```yaml
CIBW_CONFIG_SETTINGS_LINUX: "setup-args=--cross-file={project}/cross_file.txt"
```
```yaml
CIBW_CONFIG_SETTINGS: "editable-verbose=true source-dir={package}"
```
+25 -1
View File
@@ -10,7 +10,11 @@ import pytest
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,
@@ -593,6 +597,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"),
[