From 4117689dbb02f93b23d049bd93bd248e075cd92c Mon Sep 17 00:00:00 2001 From: Hugo Osvaldo Barrera Date: Sat, 25 Jul 2026 20:35:27 +0200 Subject: [PATCH] Don't require dependencies for foreign targets Fixes: https://github.com/PyO3/setuptools-rust/issues/610 --- CHANGELOG.md | 4 ++++ setuptools_rust/build.py | 17 ++++++++++++++++- setuptools_rust/extension.py | 23 ++++++++++++++++++++--- tests/test_extension.py | 9 +++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6e7156..969e0716 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased +### Fixed +- Pass `--filter-platform` to `cargo metadata` so offline builds don't require dependencies exclusive to foreign targets. [#610](https://github.com/PyO3/setuptools-rust/pull/610) + ## 1.13.0 (2026-06-27) ### Added - Add `generated-files` option to `RustExtension` to copy files from the build script output directory to the wheel. [#574](https://github.com/PyO3/setuptools-rust/pull/574) diff --git a/setuptools_rust/build.py b/setuptools_rust/build.py index ff7ab184..7d2d725c 100644 --- a/setuptools_rust/build.py +++ b/setuptools_rust/build.py @@ -32,6 +32,7 @@ from .command import RustCommand from .extension import Binding, RustBin, RustExtension, Strip from .rustc_info import ( + _is_custom_target, get_rust_host, get_rust_version, get_rustc_cfgs, @@ -129,6 +130,17 @@ def run_for_extension(self, ext: RustExtension) -> None: dylib_paths, artifact_dir = self.build_extension(ext) self.install_extension(ext, dylib_paths, artifact_dir) + def _metadata_filter_platforms(self, ext: RustExtension) -> Tuple[str, ...]: + """Target triples of the platforms being built.""" + target = self.target + if target is _Platform.CARGO_DEFAULT: + return (get_rust_host(ext.env),) + elif target is _Platform.UNIVERSAL2: + return _UNIVERSAL2_TARGETS + elif _is_custom_target(target): + return () # Custom target specs cannot be passed to --filter-platform + return target + def build_extension( self, ext: RustExtension ) -> Tuple[List["_BuiltModule"], Optional[Path]]: @@ -148,7 +160,10 @@ def build_extension( debug = self._is_debug_build(ext) use_cargo_crate_type = _check_cargo_supports_crate_type_option(ext.env) - package_id = ext.metadata(quiet=quiet)["resolve"]["root"] + package_id = ext.metadata( + quiet=quiet, + filter_platforms=self._metadata_filter_platforms(ext), + )["resolve"]["root"] if package_id is None: raise FileError( f"manifest for Rust extention `{ext.name}` at path `{ext.path}` is a virtual manifest (a workspace root without a package).\n\n" diff --git a/setuptools_rust/extension.py b/setuptools_rust/extension.py index bd3e5c03..072843f2 100644 --- a/setuptools_rust/extension.py +++ b/setuptools_rust/extension.py @@ -256,16 +256,31 @@ def install_script(self, module_name: str, exe_path: str) -> None: with open(file, "w") as f: f.write(_SCRIPT_TEMPLATE.format(executable=repr(executable))) - def metadata(self, *, quiet: bool) -> "CargoMetadata": + def metadata( + self, + *, + quiet: bool, + filter_platforms: Sequence[str] = (), + ) -> "CargoMetadata": """Returns cargo metadata for this extension package. + ``filter_platforms`` restricts the dependency resolution to the given + target triples (``cargo metadata --filter-platform``). + Cached - will only execute cargo on first invocation. """ - return self._metadata(os.environ.get("CARGO", "cargo"), quiet) + return self._metadata( + os.environ.get("CARGO", "cargo"), quiet, tuple(filter_platforms) + ) @lru_cache() - def _metadata(self, cargo: str, quiet: bool) -> "CargoMetadata": + def _metadata( + self, + cargo: str, + quiet: bool, + filter_platforms: "tuple[str, ...]" = (), + ) -> "CargoMetadata": metadata_command = [ cargo, "metadata", @@ -274,6 +289,8 @@ def _metadata(self, cargo: str, quiet: bool) -> "CargoMetadata": "--format-version", "1", ] + for platform in filter_platforms: + metadata_command.append(f"--filter-platform={platform}") if self.cargo_manifest_args: metadata_command.extend(self.cargo_manifest_args) diff --git a/tests/test_extension.py b/tests/test_extension.py index 28315649..9a4b6ea5 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -4,6 +4,7 @@ from pytest import CaptureFixture, MonkeyPatch from setuptools_rust.extension import RustBin, RustExtension +from setuptools_rust.rustc_info import get_rust_host SETUPTOOLS_RUST_DIR = Path(__file__).parent.parent @@ -33,6 +34,14 @@ def test_metadata_contents(hello_world_bin: RustBin) -> None: assert "target_directory" in metadata +def test_metadata_filter_platforms(hello_world_bin: RustBin) -> None: + metadata = hello_world_bin.metadata( + quiet=False, filter_platforms=(get_rust_host(None),) + ) + assert "target_directory" in metadata + assert metadata["resolve"]["root"] is not None + + def test_metadata_cargo_log( capfd: CaptureFixture, monkeypatch: MonkeyPatch, hello_world_bin: RustBin ) -> None: