Skip to content

Commit 40312da

Browse files
committed
ENH: Add Windows Stable ABI build support
Also requires InsightSoftwareConsortium/ITK#4558
1 parent d341e33 commit 40312da

File tree

4 files changed

+57
-73
lines changed

4 files changed

+57
-73
lines changed

scripts/internal/manylinux-build-wheels.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ for PYBIN in "${PYBINARIES[@]}"; do
116116
-DITK_SOURCE_DIR:PATH=${source_path} \
117117
-DITK_BINARY_DIR:PATH=${build_path} \
118118
-DBUILD_TESTING:BOOL=OFF \
119+
-DSKBUILD:BOOL=ON \
119120
-DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \
120121
-DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \
121122
-DCMAKE_CXX_COMPILER_TARGET:STRING=$(uname -m)-linux-gnu \

scripts/internal/windows_build_common.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
import shutil
66

7-
DEFAULT_PY_ENVS = ["38-x64", "39-x64", "310-x64", "311-x64", "312-x64"]
7+
DEFAULT_PY_ENVS = ["38-x64", "39-x64", "310-x64", "311-x64"]
88

99
SCRIPT_DIR = os.path.dirname(__file__)
1010
ROOT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "..", ".."))
@@ -23,7 +23,11 @@ def venv_paths(python_version):
2323
# with a given interpreter.
2424
xy_ver = python_version.split("-")[0]
2525

26-
python_library = "C:/Python%s/libs/python%s.lib" % (python_version, xy_ver)
26+
if int(python_version.split("-")[0][1:]) >= 11:
27+
# Stable ABI
28+
python_library = "C:/Python%s/libs/python3.lib" % (python_version)
29+
else:
30+
python_library = "C:/Python%s/libs/python%s.lib" % (python_version, xy_ver)
2731

2832
print("")
2933
print("Python3_EXECUTABLE: %s" % python_executable)

scripts/windows_build_module_wheels.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def fixup_wheel(py_envs, filepath, lib_paths:str='', exclude_libs:str=''):
113113
print(f'Library paths for fixup: {lib_paths}')
114114

