1
1
#! /bin/bash
2
2
3
- # Setup that needs to be done before multibuild utils are invoked
4
- PROJECTDIR=$( pwd)
5
- if [[ " $( uname -s) " == " Darwin" ]]; then
6
- # Safety check - macOS builds require that CIBW_ARCHS is set, and that it
7
- # only contains a single value (even though cibuildwheel allows multiple
8
- # values in CIBW_ARCHS).
3
+ # Safety check - Pillow builds require that CIBW_ARCHS is set, and that it only
4
+ # contains a single value (even though cibuildwheel allows multiple values in
5
+ # CIBW_ARCHS). This check doesn't work on Linux because of how the CIBW_ARCHS
6
+ # variable is exposed.
7
+ function check_cibw_archs {
9
8
if [[ -z " $CIBW_ARCHS " ]]; then
10
- echo " ERROR: Pillow macOS builds require CIBW_ARCHS be defined."
9
+ echo " ERROR: Pillow builds require CIBW_ARCHS be defined."
11
10
exit 1
12
11
fi
13
12
if [[ " $CIBW_ARCHS " == * " " * ]]; then
14
- echo " ERROR: Pillow macOS builds only support a single architecture in CIBW_ARCHS."
13
+ echo " ERROR: Pillow builds only support a single architecture in CIBW_ARCHS."
15
14
exit 1
16
15
fi
16
+ }
17
+
18
+ # Setup that needs to be done before multibuild utils are invoked. Process
19
+ # potential cross-build platforms before native platforms to ensure that we pick
20
+ # up the cross environment.
21
+ PROJECTDIR=$( pwd)
22
+ if [[ " $CIBW_PLATFORM " == " ios" ]]; then
23
+ check_cibw_archs
24
+ # On iOS, CIBW_ARCHS is actually a multi-arch - arm64_iphoneos,
25
+ # arm64_iphonesimulator or x86_64_iphonesimulator. Split into the CPU
26
+ # platform, and the iOS SDK.
27
+ PLAT=$( echo $CIBW_ARCHS | sed " s/\(.*\)_\(.*\)/\1/" )
28
+ IOS_SDK=$( echo $CIBW_ARCHS | sed " s/\(.*\)_\(.*\)/\2/" )
29
+
30
+ # Build iOS builds in `build/iphoneos` or `build/iphonesimulator`
31
+ # (depending on the build target). Install them into `build/deps/iphoneos`
32
+ # or `build/deps/iphonesimulator`
33
+ WORKDIR=$( pwd) /build/$IOS_SDK
34
+ BUILD_PREFIX=$( pwd) /build/deps/$IOS_SDK
35
+ PATCH_DIR=$( pwd) /patches/iOS
36
+
37
+ # GNU tooling insists on using aarch64 rather than arm64
38
+ if [[ $PLAT == " arm64" ]]; then
39
+ GNU_ARCH=aarch64
40
+ else
41
+ GNU_ARCH=x86_64
42
+ fi
43
+
44
+ IOS_SDK_PATH=$( xcrun --sdk $IOS_SDK --show-sdk-path)
45
+ CMAKE_SYSTEM_NAME=iOS
46
+ IOS_HOST_TRIPLE=$PLAT -apple-ios$IPHONEOS_DEPLOYMENT_TARGET
47
+ if [[ " $IOS_SDK " == " iphonesimulator" ]]; then
48
+ IOS_HOST_TRIPLE=$IOS_HOST_TRIPLE -simulator
49
+ fi
17
50
51
+ # GNU Autotools doesn't recognize the existence of arm64-apple-ios-simulator
52
+ # as a valid host. However, the only difference between arm64-apple-ios and
53
+ # arm64-apple-ios-simulator is the choice of sysroot, and that is
54
+ # coordinated by CC, CFLAGS etc. From the perspective of configure, the two
55
+ # platforms are identical, so we can use arm64-apple-ios consistently.
56
+ # This (mostly) avoids us needing to patch config.sub in dependency sources.
57
+ HOST_CONFIGURE_FLAGS=" --disable-shared --enable-static --host=$GNU_ARCH -apple-ios --build=$GNU_ARCH -apple-darwin"
58
+
59
+ # CMake has native support for iOS. However, most of that support is based
60
+ # on using the Xcode builder, which isn't very helpful for most of Pillow's
61
+ # dependencies. Therefore, we lean on the OSX configurations, plus CC, CFLAGS
62
+ # etc. to ensure the right sysroot is selected.
63
+ HOST_CMAKE_FLAGS=" -DCMAKE_SYSTEM_NAME=$CMAKE_SYSTEM_NAME -DCMAKE_SYSTEM_PROCESSOR=$GNU_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET -DCMAKE_OSX_SYSROOT=$IOS_SDK_PATH -DBUILD_SHARED_LIBS=NO"
64
+
65
+ # Meson needs to be pointed at a cross-platform configuration file
66
+ # This will be generated once CC etc. have been evaluated.
67
+ HOST_MESON_FLAGS=" --cross-file $WORKDIR /meson-cross.txt -Dprefer_static=true -Ddefault_library=static"
68
+
69
+ elif [[ " $( uname -s) " == " Darwin" ]]; then
70
+ check_cibw_archs
18
71
# Build macOS dependencies in `build/darwin`
19
72
# Install them into `build/deps/darwin`
73
+ PLAT=$CIBW_ARCHS
20
74
WORKDIR=$( pwd) /build/darwin
21
75
BUILD_PREFIX=$( pwd) /build/deps/darwin
22
76
else
23
77
# Build prefix will default to /usr/local
78
+ PLAT=" ${CIBW_ARCHS:- $AUDITWHEEL_ARCH } "
24
79
WORKDIR=$( pwd) /build
25
80
MB_ML_LIBC=${AUDITWHEEL_POLICY:: 9}
26
81
MB_ML_VER=${AUDITWHEEL_POLICY: 9}
27
82
fi
28
- PLAT=" ${CIBW_ARCHS:- $AUDITWHEEL_ARCH } "
29
83
30
84
# Define custom utilities
31
85
source wheels/multibuild/common_utils.sh
32
86
source wheels/multibuild/library_builders.sh
33
- if [ -z " $IS_MACOS " ]; then
87
+ if [[ -z " $IS_MACOS " ] ]; then
34
88
source wheels/multibuild/manylinux_utils.sh
35
89
fi
36
90
37
91
ARCHIVE_SDIR=pillow-depends-main
38
92
39
- # Package versions for fresh source builds
93
+ # Package versions for fresh source builds. Version numbers with "Patched"
94
+ # annotations have a source code patch that is required for some platforms. If
95
+ # you change those versions, ensure the patch is also updated.
40
96
FREETYPE_VERSION=2.13.3
41
97
HARFBUZZ_VERSION=11.2.1
42
98
LIBPNG_VERSION=1.6.49
@@ -47,32 +103,58 @@ TIFF_VERSION=4.7.0
47
103
LCMS2_VERSION=2.17
48
104
ZLIB_VERSION=1.3.1
49
105
ZLIB_NG_VERSION=2.2.4
50
- LIBWEBP_VERSION=1.5.0
106
+ LIBWEBP_VERSION=1.5.0 # Patched; next release won't need patching. See patch file.
51
107
BZIP2_VERSION=1.0.8
52
108
LIBXCB_VERSION=1.17.0
53
- BROTLI_VERSION=1.1.0
109
+ BROTLI_VERSION=1.1.0 # Patched; next release won't need patching. See patch file.
54
110
LIBAVIF_VERSION=1.3.0
55
111
56
112
function build_pkg_config {
57
113
if [ -e pkg-config-stamp ]; then return ; fi
58
- # This essentially duplicates the Homebrew recipe
59
- CFLAGS=" $CFLAGS -Wno-int-conversion" build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
114
+ # This essentially duplicates the Homebrew recipe.
115
+ # On iOS, we need a binary that can be executed on the build machine; but we
116
+ # can create a host-specific pc-path to store iOS .pc files. To ensure a
117
+ # macOS-compatible build, we temporarily clear environment flags that set
118
+ # iOS-specific values.
119
+ if [[ -n " $IOS_SDK " ]]; then
120
+ ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
121
+ ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET
122
+ unset HOST_CONFIGURE_FLAGS
123
+ unset IPHONEOS_DEPLOYMENT_TARGET
124
+ fi
125
+
126
+ CFLAGS=" $CFLAGS -Wno-int-conversion" CPPFLAGS=" " build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
60
127
--disable-debug --disable-host-tool --with-internal-glib \
61
128
--with-pc-path=$BUILD_PREFIX /share/pkgconfig:$BUILD_PREFIX /lib/pkgconfig \
62
129
--with-system-include-path=$( xcrun --show-sdk-path --sdk macosx) /usr/include
130
+
131
+ if [[ -n " $IOS_SDK " ]]; then
132
+ HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS
133
+ IPHONEOS_DEPLOYMENT_TARGET=$ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET
134
+ fi ;
135
+
63
136
export PKG_CONFIG=$BUILD_PREFIX /bin/pkg-config
64
137
touch pkg-config-stamp
65
138
}
66
139
67
140
function build_zlib_ng {
68
141
if [ -e zlib-stamp ]; then return ; fi
142
+ # zlib-ng uses a "configure" script, but it's not a GNU autotools script, so
143
+ # it doesn't honor the usual flags. Temporarily disable any
144
+ # cross-compilation flags.
145
+ ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
146
+ unset HOST_CONFIGURE_FLAGS
147
+
69
148
build_github zlib-ng/zlib-ng $ZLIB_NG_VERSION --zlib-compat
70
149
71
- if [ -n " $IS_MACOS " ]; then
150
+ HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS
151
+
152
+ if [[ -n " $IS_MACOS " ]] && [[ -z " $IOS_SDK " ]]; then
72
153
# Ensure that on macOS, the library name is an absolute path, not an
73
154
# @rpath, so that delocate picks up the right library (and doesn't need
74
155
# DYLD_LIBRARY_PATH to be set). The default Makefile doesn't have an
75
- # option to control the install_name.
156
+ # option to control the install_name. This isn't needed on iOS, as iOS
157
+ # only builds the static library.
76
158
install_name_tool -id $BUILD_PREFIX /lib/libz.1.dylib $BUILD_PREFIX /lib/libz.1.dylib
77
159
fi
78
160
touch zlib-stamp
@@ -82,7 +164,7 @@ function build_brotli {
82
164
if [ -e brotli-stamp ]; then return ; fi
83
165
local out_dir=$( fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION .tar.gz brotli-$BROTLI_VERSION .tar.gz)
84
166
(cd $out_dir \
85
- && cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX /lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX /lib . \
167
+ && cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX /lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX /lib $HOST_CMAKE_FLAGS . \
86
168
&& make install)
87
169
touch brotli-stamp
88
170
}
@@ -93,7 +175,7 @@ function build_harfbuzz {
93
175
94
176
local out_dir=$( fetch_unpack https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION /harfbuzz-$HARFBUZZ_VERSION .tar.xz harfbuzz-$HARFBUZZ_VERSION .tar.xz)
95
177
(cd $out_dir \
96
- && meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX /lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled)
178
+ && meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX /lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled $HOST_MESON_FLAGS )
97
179
(cd $out_dir /build \
98
180
&& meson install)
99
181
touch harfbuzz-stamp
@@ -164,19 +246,19 @@ function build {
164
246
fi
165
247
166
248
build_simple xcb-proto 1.17.0 https://xorg.freedesktop.org/archive/individual/proto
167
- if [ -n " $IS_MACOS " ]; then
249
+ if [[ -n " $IS_MACOS " ] ]; then
168
250
build_simple xorgproto 2024.1 https://www.x.org/pub/individual/proto
169
251
build_simple libXau 1.0.12 https://www.x.org/pub/individual/lib
170
252
build_simple libpthread-stubs 0.5 https://xcb.freedesktop.org/dist
171
253
else
172
- sed s/\$ {pc_sysrootdir\} // $BUILD_PREFIX /share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX /lib/pkgconfig/xcb-proto.pc
254
+ sed " s/\$ {pc_sysrootdir\}//" $BUILD_PREFIX /share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX /lib/pkgconfig/xcb-proto.pc
173
255
fi
174
256
build_simple libxcb $LIBXCB_VERSION https://www.x.org/releases/individual/lib
175
257
176
258
build_libjpeg_turbo
177
- if [ -n " $IS_MACOS " ]; then
259
+ if [[ -n " $IS_MACOS " ] ]; then
178
260
# Custom tiff build to include jpeg; by default, configure won't include
179
- # headers/libs in the custom macOS prefix. Explicitly disable webp,
261
+ # headers/libs in the custom macOS/iOS prefix. Explicitly disable webp,
180
262
# libdeflate and zstd, because on x86_64 macs, it will pick up the
181
263
# Homebrew versions of those libraries from /usr/local.
182
264
build_simple tiff $TIFF_VERSION https://download.osgeo.org/libtiff tar.gz \
@@ -186,7 +268,10 @@ function build {
186
268
build_tiff
187
269
fi
188
270
189
- build_libavif
271
+ if [[ -z " $IOS_SDK " ]]; then
272
+ # Short term workaround; don't build libavif on iOS
273
+ build_libavif
274
+ fi
190
275
build_libpng
191
276
build_lcms2
192
277
build_openjpeg
@@ -201,14 +286,44 @@ function build {
201
286
202
287
build_brotli
203
288
204
- if [ -n " $IS_MACOS " ]; then
289
+ if [[ -n " $IS_MACOS " ] ]; then
205
290
# Custom freetype build
206
291
build_simple freetype $FREETYPE_VERSION https://download.savannah.gnu.org/releases/freetype tar.gz --with-harfbuzz=no
207
292
else
208
293
build_freetype
209
294
fi
210
295
211
- build_harfbuzz
296
+ if [[ -z " $IOS_SDK " ]]; then
297
+ # On iOS, there's no vendor-provided raqm, and we can't ship it due to
298
+ # licensing, so there's no point building harfbuzz.
299
+ build_harfbuzz
300
+ fi
301
+ }
302
+
303
+ function create_meson_cross_config {
304
+ cat << EOF > $WORKDIR /meson-cross.txt
305
+ [binaries]
306
+ pkg-config = '$BUILD_PREFIX /bin/pkg-config'
307
+ cmake = '$( which cmake) '
308
+ c = '$CC '
309
+ cpp = '$CXX '
310
+ strip = '$STRIP '
311
+
312
+ [built-in options]
313
+ c_args = '$CFLAGS -I$BUILD_PREFIX /include'
314
+ cpp_args = '$CXXFLAGS -I$BUILD_PREFIX /include'
315
+ c_link_args = '$CFLAGS -L$BUILD_PREFIX /lib'
316
+ cpp_link_args = '$CFLAGS -L$BUILD_PREFIX /lib'
317
+
318
+ [host_machine]
319
+ system = 'darwin'
320
+ subsystem = 'ios'
321
+ kernel = 'xnu'
322
+ cpu_family = '$( uname -m) '
323
+ cpu = '$( uname -m) '
324
+ endian = 'little'
325
+
326
+ EOF
212
327
}
213
328
214
329
# Perform all dependency builds in the build subfolder.
@@ -227,24 +342,40 @@ if [[ ! -d $WORKDIR/pillow-depends-main ]]; then
227
342
fi
228
343
229
344
if [[ -n " $IS_MACOS " ]]; then
230
- # Homebrew (or similar packaging environments) install can contain some of
231
- # the libraries that we're going to build. However, they may be compiled
232
- # with a MACOSX_DEPLOYMENT_TARGET that doesn't match what we want to use,
233
- # and they may bring in other dependencies that we don't want. The same will
234
- # be true of any other locations on the path. To avoid conflicts, strip the
235
- # path down to the bare minimum (which, on macOS, won't include any
236
- # development dependencies).
237
- export PATH=" $BUILD_PREFIX /bin:$( dirname $( which python3) ) :/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
238
- export CMAKE_PREFIX_PATH=$BUILD_PREFIX
239
-
240
345
# Ensure the basic structure of the build prefix directory exists.
241
346
mkdir -p " $BUILD_PREFIX /bin"
242
347
mkdir -p " $BUILD_PREFIX /lib"
243
348
244
- # Ensure pkg-config is available
349
+ # Ensure pkg-config is available. This is done *before* setting CC, CFLAGS
350
+ # etc. to ensure that the build is *always* a macOS build, even when building
351
+ # for iOS.
245
352
build_pkg_config
246
- # Ensure cmake is available
353
+
354
+ # Ensure cmake is available, and that the default prefix used by CMake is
355
+ # the build prefix
247
356
python3 -m pip install cmake
357
+ export CMAKE_PREFIX_PATH=$BUILD_PREFIX
358
+
359
+ if [[ -n " $IOS_SDK " ]]; then
360
+ export AR=" $( xcrun --find --sdk $IOS_SDK ar) "
361
+ export CPP=" $( xcrun --find --sdk $IOS_SDK clang) -E"
362
+ export CC=$( xcrun --find --sdk $IOS_SDK clang)
363
+ export CXX=$( xcrun --find --sdk $IOS_SDK clang++)
364
+ export LD=$( xcrun --find --sdk $IOS_SDK ld)
365
+ export STRIP=$( xcrun --find --sdk $IOS_SDK strip)
366
+
367
+ CPPFLAGS=" $CPPFLAGS --sysroot=$IOS_SDK_PATH "
368
+ CFLAGS=" -target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET "
369
+ CXXFLAGS=" -target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET "
370
+
371
+ # Having IPHONEOS_DEPLOYMENT_TARGET in the environment causes problems
372
+ # with some cross-building toolchains, because it introduces implicit
373
+ # behavior into clang.
374
+ unset IPHONEOS_DEPLOYMENT_TARGET
375
+
376
+ # Now that we know CC etc., we can create a meson cross-configuration file
377
+ create_meson_cross_config
378
+ fi
248
379
fi
249
380
250
381
wrap_wheel_builder build
0 commit comments