11#! /bin/bash
22
3- # Setup that needs to be done before multibuild utils are invoked
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).
6+ if [[ -z " $CIBW_ARCHS " ]]; then
7+ echo " ERROR: Pillow builds require CIBW_ARCHS be defined."
8+ exit 1
9+ fi
10+ if [[ " $CIBW_ARCHS " == * " " * ]]; then
11+ echo " ERROR: Pillow builds only support a single architecture in CIBW_ARCHS."
12+ exit 1
13+ fi
14+
15+ # Setup that needs to be done before multibuild utils are invoked. Process
16+ # potential cross-build platforms before native platforms to ensure that we pick
17+ # up the cross environment.
418PROJECTDIR=$( 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).
9- if [[ -z " $CIBW_ARCHS " ]]; then
10- echo " ERROR: Pillow macOS builds require CIBW_ARCHS be defined."
11- exit 1
19+ if [[ " $CIBW_PLATFORM " == " ios" ]]; then
20+ # On iOS, CIBW_ARCHS is actually a multi-arch - arm64_iphoneos,
21+ # arm64_iphonesimulator or x86_64_iphonesimulator. Split into the CPU
22+ # platform, and the iOS SDK.
23+ PLAT=$( echo $CIBW_ARCHS | sed " s/\(.*\)_\(.*\)/\1/" )
24+ IOS_SDK=$( echo $CIBW_ARCHS | sed " s/\(.*\)_\(.*\)/\2/" )
25+
26+ # Build iOS builds in `build/iphoneos` or `build/iphonesimulator/`
27+ # (depending on the build target). Install them into `build/deps/iphoneos`
28+ # or `build/deps/iphonesimulator`
29+ WORKDIR=$( pwd) /build/$IOS_SDK
30+ BUILD_PREFIX=$( pwd) /build/deps/$IOS_SDK
31+ PATCH_DIR=$( pwd) /patches/iOS
32+
33+ # GNU tooling insists on using aarch64 rather than arm64
34+ if [[ $PLAT == " arm64" ]]; then
35+ GNU_ARCH=aarch64
36+ else
37+ GNU_ARCH=x86_64
1238 fi
13- if [[ " $CIBW_ARCHS " == * " " * ]]; then
14- echo " ERROR: Pillow macOS builds only support a single architecture in CIBW_ARCHS."
15- exit 1
39+
40+ IOS_SDK_PATH=$( xcrun --sdk $IOS_SDK --show-sdk-path)
41+ if [[ " $IOS_SDK " == " iphonesimulator" ]]; then
42+ CMAKE_SYSTEM_NAME=iOS
43+ IOS_HOST_TRIPLE=$PLAT -apple-ios$IPHONEOS_DEPLOYMENT_TARGET -simulator
44+ else
45+ CMAKE_SYSTEM_NAME=iOS
46+ IOS_HOST_TRIPLE=$PLAT -apple-ios$IPHONEOS_DEPLOYMENT_TARGET
1647 fi
1748
49+ # GNU Autotools doesn't recognize the existence of arm64-apple-ios-simulator
50+ # as a valid host. However, the only difference between arm64-apple-ios and
51+ # arm64-apple-ios-simulator is the choice of sysroot, and that is
52+ # coordinated by CC,CFLAGS etc. From the perspective of configure, the two
53+ # platforms are identical, so we can use arm64-apple-ios consistently.
54+ # This (mostly) avoids us needing to patch config.sub in dependency sources.
55+ HOST_CONFIGURE_FLAGS=" --disable-shared --enable-static --host=$GNU_ARCH -apple-ios --build=$GNU_ARCH -apple-darwin"
56+
57+ # Cmake has native support for iOS. However, most of that support is based
58+ # on using the Xcode builder, which isn't very helpful for most of Pillow's
59+ # dependencies. Therefore, we lean on the OSX configurations, plus CC/CFLAGS
60+ # etc to ensure the right sysroot is selected.
61+ 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"
62+
63+ # Meson needs to be pointed at a cross-platform configuration file
64+ # This will be generated once CC etc have been evaluated.
65+ HOST_MESON_FLAGS=" --cross-file $WORKDIR /meson-cross.txt -Dprefer_static=true -Ddefault_library=static"
66+
67+ elif [[ " $( uname -s) " == " Darwin" ]]; then
1868 # Build macOS dependencies in `build/darwin`
1969 # Install them into `build/deps/darwin`
70+ PLAT=" ${CIBW_ARCHS:- $AUDITWHEEL_ARCH } "
2071 WORKDIR=$( pwd) /build/darwin
2172 BUILD_PREFIX=$( pwd) /build/deps/darwin
2273else
2374 # Build prefix will default to /usr/local
75+ PLAT=" ${CIBW_ARCHS:- $AUDITWHEEL_ARCH } "
2476 WORKDIR=$( pwd) /build
2577 MB_ML_LIBC=${AUDITWHEEL_POLICY:: 9}
2678 MB_ML_VER=${AUDITWHEEL_POLICY: 9}
2779fi
28- PLAT=" ${CIBW_ARCHS:- $AUDITWHEEL_ARCH } "
2980
3081# Define custom utilities
3182source wheels/multibuild/common_utils.sh
3687
3788ARCHIVE_SDIR=pillow-depends-main
3889
39- # Package versions for fresh source builds
90+ # Package versions for fresh source builds. Version numbers with "Patched"
91+ # annotations have a source code patch that is required for some platforms. If
92+ # you change those versions, ensure the patch is also updated.
4093FREETYPE_VERSION=2.13.3
4194HARFBUZZ_VERSION=11.2.1
4295LIBPNG_VERSION=1.6.49
@@ -47,52 +100,83 @@ TIFF_VERSION=4.7.0
47100LCMS2_VERSION=2.17
48101ZLIB_VERSION=1.3.1
49102ZLIB_NG_VERSION=2.2.4
50- LIBWEBP_VERSION=1.5.0
103+ LIBWEBP_VERSION=1.5.0 # Patched
51104BZIP2_VERSION=1.0.8
52105LIBXCB_VERSION=1.17.0
53- BROTLI_VERSION=1.1.0
106+ BROTLI_VERSION=1.1.0 # Patched
54107
55108function build_pkg_config {
56109 if [ -e pkg-config-stamp ]; then return ; fi
57- # This essentially duplicates the Homebrew recipe
58- CFLAGS=" $CFLAGS -Wno-int-conversion" build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
110+ # This essentially duplicates the Homebrew recipe.
111+ # On iOS, we need a binary that can be executed on the build machine; but we
112+ # can create a host-specific pc-path to store iOS .pc files. To ensure a
113+ # macOS-compatible build, we temporarily clear environment flags that set
114+ # iOS-specific values.
115+ if [[ -n " $IOS_SDK " ]]; then
116+ ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
117+ ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET
118+ unset HOST_CONFIGURE_FLAGS
119+ unset IPHONEOS_DEPLOYMENT_TARGET
120+ fi
121+
122+ CFLAGS=" $CFLAGS -Wno-int-conversion" CPPFLAGS=" " build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
59123 --disable-debug --disable-host-tool --with-internal-glib \
60124 --with-pc-path=$BUILD_PREFIX /share/pkgconfig:$BUILD_PREFIX /lib/pkgconfig \
61125 --with-system-include-path=$( xcrun --show-sdk-path --sdk macosx) /usr/include
126+
127+ if [[ -n " $IOS_SDK " ]]; then
128+ HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS
129+ IPHONEOS_DEPLOYMENT_TARGET=$ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET
130+ fi ;
131+
62132 export PKG_CONFIG=$BUILD_PREFIX /bin/pkg-config
63133 touch pkg-config-stamp
64134}
65135
66136function build_zlib_ng {
67137 if [ -e zlib-stamp ]; then return ; fi
138+ # zlib-ng uses a "configure" script, but it's not a GNU autotools script, so
139+ # it doesn't honor the usual flags. Temporarily disable any
140+ # cross-compilation flags.
141+ ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
142+ unset HOST_CONFIGURE_FLAGS
143+
68144 build_github zlib-ng/zlib-ng $ZLIB_NG_VERSION --zlib-compat
69145
70- if [ -n " $IS_MACOS " ]; then
146+ HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS
147+
148+ if [ -n " $IS_MACOS " ] && [ -z " $IOS_SDK " ]; then
71149 # Ensure that on macOS, the library name is an absolute path, not an
72150 # @rpath, so that delocate picks up the right library (and doesn't need
73151 # DYLD_LIBRARY_PATH to be set). The default Makefile doesn't have an
74- # option to control the install_name.
152+ # option to control the install_name. This isn't needed on iOS, as iOS
153+ # only builds the static library.
75154 install_name_tool -id $BUILD_PREFIX /lib/libz.1.dylib $BUILD_PREFIX /lib/libz.1.dylib
76155 fi
77156 touch zlib-stamp
78157}
79158
80159function build_brotli {
81160 if [ -e brotli-stamp ]; then return ; fi
161+ local name=brotli
162+ local version=$BROTLI_VERSION
82163 local out_dir=$( fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION .tar.gz brotli-$BROTLI_VERSION .tar.gz)
83164 (cd $out_dir \
84- && cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX /lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX /lib . \
165+ && cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX /lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX /lib $HOST_CMAKE_FLAGS . \
85166 && make install)
86167 touch brotli-stamp
87168}
88169
89170function build_harfbuzz {
90171 if [ -e harfbuzz-stamp ]; then return ; fi
91- python3 -m pip install meson ninja
172+ local name=harfbuzz
173+ local version=$HARFBUZZ_VERSION
174+
175+ python3 -m pip install --disable-pip-version-check meson ninja
92176
93177 local out_dir=$( fetch_unpack https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION /harfbuzz-$HARFBUZZ_VERSION .tar.xz harfbuzz-$HARFBUZZ_VERSION .tar.xz)
94178 (cd $out_dir \
95- && meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX /lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled)
179+ && meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX /lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled $HOST_MESON_FLAGS )
96180 (cd $out_dir /build \
97181 && meson install)
98182 touch harfbuzz-stamp
@@ -110,19 +194,19 @@ function build {
110194 fi
111195
112196 build_simple xcb-proto 1.17.0 https://xorg.freedesktop.org/archive/individual/proto
113- if [ -n " $IS_MACOS " ]; then
197+ if [[ -n " $IS_MACOS " ] ]; then
114198 build_simple xorgproto 2024.1 https://www.x.org/pub/individual/proto
115199 build_simple libXau 1.0.12 https://www.x.org/pub/individual/lib
116200 build_simple libpthread-stubs 0.5 https://xcb.freedesktop.org/dist
117201 else
118- sed s/\$ {pc_sysrootdir\} // $BUILD_PREFIX /share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX /lib/pkgconfig/xcb-proto.pc
202+ sed " s/\$ \ {pc_sysrootdir\}//" $BUILD_PREFIX /share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX /lib/pkgconfig/xcb-proto.pc
119203 fi
120204 build_simple libxcb $LIBXCB_VERSION https://www.x.org/releases/individual/lib
121205
122206 build_libjpeg_turbo
123- if [ -n " $IS_MACOS " ]; then
207+ if [[ -n " $IS_MACOS " ] ]; then
124208 # Custom tiff build to include jpeg; by default, configure won't include
125- # headers/libs in the custom macOS prefix. Explicitly disable webp,
209+ # headers/libs in the custom macOS/iOS prefix. Explicitly disable webp,
126210 # libdeflate and zstd, because on x86_64 macs, it will pick up the
127211 # Homebrew versions of those libraries from /usr/local.
128212 build_simple tiff $TIFF_VERSION https://download.osgeo.org/libtiff tar.gz \
@@ -146,14 +230,44 @@ function build {
146230
147231 build_brotli
148232
149- if [ -n " $IS_MACOS " ]; then
233+ if [[ -n " $IS_MACOS " ] ]; then
150234 # Custom freetype build
151235 build_simple freetype $FREETYPE_VERSION https://download.savannah.gnu.org/releases/freetype tar.gz --with-harfbuzz=no
152236 else
153237 build_freetype
154238 fi
155239
156- build_harfbuzz
240+ if [[ -z " $IOS_SDK " ]]; then
241+ # On iOS, there's no vendor-provided raqm, and we can't ship it due to
242+ # licensing, so there's no point building harfbuzz.
243+ build_harfbuzz
244+ fi
245+ }
246+
247+ function create_meson_cross_config {
248+ cat << EOF > $WORKDIR /meson-cross.txt
249+ [binaries]
250+ pkg-config = '$BUILD_PREFIX /bin/pkg-config'
251+ cmake = '$( which cmake) '
252+ c = '$CC '
253+ cpp = '$CXX '
254+ strip = '$STRIP '
255+
256+ [built-in options]
257+ c_args = '$CFLAGS -I$BUILD_PREFIX /include'
258+ cpp_args = '$CXXFLAGS -I$BUILD_PREFIX /include'
259+ c_link_args = '$CFLAGS -L$BUILD_PREFIX /lib'
260+ cpp_link_args = '$CFLAGS -L$BUILD_PREFIX /lib'
261+
262+ [host_machine]
263+ system = 'darwin'
264+ subsystem = 'ios'
265+ kernel = 'xnu'
266+ cpu_family = '$( uname -m) '
267+ cpu = '$( uname -m) '
268+ endian = 'little'
269+
270+ EOF
157271}
158272
159273# Perform all dependency builds in the build subfolder.
@@ -172,24 +286,40 @@ if [[ ! -d $WORKDIR/pillow-depends-main ]]; then
172286fi
173287
174288if [[ -n " $IS_MACOS " ]]; then
175- # Homebrew (or similar packaging environments) install can contain some of
176- # the libraries that we're going to build. However, they may be compiled
177- # with a MACOSX_DEPLOYMENT_TARGET that doesn't match what we want to use,
178- # and they may bring in other dependencies that we don't want. The same will
179- # be true of any other locations on the path. To avoid conflicts, strip the
180- # path down to the bare minimum (which, on macOS, won't include any
181- # development dependencies).
182- export PATH=" $BUILD_PREFIX /bin:$( dirname $( which python3) ) :/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
183- export CMAKE_PREFIX_PATH=$BUILD_PREFIX
184-
185289 # Ensure the basic structure of the build prefix directory exists.
186290 mkdir -p " $BUILD_PREFIX /bin"
187291 mkdir -p " $BUILD_PREFIX /lib"
188292
189- # Ensure pkg-config is available
293+ # Ensure pkg-config is available. This is done *before* setting CC, CFLAGS
294+ # etc to ensure that the build is *always* a macOS build, even when building
295+ # for iOS.
190296 build_pkg_config
191- # Ensure cmake is available
192- python3 -m pip install cmake
297+
298+ # Ensure cmake is available, and that the default prefix used by CMake is
299+ # the build prefix
300+ python3 -m pip install --disable-pip-version-check cmake
301+ export CMAKE_PREFIX_PATH=$BUILD_PREFIX
302+
303+ if [[ -n " $IOS_SDK " ]]; then
304+ export AR=" $( xcrun --find --sdk $IOS_SDK ar) "
305+ export CPP=" $( xcrun --find --sdk $IOS_SDK clang) -E"
306+ export CC=$( xcrun --find --sdk $IOS_SDK clang)
307+ export CXX=$( xcrun --find --sdk $IOS_SDK clang++)
308+ export LD=$( xcrun --find --sdk $IOS_SDK ld)
309+ export STRIP=$( xcrun --find --sdk $IOS_SDK strip)
310+
311+ CPPFLAGS=" $CPPFLAGS --sysroot=$IOS_SDK_PATH "
312+ CFLAGS=" -target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET "
313+ CXXFLAGS=" -target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET "
314+
315+ # Having IPHONEOS_DEPLOYMENT_TARGET in the environment causes problems
316+ # with some cross-building toolchains, because it introduces implicit
317+ # behavior into clang.
318+ unset IPHONEOS_DEPLOYMENT_TARGET
319+
320+ # Now that we know CC etc, we can create a meson cross-configuration file
321+ create_meson_cross_config
322+ fi
193323fi
194324
195325wrap_wheel_builder build
0 commit comments