115115
py_env = py_envs[0]
116-
116+
117117
delve_wheel = os.path.join("C:/P/IPP", "venv-" + py_env, "Scripts", "delvewheel.exe")
118118
check_call([delve_wheel, "repair", "--no-mangle-all", "--add-path",
119119
lib_paths, "--no-dll", exclude_libs, "--ignore-in-wheel", "-w",
@@ -132,7 +132,7 @@ def fixup_wheels(py_envs, lib_paths:str='', exclude_libs:str=''):
132132
if __name__ == '__main__':
133133
parser = argparse.ArgumentParser(description='Driver script to build ITK Python module wheels.')
134134
parser.add_argument('--py-envs', nargs='+', default=DEFAULT_PY_ENVS,
135-
help='Target Python environment versions, e.g. "37-x64".')
135+
help='Target Python environment versions, e.g. "39-x64".')
136136
parser.add_argument('--no-cleanup', dest='cleanup', action='store_false', help='Do not clean up temporary build files.')
137137
parser.add_argument('--lib-paths', nargs=1, default='', help='Add semicolon-delimited library directories for delvewheel to include in the module wheel')
138138
parser.add_argument('--exclude-libs', nargs=1, default='', help='Add semicolon-delimited library names that must not be included in the module wheel, e.g. "nvcuda.dll"')

scripts/windows_build_wheels.py

Lines changed: 48 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -46,42 +46,19 @@ def prepare_build_env(python_version):
4646
print("Creating python virtual environment: %s" % venv_dir)
4747
if not os.path.exists(venv_dir):
4848
check_call([venv, venv_dir])
49-
pip_install(venv_dir, "scikit-build")
49+
pip_install(venv_dir, "scikit-build-core")
50+
pip_install(venv_dir, "ninja")
5051
pip_install(venv_dir, "delvewheel")
5152

5253

5354
def build_wrapped_itk(
5455
ninja_executable, build_type, source_path, build_path,
5556
python_executable, python_include_dir, python_library):
5657

57-
try:
58-
# Because of python issue #14243, we set "delete=False" and
59-
# delete manually after process execution.
60-
script_file = tempfile.NamedTemporaryFile(
61-
delete=False, suffix=".py")
62-
script_file.write(bytearray(textwrap.dedent(
63-
"""
64-
import json
65-
from skbuild.platform_specifics.windows import WindowsPlatform
66-
# Instantiate
67-
build_platform = WindowsPlatform()
68-
generator = build_platform.default_generators[0]
69-
assert generator.name == "Ninja"
70-
print(json.dumps(generator.env))
71-
""" # noqa: E501
72-
), "utf-8"))
73-
script_file.file.flush()
74-
output = check_output([python_executable, script_file.name])
75-
build_env = json.loads(output.decode("utf-8").strip())
76-
finally:
77-
script_file.close()
78-
os.remove(script_file.name)
79-
8058
tbb_dir = os.path.join(ROOT_DIR, 'oneTBB-prefix', 'lib', 'cmake', 'TBB')
8159

8260
# Build ITK python
83-
with push_dir(directory=build_path, make_directory=True), \
84-
push_env(**build_env):
61+
with push_dir(directory=build_path, make_directory=True):
8562

8663
check_call([
8764
"cmake",
@@ -90,6 +67,7 @@ def build_wrapped_itk(
9067
"-DITK_SOURCE_DIR:PATH=%s" % source_path,
9168
"-DITK_BINARY_DIR:PATH=%s" % build_path,
9269
"-DBUILD_TESTING:BOOL=OFF",
70+
"-DSKBUILD:BOOL=ON",
9371
"-DPython3_EXECUTABLE:FILEPATH=%s" % python_executable,
9472
"-DITK_WRAP_unsigned_short:BOOL=ON",
9573
"-DITK_WRAP_double:BOOL=ON",
@@ -98,6 +76,7 @@ def build_wrapped_itk(
9876
"-DPython3_INCLUDE_DIR:PATH=%s" % python_include_dir,
9977
"-DPython3_INCLUDE_DIRS:PATH=%s" % python_include_dir,
10078
"-DPython3_LIBRARY:FILEPATH=%s" % python_library,
79+
"-DPython3_SABI_LIBRARY:FILEPATH=%s" % python_library,
10180
"-DWRAP_ITK_INSTALL_COMPONENT_IDENTIFIER:STRING=PythonWheel",
10281
"-DWRAP_ITK_INSTALL_COMPONENT_PER_MODULE:BOOL=ON",
10382
"-DPY_SITE_PACKAGES_PATH:PATH=.",
@@ -113,8 +92,8 @@ def build_wrapped_itk(
11392
check_call([ninja_executable])
11493

11594

116-
def build_wheel(python_version, single_wheel=False,
117-
cleanup=False, wheel_names=None,
95+
def build_wheel(python_version, build_type="Release", single_wheel=False,
96+
cleanup=True, wheel_names=None,
11897
cmake_options=[]):
11998

12099
python_executable, \
@@ -130,10 +109,9 @@ def build_wheel(python_version, single_wheel=False,
130109
check_call([pip, "install", "--upgrade",
131110
"-r", os.path.join(ROOT_DIR, "requirements-dev.txt")])
132111

133-
build_type = "Release"
134112
source_path = "%s/ITK" % ITK_SOURCE
135113
build_path = "%s/ITK-win_%s" % (ROOT_DIR, python_version)
136-
setup_py_configure = os.path.join(SCRIPT_DIR, "setup_py_configure.py")
114+
pyproject_configure = os.path.join(SCRIPT_DIR, "pyproject_configure.py")
137115

138116
# Clean up previous invocations
139117
if cleanup and os.path.exists(build_path):
@@ -145,26 +123,26 @@ def build_wheel(python_version, single_wheel=False,
145123
print("# Build single ITK wheel")
146124
print("#")
147125

148-
# Configure setup.py
149-
check_call([python_executable, setup_py_configure, "itk"])
126+
# Configure pyproject.toml
127+
check_call([python_executable, pyproject_configure, "itk"])
150128

151129
# Generate wheel
152130
check_call([
153-
python_executable,
154-
"setup.py", "bdist_wheel",
155-
"--build-type", build_type, "-G", "Ninja",
156-
"--",
157-
"-DCMAKE_MAKE_PROGRAM:FILEPATH=%s" % ninja_executable,
158-
"-DITK_SOURCE_DIR:PATH=%s" % source_path,
159-
"-DITK_BINARY_DIR:PATH=%s" % build_path,
160-
"-DPython3_EXECUTABLE:FILEPATH=%s" % python_executable,
161-
"-DPython3_INCLUDE_DIR:PATH=%s" % python_include_dir,
162-
"-DPython3_INCLUDE_DIRS:PATH=%s" % python_include_dir,
163-
"-DPython3_LIBRARY:FILEPATH=%s" % python_library,
164-
"-DDOXYGEN_EXECUTABLE:FILEPATH=C:/P/doxygen/doxygen.exe",
165-
] + cmake_options)
166-
# Cleanup
167-
check_call([python_executable, "setup.py", "clean"])
131+
python_executable,
132+
"-m", "pip",
133+
"--verbose",
134+
"wheel",
135+
"--wheel-dir", "dist",
136+
"--no-deps",
137+
"--config-settings=cmake.build-type=%s" % build_type,
138+
"--config-settings=cmake.define.ITK_SOURCE_DIR:PATH=%s" % source_path,
139+
"--config-settings=cmake.define.ITK_BINARY_DIR:PATH=%s" % build_path,
140+
"--config-settings=cmake.define.Python3_EXECUTABLE:FILEPATH=%s" % python_executable,
141+
"--config-settings=cmake.define.Python3_INCLUDE_DIR:PATH=%s" % python_include_dir,
142+
"--config-settings=cmake.define.Python3_INCLUDE_DIRS:PATH=%s" % python_include_dir,
143+
"--config-settings=cmake.define.Python3_LIBRARY:FILEPATH=%s" % python_library,
144+
"--config-settings=cmake.define.DOXYGEN_EXECUTABLE:FILEPATH=C:/P/doxygen/doxygen.exe",
145+
] + [o.replace('-D', '--config-settings=cmake.define.') for o in cmake_options] + ['.',])
168146

169147
else:
170148

@@ -184,30 +162,28 @@ def build_wheel(python_version, single_wheel=False,
184162
for wheel_name in content.readlines()]
185163

186164
for wheel_name in wheel_names:
187-
# Configure setup.py
165+
# Configure pyproject.toml
188166
check_call([
189-
python_executable, setup_py_configure, wheel_name])
167+
python_executable, pyproject_configure, wheel_name])
190168

191169
# Generate wheel
192170
check_call([
193171
python_executable,
194-
"setup.py", "bdist_wheel",
195-
"--build-type", build_type, "-G", "Ninja",
196-
"--",
197-
"-DCMAKE_MAKE_PROGRAM:FILEPATH=%s" % ninja_executable,
198-
"-DITK_SOURCE_DIR:PATH=%s" % source_path,
199-
"-DITK_BINARY_DIR:PATH=%s" % build_path,
200-
"-DITKPythonPackage_ITK_BINARY_REUSE:BOOL=ON",
201-
"-DITKPythonPackage_WHEEL_NAME:STRING=%s" % wheel_name,
202-
"-DPython3_EXECUTABLE:FILEPATH=%s" % python_executable,
203-
"-DPython3_INCLUDE_DIR:PATH=%s" % python_include_dir,
204-
"-DPython3_INCLUDE_DIRS:PATH=%s" % python_include_dir,
205-
"-DPython3_LIBRARY:FILEPATH=%s" % python_library
206-
] + cmake_options)
207-
208-
# Cleanup
209-
if cleanup:
210-
check_call([python_executable, "setup.py", "clean"])
172+
"-m", "pip",
173+
"--verbose",
174+
"wheel",
175+
"--wheel-dir", "dist",
176+
"--no-deps",
177+
"--config-settings=cmake.build-type=%s" % build_type,
178+
"--config-settings=cmake.define.ITK_SOURCE_DIR:PATH=%s" % source_path,
179+
"--config-settings=cmake.define.ITK_BINARY_DIR:PATH=%s" % build_path,
180+
"--config-settings=cmake.define.ITKPythonPackage_ITK_BINARY_REUSE:BOOL=ON",
181+
"--config-settings=cmake.define.ITKPythonPackage_WHEEL_NAME:STRING=%s" % wheel_name,
182+
"--config-settings=cmake.define.Python3_EXECUTABLE:FILEPATH=%s" % python_executable,
183+
"--config-settings=cmake.define.Python3_INCLUDE_DIR:PATH=%s" % python_include_dir,
184+
"--config-settings=cmake.define.Python3_INCLUDE_DIRS:PATH=%s" % python_include_dir,
185+
"--config-settings=cmake.define.Python3_LIBRARY:FILEPATH=%s" % python_library
186+
] + [o.replace('-D', '--config-settings=cmake.define.') for o in cmake_options] + ['.',])
211187

212188
# Remove unnecessary files for building against ITK
213189
if cleanup:
@@ -225,7 +201,7 @@ def fixup_wheel(py_envs, filepath, lib_paths:str=''):
225201
print(f'Library paths for fixup: {lib_paths}')
226202

227203
py_env = py_envs[0]
228-
204+
229205
delve_wheel = os.path.join(ROOT_DIR, "venv-" + py_env, "Scripts", "delvewheel.exe")
230206
check_call([delve_wheel, "repair", "--no-mangle-all", "--add-path",
231207
lib_paths, "--ignore-in-wheel", "-w",
@@ -267,6 +243,8 @@ def build_wheels(py_envs=DEFAULT_PY_ENVS, single_wheel=False,
267243
for py_env in py_envs:
268244
prepare_build_env(py_env)
269245

246+
build_type = "Release"
247+
270248
with push_dir(directory=ITK_SOURCE, make_directory=True):
271249

272250
cmake_executable = "cmake.exe"
@@ -279,6 +257,7 @@ def build_wheels(py_envs=DEFAULT_PY_ENVS, single_wheel=False,
279257
# Build standalone project and populate archive cache
280258
check_call([
281259
cmake_executable,
260+
"-DCMAKE_BUILD_TYPE:STRING=%s" % build_type,
282261
"-DITKPythonPackage_BUILD_PYTHON:PATH=0",
283262
"-G", "Ninja",
284263
"-DCMAKE_MAKE_PROGRAM:FILEPATH=%s" % ninja_executable,
@@ -293,7 +272,7 @@ def build_wheels(py_envs=DEFAULT_PY_ENVS, single_wheel=False,
293272
ninja_executable = shutil.which('ninja.exe')
294273
if ninja_executable is None:
295274
pip_install(tools_venv, "ninja")
296-
build_wheel(py_env, single_wheel=single_wheel,
275+
build_wheel(py_env, build_type, single_wheel=single_wheel,
297276
cleanup=cleanup, wheel_names=wheel_names,
298277
cmake_options=cmake_options)
299278

@@ -302,7 +281,7 @@ def main(wheel_names=None):
302281
parser = argparse.ArgumentParser(description='Driver script to build ITK Python wheels.')
303282
parser.add_argument('--single-wheel', action='store_true', help='Build a single wheel as opposed to one wheel per ITK module group.')
304283
parser.add_argument('--py-envs', nargs='+', default=DEFAULT_PY_ENVS,
305-
help='Target Python environment versions, e.g. "37-x64".')
284+
help='Target Python environment versions, e.g. "39-x64".')
306285
parser.add_argument('--no-cleanup', dest='cleanup', action='store_false', help='Do not clean up temporary build files.')
307286
parser.add_argument('--lib-paths', nargs=1, default='', help='Add semicolon-delimited library directories for delvewheel to include in the module wheel')
308287
parser.add_argument('cmake_options', nargs='*', help='Extra options to pass to CMake, e.g. -DBUILD_SHARED_LIBS:BOOL=OFF')

0 commit comments

Comments
 (0)