feat: add the ability to declare safe tools in a cross-build environment. (#2317)
* Add the ability to declare safe tools in a cross-build environment. * Add an xfail if cmake isn't available on the test machine. * Placate linter regarding positional args. * Rework test to provide more robust confirmation of safe tools. * Remove a test skip condition that is no longer needed. Co-authored-by: Joe Rickerby <joerick@mac.com> * Rename the setting to xbuild-tools. * Add docs to clarify that xbuild-tools is transitive. * Raise a warning if xbuild-tools isn't defined. * Correct a bad copy-paste in the schema generator. * .. and now fix the indentation. * Move sentinel handling earlier into the parsing process. * Remove serialization from tests that won't start a test suite. --------- Co-authored-by: Joe Rickerby <joerick@mac.com>
This commit is contained in:
co-authored by
Joe Rickerby
parent
2aaa489371
commit
830e79e11c
@@ -5,6 +5,7 @@ import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from collections.abc import Sequence, Set
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
@@ -151,6 +152,7 @@ def cross_virtualenv(
|
||||
build_python: Path,
|
||||
venv_path: Path,
|
||||
dependency_constraint_flags: Sequence[PathOrStr],
|
||||
xbuild_tools: Sequence[str] | None,
|
||||
) -> dict[str, str]:
|
||||
"""Create a cross-compilation virtual environment.
|
||||
|
||||
@@ -178,6 +180,8 @@ def cross_virtualenv(
|
||||
created.
|
||||
:param dependency_constraint_flags: Any flags that should be used when
|
||||
constraining dependencies in the environment.
|
||||
:param xbuild_tools: A list of executable names (without paths) that are
|
||||
on the path, but must be preserved in the cross environment.
|
||||
"""
|
||||
# Create an initial macOS virtual environment
|
||||
env = virtualenv(
|
||||
@@ -210,14 +214,52 @@ def cross_virtualenv(
|
||||
#
|
||||
# To prevent problems, set the PATH to isolate the build environment from
|
||||
# sources that could introduce incompatible binaries.
|
||||
#
|
||||
# However, there may be some tools on the path that are needed for the
|
||||
# build. Find their location on the path, and link the underlying binaries
|
||||
# (fully resolving symlinks) to a "safe" location that will *only* contain
|
||||
# those tools. This avoids needing to add *all* of Homebrew to the path just
|
||||
# to get access to (for example) cmake for build purposes. A value of None
|
||||
# means the user hasn't provided a list of xbuild tools.
|
||||
xbuild_tools_path = venv_path / "cibw_xbuild_tools"
|
||||
xbuild_tools_path.mkdir()
|
||||
if xbuild_tools is None:
|
||||
log.warning(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
Your project configuration does not define any cross-build tools.
|
||||
|
||||
iOS builds use an isolated build environment; if your build process requires any
|
||||
third-party tools (such as cmake, ninja, or rustc), you must explicitly declare
|
||||
that those tools are required using xbuild-tools/CIBW_XBUILD_TOOLS. This will
|
||||
likely manifest as a "somebuildtool: command not found" error.
|
||||
|
||||
If the build succeeds, you can silence this warning by setting adding
|
||||
`xbuild-tools = []` to your pyproject.toml configuration, or exporting
|
||||
CIBW_XBUILD_TOOLS as an empty string into your environment.
|
||||
"""
|
||||
)
|
||||
)
|
||||
else:
|
||||
for tool in xbuild_tools:
|
||||
tool_path = shutil.which(tool)
|
||||
if tool_path is None:
|
||||
msg = f"Could not find a {tool!r} executable on the path."
|
||||
raise errors.FatalError(msg)
|
||||
|
||||
# Link the binary into the safe tools directory
|
||||
original = Path(tool_path).resolve()
|
||||
print(f"{tool!r} will be included in the cross-build environment (using {original})")
|
||||
(xbuild_tools_path / tool).symlink_to(original)
|
||||
|
||||
env["PATH"] = os.pathsep.join(
|
||||
[
|
||||
# The target python's binary directory
|
||||
str(target_python.parent),
|
||||
# The cross-platform environments binary directory
|
||||
# The cross-platform environment's binary directory
|
||||
str(venv_path / "bin"),
|
||||
# Cargo's binary directory (to allow for Rust compilation)
|
||||
str(Path.home() / ".cargo" / "bin"),
|
||||
# The directory of cross-build tools
|
||||
str(xbuild_tools_path),
|
||||
# The bare minimum Apple system paths.
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
@@ -235,10 +277,12 @@ def cross_virtualenv(
|
||||
|
||||
def setup_python(
|
||||
tmp: Path,
|
||||
*,
|
||||
python_configuration: PythonConfiguration,
|
||||
dependency_constraint_flags: Sequence[PathOrStr],
|
||||
environment: ParsedEnvironment,
|
||||
build_frontend: BuildFrontendName,
|
||||
xbuild_tools: Sequence[str] | None,
|
||||
) -> tuple[Path, dict[str, str]]:
|
||||
if build_frontend == "build[uv]":
|
||||
msg = "uv doesn't support iOS"
|
||||
@@ -291,6 +335,7 @@ def setup_python(
|
||||
build_python=build_python,
|
||||
venv_path=venv_path,
|
||||
dependency_constraint_flags=dependency_constraint_flags,
|
||||
xbuild_tools=xbuild_tools,
|
||||
)
|
||||
venv_bin_path = venv_path / "bin"
|
||||
assert venv_bin_path.exists()
|
||||
@@ -414,10 +459,11 @@ def build(options: Options, tmp_path: Path) -> None:
|
||||
|
||||
target_install_path, env = setup_python(
|
||||
identifier_tmp_dir / "build",
|
||||
config,
|
||||
dependency_constraint_flags,
|
||||
build_options.environment,
|
||||
build_frontend.name,
|
||||
python_configuration=config,
|
||||
dependency_constraint_flags=dependency_constraint_flags,
|
||||
environment=build_options.environment,
|
||||
build_frontend=build_frontend.name,
|
||||
xbuild_tools=build_options.xbuild_tools,
|
||||
)
|
||||
pip_version = get_pip_version(env)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user