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 typing import Literal, Self, get_args
from cibuildwheel.logger import log 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"] 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] 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. # Based on build.__main__.main.
def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str]]: def parse_config_settings(config_settings_str: str) -> dict[str, str | list[str]]:
config_settings: 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 import errors, platforms # pylint: disable=cyclic-import
from cibuildwheel.architecture import Architecture, arch_synonym 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.logger import log
from cibuildwheel.options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
from cibuildwheel.selector import BuildSelector from cibuildwheel.selector import BuildSelector
@@ -466,7 +470,11 @@ def build_wheel(state: BuildState) -> Path:
*get_build_frontend_extra_flags( *get_build_frontend_extra_flags(
state.options.build_frontend, state.options.build_frontend,
state.options.build_verbosity, state.options.build_verbosity,
state.options.config_settings, prepare_config_settings(
state.options.config_settings,
project=".",
package=state.options.package_dir,
),
py38=False, py38=False,
), ),
env=state.android_env, env=state.android_env,
@@ -484,7 +492,11 @@ def build_wheel(state: BuildState) -> Path:
*get_build_frontend_extra_flags( *get_build_frontend_extra_flags(
state.options.build_frontend, state.options.build_frontend,
state.options.build_verbosity, state.options.build_verbosity,
state.options.config_settings, prepare_config_settings(
state.options.config_settings,
project=".",
package=state.options.package_dir,
),
py38=False, py38=False,
), ),
env=state.android_env, env=state.android_env,
+10 -2
View File
@@ -15,7 +15,11 @@ from filelock import FileLock
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture from cibuildwheel.architecture import Architecture
from cibuildwheel.environment import ParsedEnvironment 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.logger import log
from cibuildwheel.options import Options from cibuildwheel.options import Options
from cibuildwheel.platforms.macos import install_cpython as install_build_cpython 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( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_frontend,
build_options.build_verbosity, build_options.build_verbosity,
build_options.config_settings, prepare_config_settings(
build_options.config_settings,
project=".",
package=build_options.package_dir,
),
py38=False, py38=False,
) )
+6 -2
View File
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, assert_never
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture 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.logger import log
from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform from cibuildwheel.oci_container import OCIContainer, OCIContainerEngineConfig, OCIPlatform
from cibuildwheel.options import BuildOptions, Options from cibuildwheel.options import BuildOptions, Options
@@ -286,7 +286,11 @@ def build_in_container(
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_frontend,
build_options.build_verbosity, 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"), 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.architecture import Architecture
from cibuildwheel.ci import detect_ci_provider from cibuildwheel.ci import detect_ci_provider
from cibuildwheel.environment import ParsedEnvironment 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.logger import log
from cibuildwheel.options import Options from cibuildwheel.options import Options
from cibuildwheel.selector import BuildSelector from cibuildwheel.selector import BuildSelector
@@ -474,7 +478,11 @@ def build(options: Options, tmp_path: Path) -> None:
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_frontend,
build_options.build_verbosity, 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"), py38=config.identifier[1:].startswith("p38"),
) )
+6 -2
View File
@@ -17,7 +17,7 @@ from filelock import FileLock
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture from cibuildwheel.architecture import Architecture
from cibuildwheel.environment import ParsedEnvironment 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.logger import log
from cibuildwheel.options import Options from cibuildwheel.options import Options
from cibuildwheel.selector import BuildSelector from cibuildwheel.selector import BuildSelector
@@ -423,7 +423,11 @@ def build(options: Options, tmp_path: Path) -> None:
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_frontend,
build_options.build_verbosity, build_options.build_verbosity,
build_options.config_settings, prepare_config_settings(
build_options.config_settings,
project=".",
package=build_options.package_dir,
),
py38=False, py38=False,
) )
+10 -2
View File
@@ -15,7 +15,11 @@ from filelock import FileLock
from cibuildwheel import errors from cibuildwheel import errors
from cibuildwheel.architecture import Architecture from cibuildwheel.architecture import Architecture
from cibuildwheel.environment import ParsedEnvironment 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.logger import log
from cibuildwheel.options import Options from cibuildwheel.options import Options
from cibuildwheel.selector import BuildSelector from cibuildwheel.selector import BuildSelector
@@ -462,7 +466,11 @@ def build(options: Options, tmp_path: Path) -> None:
extra_flags = get_build_frontend_extra_flags( extra_flags = get_build_frontend_extra_flags(
build_frontend, build_frontend,
build_options.build_verbosity, 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"), 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 item will be passed via `--config-setting`. In TOML, you can specify
a table of items, including arrays. 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 !!! tip
Currently, "build" supports arrays for options, but "pip" only supports Currently, "build" supports arrays for options, but "pip" only supports
single values. single values.
@@ -566,6 +569,14 @@ Platform-specific environment variables also available:<br/>
CIBW_CONFIG_SETTINGS: "--build-option=--use-mypyc" 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 import errors
from cibuildwheel.bashlex_eval import local_environment_executor 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.logger import Logger
from cibuildwheel.options import ( from cibuildwheel.options import (
CommandLineArguments, CommandLineArguments,
@@ -593,6 +597,26 @@ def test_get_build_frontend_extra_flags_warning(
mock_warning.assert_called_once() 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( @pytest.mark.parametrize(
("definition", "expected_args"), ("definition", "expected_args"),
[ [