Skip to content

Commit 084f457

Browse files
authored
feat: wheel_tag & support for conda's CMAKE_SYSTEM_PROCESSOR (#207)
A bit of refactoring. Signed-off-by: Henry Schreiner <[email protected]>
1 parent ed20b57 commit 084f457

File tree

5 files changed

+61
-63
lines changed

5 files changed

+61
-63
lines changed

src/scikit_build_core/build/wheel.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import dataclasses
4+
import os
45
import shutil
56
import sys
67
import tempfile
@@ -13,7 +14,7 @@
1314
from .. import __version__
1415
from .._compat import tomllib
1516
from .._logging import logger, rich_print
16-
from ..builder.builder import Builder
17+
from ..builder.builder import Builder, archs_to_tags, get_archs
1718
from ..builder.wheel_tag import WheelTag
1819
from ..cmake import CMake, CMaker
1920
from ..settings.skbuild_read_settings import SettingsReader
@@ -108,9 +109,18 @@ def _build_wheel_impl(
108109
build_tmp_folder = Path(tmpdir)
109110
wheel_dir = build_tmp_folder / "wheel"
110111

112+
tags = WheelTag.compute_best(
113+
archs_to_tags(get_archs(os.environ)),
114+
settings.wheel.py_api,
115+
expand_macos=settings.wheel.expand_macos_universal_tags,
116+
)
117+
111118
# A build dir can be specified, otherwise use a temporary directory
112119
build_dir = (
113-
Path(settings.build_dir.format(cache_tag=sys.implementation.cache_tag))
120+
Path(
121+
settings.build_dir.format(cache_tag=sys.implementation.cache_tag),
122+
wheel_tag=str(tags),
123+
)
114124
if settings.build_dir
115125
else build_tmp_folder / "build"
116126
)
@@ -153,12 +163,6 @@ def _build_wheel_impl(
153163
config=config,
154164
)
155165

156-
tags = WheelTag.compute_best(
157-
builder.get_arch_tags(),
158-
settings.wheel.py_api,
159-
expand_macos=settings.wheel.expand_macos_universal_tags,
160-
)
161-
162166
if wheel_directory is None:
163167
if metadata_directory is None:
164168
msg = "metadata_directory must be specified if wheel_directory is None"

src/scikit_build_core/builder/builder.py

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import sys
66
import sysconfig
7+
from collections.abc import Sequence
78
from pathlib import Path
89
from typing import Mapping
910

@@ -17,7 +18,7 @@
1718
from .generator import set_environment_for_gen
1819
from .sysconfig import get_platform, get_python_include_dir, get_python_library
1920

20-
__all__: list[str] = ["Builder"]
21+
__all__: list[str] = ["Builder", "get_archs", "archs_to_tags"]
2122

2223
DIR = Path(__file__).parent.resolve()
2324

@@ -26,45 +27,53 @@ def __dir__() -> list[str]:
2627
return __all__
2728

2829

29-
@dataclasses.dataclass
30-
class Builder:
31-
settings: ScikitBuildSettings
32-
config: CMaker
30+
# TODO: cross-compile support for other platforms
31+
def get_archs(env: Mapping[str, str], cmake_args: Sequence[str] = ()) -> list[str]:
32+
"""
33+
Takes macOS platform settings and returns a list of platforms.
3334
34-
# TODO: cross-compile support for other platforms
35-
def get_archs(self) -> list[str]:
36-
"""
37-
Takes macOS platform settings and returns a list of platforms.
35+
Example (macOS):
36+
ARCHFLAGS="-arch x86_64" -> ["x86_64"]
37+
ARCHFLAGS="-arch x86_64 -arch arm64" -> ["x86_64", "arm64"]
3838
39-
Example (macOS):
40-
ARCHFLAGS="-arch x86_64" -> ["x86_64"]
41-
ARCHFLAGS="-arch x86_64 -arch arm64" -> ["x86_64", "arm64"]
39+
Returns an empty list otherwise or if ARCHFLAGS is not set.
40+
"""
4241

43-
Returns an empty list otherwise or if ARCHFLAGS is not set.
44-
"""
42+
if sys.platform.startswith("darwin"):
43+
for cmake_arg in cmake_args:
44+
if "CMAKE_SYSTEM_PROCESSOR" in cmake_arg:
45+
return [cmake_arg.split("=")[1]]
46+
archs = re.findall(r"-arch (\S+)", env.get("ARCHFLAGS", ""))
47+
return archs
48+
if sys.platform.startswith("win") and get_platform(env) == "win-arm64":
49+
return ["win_arm64"]
50+
51+
return []
52+
53+
54+
def archs_to_tags(archs: list[str]) -> list[str]:
55+
"""
56+
Convert a list of architectures to a list of tags (e.g. "universal2").
57+
"""
58+
if sys.platform.startswith("darwin") and set(archs) == {"arm64", "x86_64"}:
59+
return ["universal2"]
60+
return archs
4561

46-
if sys.platform.startswith("darwin"):
47-
archs = re.findall(r"-arch (\S+)", self.config.env.get("ARCHFLAGS", ""))
48-
return archs
49-
if (
50-
sys.platform.startswith("win")
51-
and get_platform(self.config.env) == "win-arm64"
52-
):
53-
return ["win_arm64"]
5462

55-
return []
63+
@dataclasses.dataclass
64+
class Builder:
65+
settings: ScikitBuildSettings
66+
config: CMaker
5667

57-
def get_arch_tags(self) -> list[str]:
68+
def get_cmake_args(self) -> list[str]:
5869
"""
59-
This function returns tags suitable for use in wheels. The main
60-
difference between this method and get_archs() is that this returns
61-
universal2 instead of separate tags for x86_64 and arm64.
70+
Get CMake args from the settings and environment.
6271
"""
72+
# Adding CMake arguments set as environment variable
73+
# (needed e.g. to build for ARM OSX on conda-forge)
74+
env_cmake_args = filter(None, self.config.env.get("CMAKE_ARGS", "").split(" "))
6375

64-
archs = self.get_archs()
65-
if sys.platform.startswith("darwin") and set(archs) == {"arm64", "x86_64"}:
66-
return ["universal2"]
67-
return archs
76+
return [*self.settings.cmake.args, *env_cmake_args]
6877

6978
def configure(
7079
self,
@@ -76,7 +85,6 @@ def configure(
7685
limited_abi: bool | None = None,
7786
) -> None:
7887
cmake_defines = dict(defines)
79-
cmake_args: list[str] = []
8088

8189
# Add site-packages to the prefix path for CMake
8290
site_packages = Path(sysconfig.get_path("purelib"))
@@ -151,18 +159,9 @@ def configure(
151159

152160
self.config.init_cache(cache_config)
153161

154-
# Add the pre-defined or passed CMake args
155-
cmake_args += self.settings.cmake.args
156-
157-
# Adding CMake arguments set as environment variable
158-
# (needed e.g. to build for ARM OSX on conda-forge)
159-
cmake_args += [
160-
item for item in self.config.env.get("CMAKE_ARGS", "").split(" ") if item
161-
]
162-
163162
if sys.platform.startswith("darwin"):
164163
# Cross-compile support for macOS - respect ARCHFLAGS if set
165-
archs = self.get_archs()
164+
archs = get_archs(self.config.env)
166165
if archs:
167166
cmake_defines["CMAKE_OSX_ARCHITECTURES"] = ";".join(archs)
168167

@@ -171,7 +170,7 @@ def configure(
171170

172171
self.config.configure(
173172
defines=cmake_defines,
174-
cmake_args=cmake_args,
173+
cmake_args=self.get_cmake_args(),
175174
)
176175

177176
def build(self, build_args: list[str]) -> None:

src/scikit_build_core/cmake.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def init_cache(
139139
)
140140

141141
def _compute_cmake_args(
142-
self, settings: Mapping[str, str | os.PathLike[str] | bool]
142+
self, defines: Mapping[str, str | os.PathLike[str] | bool]
143143
) -> Generator[str, None, None]:
144144
yield f"-S{self.source_dir}"
145145
yield f"-B{self.build_dir}"
@@ -150,7 +150,7 @@ def _compute_cmake_args(
150150
if self.single_config and self.build_type:
151151
yield f"-DCMAKE_BUILD_TYPE={self.build_type}"
152152

153-
for key, value in settings.items():
153+
for key, value in defines.items():
154154
if isinstance(value, bool):
155155
value = "ON" if value else "OFF"
156156
yield f"-D{key}:BOOL={value}"

src/scikit_build_core/setuptools/extension.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from setuptools.dist import Distribution
1313

1414
from .._compat.typing import Literal
15-
from ..builder.builder import Builder
15+
from ..builder.builder import Builder, get_archs
1616
from ..builder.macos import normalize_macos_version
1717
from ..cmake import CMake, CMaker
1818
from ..settings.skbuild_read_settings import SettingsReader
@@ -77,7 +77,7 @@ def build_extension(self, ext: setuptools.Extension) -> None:
7777

7878
# Setuptools requires this be specified if there's a mismatch.
7979
if sys.platform.startswith("darwin"):
80-
arm_only = builder.get_archs() == ["arm64"]
80+
arm_only = get_archs(builder.config.env) == ["arm64"]
8181
orig_macos_str = sysconfig.get_platform().rsplit("-", 1)[0].split("-", 1)[1]
8282
orig_macos = normalize_macos_version(orig_macos_str, arm_only)
8383
config.env.setdefault("MACOSX_DEPLOYMENT_TARGET", str(orig_macos))

tests/test_builder.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import pytest
1111

12-
from scikit_build_core.builder.builder import Builder
12+
from scikit_build_core.builder.builder import Builder, archs_to_tags, get_archs
1313
from scikit_build_core.builder.macos import get_macosx_deployment_target
1414
from scikit_build_core.builder.sysconfig import (
1515
get_python_include_dir,
@@ -87,12 +87,7 @@ def test_get_python_library_xcompile(tmp_path):
8787
def test_builder_macos_arch(monkeypatch, archs):
8888
archflags = " ".join(f"-arch {arch}" for arch in archs)
8989
monkeypatch.setattr(sys, "platform", "darwin")
90-
monkeypatch.setenv("ARCHFLAGS", archflags)
91-
tmpcfg = SimpleNamespace(env=os.environ.copy())
92-
tmpbuilder = typing.cast(
93-
Builder, SimpleNamespace(config=tmpcfg, settings=ScikitBuildSettings())
94-
)
95-
assert Builder.get_archs(tmpbuilder) == archs
90+
assert get_archs({"ARCHFLAGS": archflags}) == archs
9691

9792

9893
def test_builder_macos_arch_extra(monkeypatch):
@@ -105,7 +100,7 @@ def test_builder_macos_arch_extra(monkeypatch):
105100
settings=ScikitBuildSettings(wheel=WheelSettings()),
106101
config=tmpcfg,
107102
)
108-
assert tmpbuilder.get_arch_tags() == ["universal2"]
103+
assert archs_to_tags(get_archs(tmpbuilder.config.env)) == ["universal2"]
109104

110105

111106
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)