Skip to content

Commit 118059e

Browse files
committed
Merge branch 'master' into release
2 parents c4a27e1 + 3f0c260 commit 118059e

File tree

5 files changed

+161
-10
lines changed

5 files changed

+161
-10
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ if(ITKPythonPackage_SUPERBUILD)
271271
-DITK_WRAP_PYTHON:BOOL=ON
272272
-DITK_WRAP_unsigned_short:BOOL=ON
273273
-DITK_WRAP_double:BOOL=ON
274+
-DITK_WRAP_complex_double:BOOL=ON
274275
-DITK_WRAP_IMAGE_DIMS:STRING=2;3;4
275276
-DITK_WRAP_DOC:BOOL=ON
276277
-DDOXYGEN_EXECUTABLE:FILEPATH=${DOXYGEN_EXECUTABLE}

scripts/dockcross-manylinux-download-cache-and-build-module-wheels.sh

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33
# This module should be pulled and run from an ITKModule root directory to generate the Linux python wheels of this module,
44
# it is used by the azure-pipeline.yml file contained in ITKModuleTemplate: https://github.com/InsightSoftwareConsortium/ITKModuleTemplate
55

6+
# -----------------------------------------------------------------------
7+
# Script argument parsing
8+
#
9+
usage()
10+
{
11+
echo "Usage:
12+
dockcross-manylinux-download-cache-and-build-module-wheels
13+
[ -h | --help ] show usage
14+
[ -c | --cmake_options ] space-delimited string containing CMake options to forward to the module (e.g. \"-DBUILD_TESTING=OFF\")
15+
[ -x | --exclude_libs ] semicolon-delimited library names to exclude when repairing wheel (e.g. \"libcuda.so\")
16+
[ python_version ] build wheel for a specific python version. (e.g. cp39)"
17+
exit 2
18+
}
19+
20+
FORWARD_ARGS=("$@") # Store arguments to forward them later
21+
PARSED_ARGS=$(getopt -a -n dockcross-manylinux-download-cache-and-build-module-wheels \
22+
-o hc:x: --long help,cmake_options:,exclude_libs: -- "$@")
23+
eval set -- "$PARSED_ARGS"
24+
25+
while :
26+
do
27+
case "$1" in
28+
-h | --help) usage; break ;;
29+
-c | --cmake_options) CMAKE_OPTIONS="$2" ; shift 2 ;;
30+
-x | --exclude_libs) EXCLUDE_LIBS="$2" ; shift 2 ;;
31+
--) shift; break ;;
32+
*) echo "Unexpected option: $1.";
33+
usage; break ;;
34+
esac
35+
done
36+
# -----------------------------------------------------------------------
37+
638
# Packages distributed by github are in zstd format, so we need to download that binary to uncompress
739
if [[ ! -f zstd-1.2.0-linux.tar.gz ]]; then
840
curl https://data.kitware.com/api/v1/file/592dd8068d777f16d01e1a92/download -o zstd-1.2.0-linux.tar.gz
@@ -22,7 +54,7 @@ if [[ ! -f ./ITKPythonBuilds-linux.tar.zst ]]; then
2254
exit 255
2355
fi
2456
./zstd-1.2.0-linux/bin/unzstd ./ITKPythonBuilds-linux.tar.zst -o ITKPythonBuilds-linux.tar
25-
if [ "$#" -le 1 ]; then
57+
if [ "$#" -lt 1 ]; then
2658
echo "Extracting all files";
2759
tar xf ITKPythonBuilds-linux.tar
2860
else
@@ -39,4 +71,5 @@ if [[ ! -f ./ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh
3971
fi
4072
cp -a ITKPythonPackage/oneTBB-prefix ./
4173

74+
set -- "${FORWARD_ARGS[@]}"; # Restore initial argument list
4275
./ITKPythonPackage/scripts/dockcross-manylinux-build-module-wheels.sh "$@"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Patch auditwheel to skip actions on libraries specified in the whitelist.
2+
Other arguments are forwarded to auditwheel."""
3+
4+
import argparse
5+
import sys
6+
7+
from auditwheel.main import main
8+
from auditwheel.policy import _POLICIES as POLICIES
9+
10+
11+
def exclude_libs(whitelist):
12+
# Do not include the following libraries when repairing wheels.
13+
for lib in whitelist.split(';'):
14+
for p in POLICIES:
15+
p['lib_whitelist'].append(lib)
16+
17+
if __name__ == "__main__":
18+
parser = argparse.ArgumentParser(description='Driver script to build ITK Python module wheels.')
19+
parser.add_argument('command', nargs=1, default='', help='auditwheel command (e.g. repair).')
20+
parser.add_argument('wheel_file', nargs=1, default='', help='auditwheel wheel file.')
21+
parser.add_argument('--wheel-dir', '-w', nargs=1, default='', type=str, help='Directory to store delocated wheels.')
22+
parser.add_argument('--whitelist', nargs=1, default=None, type=str, help='Semicolon-delimited libraries to exclude from repaired wheel (e.g. libcuda.so)')
23+
args = parser.parse_args()
24+
25+
if args.whitelist is not None:
26+
whitelist = ';'.join(args.whitelist)
27+
exclude_libs(whitelist)
28+
# Do not forward whitelist args to auditwheel
29+
sys.argv.remove('--whitelist')
30+
sys.argv.remove(whitelist)
31+
32+
sys.exit(main())

scripts/internal/manylinux-build-module-wheels.sh

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,39 @@
1616
# /tmp/dockcross-manylinux-x64 -a "$DOCKER_ARGS" manylinux-build-module-wheels.sh
1717
#
1818

19+
# -----------------------------------------------------------------------
20+
# Script argument parsing
21+
#
22+
usage()
23+
{
24+
echo "Usage:
25+
manylinux-build-module-wheels
26+
[ -h | --help ] show usage
27+
[ -c | --cmake_options ] space-separated string of CMake options to forward to the module (e.g. \"-DBUILD_TESTING=OFF\")
28+
[ -x | --exclude_libs ] semicolon-separated library names to exclude when repairing wheel (e.g. \"libcuda.so\")
29+
[ python_version ] build wheel for a specific python version. (e.g. cp39)"
30+
exit 2
31+
}
32+
33+
PARSED_ARGS=$(getopt -a -n dockcross-manylinux-download-cache-and-build-module-wheels \
34+
-o hc:x: --long help,cmake_options:,exclude_libs: -- "$@")
35+
eval set -- "$PARSED_ARGS"
36+
37+
while :
38+
do
39+
case "$1" in
40+
-h | --help) usage; break ;;
41+
-c | --cmake_options) CMAKE_OPTIONS="$2" ; shift 2 ;;
42+
-x | --exclude_libs) EXCLUDE_LIBS="$2" ; shift 2 ;;
43+
--) shift; break ;;
44+
*) echo "Unexpected option: $1.";
45+
usage; break ;;
46+
esac
47+
done
48+
49+
PYTHON_VERSION="$@"
50+
# -----------------------------------------------------------------------
51+
1952
# -----------------------------------------------------------------------
2053
# These variables are set in common script:
2154
#
@@ -66,13 +99,19 @@ for PYBIN in "${PYBINARIES[@]}"; do
6699
-DBUILD_TESTING:BOOL=OFF \
67100
-DPython3_EXECUTABLE:FILEPATH=${Python3_EXECUTABLE} \
68101
-DPython3_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIR} \
102+
${CMAKE_OPTIONS} \
69103
|| exit 1
70104
${PYBIN}/python setup.py clean
71105
done
72106

73107
if test "${ARCH}" == "x64"; then
108+
# Make sure auditwheel is installed for this python exe before importing
109+
# it in auditwheel_whitelist_monkeypatch.py
110+
sudo ${Python3_EXECUTABLE} -m pip install auditwheel
74111
for whl in dist/*linux_$(uname -p).whl; do
75-
auditwheel repair ${whl} -w /work/dist/
112+
# Repair wheel using monkey patch to exclude shared libraries provided in whitelist
113+
${Python3_EXECUTABLE} "${script_dir}/auditwheel_whitelist_monkeypatch.py" \
114+
repair ${whl} -w /work/dist/ --whitelist "${EXCLUDE_LIBS}"
76115
rm ${whl}
77116
done
78117
fi

scripts/windows_build_module_wheels.py

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import glob
88
import sys
99
import argparse
10+
import shutil
1011

1112
SCRIPT_DIR = os.path.dirname(__file__)
1213
ROOT_DIR = os.path.abspath(os.getcwd())
@@ -19,6 +20,19 @@
1920
from wheel_builder_utils import push_dir, push_env
2021
from windows_build_common import DEFAULT_PY_ENVS, venv_paths
2122

23+
def install_and_import(package):
24+
"""
25+
Install package with pip and import in current script.
26+
"""
27+
import importlib
28+
try:
29+
importlib.import_module(package)
30+
except ImportError:
31+
import pip
32+
pip.main(['install', package])
33+
finally:
34+
globals()[package] = importlib.import_module(package)
35+
2236
def build_wheels(py_envs=DEFAULT_PY_ENVS, cleanup=True, cmake_options=[]):
2337
for py_env in py_envs:
2438
python_executable, \
@@ -64,33 +78,65 @@ def build_wheels(py_envs=DEFAULT_PY_ENVS, cleanup=True, cmake_options=[]):
6478
if cleanup:
6579
check_call([python_executable, "setup.py", "clean"])
6680

67-
68-
def fixup_wheel(py_envs, filepath, lib_paths:str=''):
69-
lib_paths = lib_paths.strip() if lib_paths.isspace() else lib_paths.strip() + ";"
70-
lib_paths += "C:/P/IPP/oneTBB-prefix/bin"
81+
def rename_wheel_init(py_env, filepath):
82+
"""
83+
Rename module __init__ file in wheel.
84+
This is required to prevent modules to override ITK's __init__ file on install.
85+
If the module ships its own __init__ file, it is automatically renamed to
86+
__init_{module_name}__ by this function. The renamed __init__ file will be executed
87+
by ITK's __init__ file when loading ITK.
88+
"""
89+
python_executable, python_include_dir, python_library, pip, ninja_executable, path = venv_paths(py_env)
90+
91+
# Get module info
92+
install_and_import("pkginfo")
93+
w = pkginfo.Wheel(filepath)
94+
module_name = w.name.split("itk-")[-1]
95+
module_version = w.version
96+
97+
dist_dir = os.path.dirname(filepath)
98+
wheel_dir = os.path.join(dist_dir, "itk_" + module_name + "-" + module_version)
99+
init_dir = os.path.join(wheel_dir, "itk")
100+
init_file = os.path.join(init_dir, "__init__.py")
101+
102+
# Unpack wheel and rename __init__ file if it exists.
103+
check_call([python_executable, "-m", "wheel", "unpack", filepath, "-d", dist_dir])
104+
if os.path.isfile(init_file):
105+
shutil.move(init_file, os.path.join(init_dir, "__init_" + module_name + "__.py"))
106+
# Pack wheel and clean wheel folder
107+
check_call([python_executable, "-m", "wheel", "pack", wheel_dir, "-d", dist_dir])
108+
shutil.rmtree(wheel_dir)
109+
110+
def fixup_wheel(py_envs, filepath, lib_paths:str='', exclude_libs:str=''):
111+
lib_paths = ';'.join(["C:/P/IPP/oneTBB-prefix/bin",lib_paths.strip()]).strip(';')
71112
print(f'Library paths for fixup: {lib_paths}')
72113

73114
py_env = py_envs[0]
74115

75116
delve_wheel = os.path.join(ROOT_DIR, "venv-" + py_env, "Scripts", "delvewheel.exe")
76117
check_call([delve_wheel, "repair", "--no-mangle-all", "--add-path",
77-
lib_paths, "--ignore-in-wheel", "-w",
118+
lib_paths, "--no-dll", exclude_libs, "--ignore-in-wheel", "-w",
78119
os.path.join(ROOT_DIR, "dist"), filepath])
79120

121+
# The delve_wheel patch loading shared libraries is added to the module
122+
# __init__ file. Rename this file here to prevent conflicts on installation.
123+
# The renamed __init__ file will be executed when loading ITK.
124+
rename_wheel_init(py_env, filepath)
80125

81-
def fixup_wheels(py_envs, lib_paths:str=''):
126+
def fixup_wheels(py_envs, lib_paths:str='', exclude_libs:str=''):
82127
# shared library fix-up
83128
for wheel in glob.glob(os.path.join(ROOT_DIR, "dist", "*.whl")):
84-
fixup_wheel(py_envs, wheel, ';'.join(lib_paths))
129+
fixup_wheel(py_envs, wheel, lib_paths, exclude_libs)
85130

86131
if __name__ == '__main__':
87132
parser = argparse.ArgumentParser(description='Driver script to build ITK Python module wheels.')
88133
parser.add_argument('--py-envs', nargs='+', default=DEFAULT_PY_ENVS,
89134
help='Target Python environment versions, e.g. "37-x64".')
90135
parser.add_argument('--no-cleanup', dest='cleanup', action='store_false', help='Do not clean up temporary build files.')
91136
parser.add_argument('--lib-paths', nargs=1, default='', help='Add semicolon-delimited library directories for delvewheel to include in the module wheel')
137+
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"')
92138
parser.add_argument('cmake_options', nargs='*', help='Extra options to pass to CMake, e.g. -DBUILD_SHARED_LIBS:BOOL=OFF')
93139
args = parser.parse_args()
94140

95141
build_wheels(cleanup=args.cleanup, py_envs=args.py_envs, cmake_options=args.cmake_options)
96-
fixup_wheels(args.py_envs, ';'.join(args.lib_paths))
142+
fixup_wheels(args.py_envs, ';'.join(args.lib_paths), ';'.join(args.exclude_libs))

0 commit comments

Comments
 (0)