Skip to content

Commit 501e503

Browse files
authored
fix: Windows ARM cross-compile (#162)
Experimental cross-compile support. Signed-off-by: Henry Schreiner <[email protected]>
1 parent 942174e commit 501e503

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

src/scikit_build_core/builder/builder.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from ..resources import find_python
1515
from ..settings.skbuild_model import ScikitBuildSettings
1616
from .generator import set_environment_for_gen
17-
from .sysconfig import get_python_include_dir, get_python_library
17+
from .sysconfig import get_platform, get_python_include_dir, get_python_library
1818

1919
__all__: list[str] = ["Builder"]
2020

@@ -45,6 +45,9 @@ def get_archs(self) -> list[str]:
4545
if sys.platform.startswith("darwin"):
4646
archs = re.findall(r"-arch (\S+)", self.config.env.get("ARCHFLAGS", ""))
4747
return archs
48+
if sys.platform.startswith("win"):
49+
if get_platform(self.config.env) == "win-arm64":
50+
return ["win_arm64"]
4851

4952
return []
5053

@@ -94,9 +97,13 @@ def configure(
9497
if version is not None:
9598
cache_config["SKBUILD_PROJECT_VERSION"] = str(version)
9699

97-
# Classic Find Python
98-
python_library = get_python_library()
100+
if limited_abi is None:
101+
limited_abi = self.settings.wheel.py_api.startswith("cp3")
102+
103+
python_library = get_python_library(self.config.env, abi3=limited_abi)
99104
python_include_dir = get_python_include_dir()
105+
106+
# Classic Find Python
100107
cache_config["PYTHON_EXECUTABLE"] = sys.executable
101108
cache_config["PYTHON_INCLUDE_DIR"] = python_include_dir
102109
if python_library:
@@ -109,9 +116,6 @@ def configure(
109116
cache_config[f"{prefix}_INCLUDE_DIR"] = python_include_dir
110117
cache_config[f"{prefix}_FIND_REGISTRY"] = "NEVER"
111118

112-
if limited_abi is None:
113-
limited_abi = self.settings.wheel.py_api.startswith("cp3")
114-
115119
if limited_abi:
116120
cache_config["SKBUILD_SOABI"] = (
117121
"" if sys.platform.startswith("win") else "abi3"

src/scikit_build_core/builder/sysconfig.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import configparser
34
import os
45
import sys
56
import sysconfig
@@ -30,7 +31,18 @@ def __dir__() -> list[str]:
3031
return __all__
3132

3233

33-
def get_python_library() -> Path | None:
34+
def get_python_library(env: Mapping[str, str], *, abi3: bool = False) -> Path | None:
35+
# When cross-compiling, check DIST_EXTRA_CONFIG first
36+
config_file = env.get("DIST_EXTRA_CONFIG", None)
37+
if config_file and Path(config_file).is_file():
38+
cp = configparser.ConfigParser()
39+
cp.read(config_file)
40+
result = cp.get("build_ext", "library_dirs", fallback="")
41+
if result:
42+
logger.info("Reading DIST_EXTRA_CONFIG:build_ext.library_dirs={}", result)
43+
minor = "" if abi3 else sys.version_info[1]
44+
return Path(result) / f"python3{minor}.lib"
45+
3446
libdirstr = sysconfig.get_config_var("LIBDIR")
3547
ldlibrarystr = sysconfig.get_config_var("LDLIBRARY")
3648
libdir: Path | None = libdirstr and Path(libdirstr)
@@ -96,8 +108,11 @@ def get_platform(env: Mapping[str, str] | None = None) -> str:
96108
"""
97109
if env is None:
98110
env = os.environ
99-
if os.name == "nt" and "VSCMD_ARG_TGT_ARCH" in env:
100-
return TARGET_TO_PLAT.get(env["VSCMD_ARG_TGT_ARCH"]) or get_host_platform()
111+
if sys.platform.startswith("win"):
112+
if "VSCMD_ARG_TGT_ARCH" in env:
113+
return TARGET_TO_PLAT.get(env["VSCMD_ARG_TGT_ARCH"]) or get_host_platform()
114+
if "arm64" in env.get("SETUPTOOLS_EXT_SUFFIX", "").lower():
115+
return "win-arm64"
101116
return get_host_platform()
102117

103118

tests/test_builder.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
import sysconfig
66
import typing
7+
from pathlib import Path
78
from types import SimpleNamespace
89

910
import pytest
@@ -54,14 +55,34 @@ def test_get_python_include_dir():
5455
def test_get_python_library():
5556
pprint.pprint(sysconfig.get_config_vars())
5657

57-
lib = get_python_library()
58+
lib = get_python_library({})
5859
if sys.platform.startswith("win"):
5960
assert lib is None
6061
else:
6162
assert lib
6263
assert lib.is_file()
6364

6465

66+
@pytest.mark.skipif(not sys.platform.startswith("win"), reason="Windows only")
67+
def test_get_python_library_xcompile(tmp_path):
68+
config_path = tmp_path / "tmp.cfg"
69+
config_path.write_text(
70+
"""\
71+
[build_ext]
72+
library_dirs=C:\\Python\\libs
73+
"""
74+
)
75+
env = {"DIST_EXTRA_CONFIG": str(config_path)}
76+
lib = get_python_library(env)
77+
assert lib
78+
assert lib.parent == Path("C:\\Python\\libs")
79+
assert lib.parent != Path("C:\\Python\\libs\\python3.lib")
80+
81+
lib2 = get_python_library(env, abi3=True)
82+
assert lib2
83+
assert lib2 == Path("C:\\Python\\libs\\python3.lib")
84+
85+
6586
@pytest.mark.parametrize("archs", (["x86_64"], ["arm64", "universal2"]))
6687
def test_builder_macos_arch(monkeypatch, archs):
6788
archflags = " ".join(f"-arch {arch}" for arch in archs)

0 commit comments

Comments
 (0)