Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
3c4b619
Add tooling to support iOS build.
freakboy3742 Feb 17, 2025
59f3557
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 21, 2025
e430bde
Corrections to CI configuration.
freakboy3742 Jun 21, 2025
f428222
Apply suggestions from code review
freakboy3742 Jun 21, 2025
980a9da
Correct regex handling.
freakboy3742 Jun 21, 2025
8c3b4bb
Correct MANIFEST.in
freakboy3742 Jun 21, 2025
cb62e6a
Correct the OS image definitions for iOS CI runs.
freakboy3742 Jun 21, 2025
2cc0cd1
Remove unnecessary manifest entry.
freakboy3742 Jun 22, 2025
fc8ed5c
Only include macOS/iOS SDKs when platform guessing is enabled.
freakboy3742 Jun 22, 2025
19e3b1a
Removed unnecessary code
radarhere Jun 22, 2025
ecadd4c
Simplified code
radarhere Jun 22, 2025
7bd64c4
Do not specify default iPhone deployment target
radarhere Jun 22, 2025
4cc71ec
Apply suggestions from review
freakboy3742 Jun 23, 2025
5cad00f
Modify comment for consistency.
freakboy3742 Jun 23, 2025
ec5e5d0
Merge branch 'main' into ios-build
radarhere Jun 25, 2025
a7afc50
Add notes about removing patches.
freakboy3742 Jun 26, 2025
504223c
Merge branch 'main' into ios-build
radarhere Jun 26, 2025
6ab8e77
Removed Android
radarhere Jun 25, 2025
3524b4e
Updated reason
radarhere Jun 24, 2025
e567602
Updated capitalisation
radarhere Jun 24, 2025
1c2ec9f
Removed duplicate lines
radarhere Jun 24, 2025
d393d09
Simplified code
radarhere Jun 25, 2025
527d18c
Run selftest directly
radarhere Jun 26, 2025
6d2cd76
Minor cleanups, plus run selftest directly rather than through pytest
freakboy3742 Jun 26, 2025
ab9dd5e
Disable libavif on iOS (for now).
freakboy3742 Jun 27, 2025
4a069e0
Save the *whole* file...
freakboy3742 Jun 27, 2025
d7cab29
Add release note about iOS support.
freakboy3742 Jun 27, 2025
14b761a
Tweaks to test flags and module exclusions.
freakboy3742 Jun 27, 2025
ff18509
Moved new iOS wheels to be next to new 3.14 wheels
radarhere Jun 27, 2025
8d8a2c0
Only Python 3.13 iOS wheels are available
radarhere Jun 27, 2025
a4de9db
Use [[ ]]
radarhere Jun 27, 2025
9e07493
Removed extra space
radarhere Jun 27, 2025
ee0ac6c
Removed pyproject.tml from test-sources
radarhere Jun 27, 2025
114ddd6
Apply suggestions from code review
freakboy3742 Jun 27, 2025
1676f71
Merge pull request #6 from radarhere/ios-build
freakboy3742 Jun 27, 2025
fdd3cc7
Merge branch 'main' into ios-build
radarhere Jun 28, 2025
a8251c5
Do not install NumPy twice
radarhere Jun 28, 2025
3efb588
Do not install NumPy on Windows x86
radarhere Jun 28, 2025
7c89190
Merge pull request #7 from radarhere/numpy
freakboy3742 Jun 28, 2025
33d522d
Updated capitalisation
radarhere Jun 30, 2025
a823a0a
Simplified setting PLAT on macOS
radarhere Jun 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 169 additions & 38 deletions .github/workflows/wheels-dependencies.sh
Original file line number Diff line number Diff line change
@@ -1,42 +1,98 @@
#!/bin/bash

# Setup that needs to be done before multibuild utils are invoked
PROJECTDIR=$(pwd)
if [[ "$(uname -s)" == "Darwin" ]]; then
# Safety check - macOS builds require that CIBW_ARCHS is set, and that it
# only contains a single value (even though cibuildwheel allows multiple
# values in CIBW_ARCHS).
# Safety check - Pillow builds require that CIBW_ARCHS is set, and that it only
# contains a single value (even though cibuildwheel allows multiple values in
# CIBW_ARCHS). This check doesn't work on Linux because of how the CIBW_ARCHS
# variable is exposed.
function check_cibw_archs {
if [[ -z "$CIBW_ARCHS" ]]; then
echo "ERROR: Pillow macOS builds require CIBW_ARCHS be defined."
echo "ERROR: Pillow builds require CIBW_ARCHS be defined."
exit 1
fi
if [[ "$CIBW_ARCHS" == *" "* ]]; then
echo "ERROR: Pillow macOS builds only support a single architecture in CIBW_ARCHS."
echo "ERROR: Pillow builds only support a single architecture in CIBW_ARCHS."
exit 1
fi
}

# Setup that needs to be done before multibuild utils are invoked. Process
# potential cross-build platforms before native platforms to ensure that we pick
# up the cross environment.
PROJECTDIR=$(pwd)
if [[ "$CIBW_PLATFORM" == "ios" ]]; then
check_cibw_archs
# On iOS, CIBW_ARCHS is actually a multi-arch - arm64_iphoneos,
# arm64_iphonesimulator or x86_64_iphonesimulator. Split into the CPU
# platform, and the iOS SDK.
PLAT=$(echo $CIBW_ARCHS | sed "s/\(.*\)_\(.*\)/\1/")
IOS_SDK=$(echo $CIBW_ARCHS | sed "s/\(.*\)_\(.*\)/\2/")

# Build iOS builds in `build/iphoneos` or `build/iphonesimulator`
# (depending on the build target). Install them into `build/deps/iphoneos`
# or `build/deps/iphonesimulator`
WORKDIR=$(pwd)/build/$IOS_SDK
BUILD_PREFIX=$(pwd)/build/deps/$IOS_SDK
PATCH_DIR=$(pwd)/patches/iOS

# GNU tooling insists on using aarch64 rather than arm64
if [[ $PLAT == "arm64" ]]; then
GNU_ARCH=aarch64
else
GNU_ARCH=x86_64
fi

IOS_SDK_PATH=$(xcrun --sdk $IOS_SDK --show-sdk-path)
CMAKE_SYSTEM_NAME=iOS
IOS_HOST_TRIPLE=$PLAT-apple-ios$IPHONEOS_DEPLOYMENT_TARGET
if [[ "$IOS_SDK" == "iphonesimulator" ]]; then
IOS_HOST_TRIPLE=$IOS_HOST_TRIPLE-simulator
fi

# GNU Autotools doesn't recognize the existence of arm64-apple-ios-simulator
# as a valid host. However, the only difference between arm64-apple-ios and
# arm64-apple-ios-simulator is the choice of sysroot, and that is
# coordinated by CC, CFLAGS etc. From the perspective of configure, the two
# platforms are identical, so we can use arm64-apple-ios consistently.
# This (mostly) avoids us needing to patch config.sub in dependency sources.
HOST_CONFIGURE_FLAGS="--disable-shared --enable-static --host=$GNU_ARCH-apple-ios --build=$GNU_ARCH-apple-darwin"

# CMake has native support for iOS. However, most of that support is based
# on using the Xcode builder, which isn't very helpful for most of Pillow's
# dependencies. Therefore, we lean on the OSX configurations, plus CC, CFLAGS
# etc. to ensure the right sysroot is selected.
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"

# Meson needs to be pointed at a cross-platform configuration file
# This will be generated once CC etc. have been evaluated.
HOST_MESON_FLAGS="--cross-file $WORKDIR/meson-cross.txt -Dprefer_static=true -Ddefault_library=static"

elif [[ "$(uname -s)" == "Darwin" ]]; then
check_cibw_archs
# Build macOS dependencies in `build/darwin`
# Install them into `build/deps/darwin`
PLAT=$CIBW_ARCHS
WORKDIR=$(pwd)/build/darwin
BUILD_PREFIX=$(pwd)/build/deps/darwin
else
# Build prefix will default to /usr/local
PLAT="${CIBW_ARCHS:-$AUDITWHEEL_ARCH}"
WORKDIR=$(pwd)/build
MB_ML_LIBC=${AUDITWHEEL_POLICY::9}
MB_ML_VER=${AUDITWHEEL_POLICY:9}
fi
PLAT="${CIBW_ARCHS:-$AUDITWHEEL_ARCH}"

# Define custom utilities
source wheels/multibuild/common_utils.sh
source wheels/multibuild/library_builders.sh
if [ -z "$IS_MACOS" ]; then
if [[ -z "$IS_MACOS" ]]; then
source wheels/multibuild/manylinux_utils.sh
fi

ARCHIVE_SDIR=pillow-depends-main

# Package versions for fresh source builds
# Package versions for fresh source builds. Version numbers with "Patched"
# annotations have a source code patch that is required for some platforms. If
# you change those versions, ensure the patch is also updated.
FREETYPE_VERSION=2.13.3
HARFBUZZ_VERSION=11.2.1
LIBPNG_VERSION=1.6.49
Expand All @@ -47,32 +103,58 @@ TIFF_VERSION=4.7.0
LCMS2_VERSION=2.17
ZLIB_VERSION=1.3.1
ZLIB_NG_VERSION=2.2.4
LIBWEBP_VERSION=1.5.0
LIBWEBP_VERSION=1.5.0 # Patched; next release won't need patching. See patch file.
BZIP2_VERSION=1.0.8
LIBXCB_VERSION=1.17.0
BROTLI_VERSION=1.1.0
BROTLI_VERSION=1.1.0 # Patched; next release won't need patching. See patch file.
LIBAVIF_VERSION=1.3.0

function build_pkg_config {
if [ -e pkg-config-stamp ]; then return; fi
# This essentially duplicates the Homebrew recipe
CFLAGS="$CFLAGS -Wno-int-conversion" build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
# This essentially duplicates the Homebrew recipe.
# On iOS, we need a binary that can be executed on the build machine; but we
# can create a host-specific pc-path to store iOS .pc files. To ensure a
# macOS-compatible build, we temporarily clear environment flags that set
# iOS-specific values.
if [[ -n "$IOS_SDK" ]]; then
ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET
unset HOST_CONFIGURE_FLAGS
unset IPHONEOS_DEPLOYMENT_TARGET
fi

CFLAGS="$CFLAGS -Wno-int-conversion" CPPFLAGS="" build_simple pkg-config 0.29.2 https://pkg-config.freedesktop.org/releases tar.gz \
--disable-debug --disable-host-tool --with-internal-glib \
--with-pc-path=$BUILD_PREFIX/share/pkgconfig:$BUILD_PREFIX/lib/pkgconfig \
--with-system-include-path=$(xcrun --show-sdk-path --sdk macosx)/usr/include

if [[ -n "$IOS_SDK" ]]; then
HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS
IPHONEOS_DEPLOYMENT_TARGET=$ORIGINAL_IPHONEOS_DEPLOYMENT_TARGET
fi;

export PKG_CONFIG=$BUILD_PREFIX/bin/pkg-config
touch pkg-config-stamp
}

function build_zlib_ng {
if [ -e zlib-stamp ]; then return; fi
# zlib-ng uses a "configure" script, but it's not a GNU autotools script, so
# it doesn't honor the usual flags. Temporarily disable any
# cross-compilation flags.
ORIGINAL_HOST_CONFIGURE_FLAGS=$HOST_CONFIGURE_FLAGS
unset HOST_CONFIGURE_FLAGS

build_github zlib-ng/zlib-ng $ZLIB_NG_VERSION --zlib-compat

if [ -n "$IS_MACOS" ]; then
HOST_CONFIGURE_FLAGS=$ORIGINAL_HOST_CONFIGURE_FLAGS

if [[ -n "$IS_MACOS" ]] && [[ -z "$IOS_SDK" ]]; then
# Ensure that on macOS, the library name is an absolute path, not an
# @rpath, so that delocate picks up the right library (and doesn't need
# DYLD_LIBRARY_PATH to be set). The default Makefile doesn't have an
# option to control the install_name.
# option to control the install_name. This isn't needed on iOS, as iOS
# only builds the static library.
install_name_tool -id $BUILD_PREFIX/lib/libz.1.dylib $BUILD_PREFIX/lib/libz.1.dylib
fi
touch zlib-stamp
Expand All @@ -82,7 +164,7 @@ function build_brotli {
if [ -e brotli-stamp ]; then return; fi
local out_dir=$(fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz brotli-$BROTLI_VERSION.tar.gz)
(cd $out_dir \
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX/lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX/lib -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib $HOST_CMAKE_FLAGS . \
&& make install)
touch brotli-stamp
}
Expand All @@ -93,7 +175,7 @@ function build_harfbuzz {

local out_dir=$(fetch_unpack https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION/harfbuzz-$HARFBUZZ_VERSION.tar.xz harfbuzz-$HARFBUZZ_VERSION.tar.xz)
(cd $out_dir \
&& meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX/lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled)
&& meson setup build --prefix=$BUILD_PREFIX --libdir=$BUILD_PREFIX/lib --buildtype=minsize -Dfreetype=enabled -Dglib=disabled -Dtests=disabled $HOST_MESON_FLAGS)
(cd $out_dir/build \
&& meson install)
touch harfbuzz-stamp
Expand Down Expand Up @@ -164,19 +246,19 @@ function build {
fi

build_simple xcb-proto 1.17.0 https://xorg.freedesktop.org/archive/individual/proto
if [ -n "$IS_MACOS" ]; then
if [[ -n "$IS_MACOS" ]]; then
build_simple xorgproto 2024.1 https://www.x.org/pub/individual/proto
build_simple libXau 1.0.12 https://www.x.org/pub/individual/lib
build_simple libpthread-stubs 0.5 https://xcb.freedesktop.org/dist
else
sed s/\${pc_sysrootdir\}// $BUILD_PREFIX/share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX/lib/pkgconfig/xcb-proto.pc
sed "s/\${pc_sysrootdir\}//" $BUILD_PREFIX/share/pkgconfig/xcb-proto.pc > $BUILD_PREFIX/lib/pkgconfig/xcb-proto.pc
fi
build_simple libxcb $LIBXCB_VERSION https://www.x.org/releases/individual/lib

build_libjpeg_turbo
if [ -n "$IS_MACOS" ]; then
if [[ -n "$IS_MACOS" ]]; then
# Custom tiff build to include jpeg; by default, configure won't include
# headers/libs in the custom macOS prefix. Explicitly disable webp,
# headers/libs in the custom macOS/iOS prefix. Explicitly disable webp,
# libdeflate and zstd, because on x86_64 macs, it will pick up the
# Homebrew versions of those libraries from /usr/local.
build_simple tiff $TIFF_VERSION https://download.osgeo.org/libtiff tar.gz \
Expand All @@ -186,7 +268,10 @@ function build {
build_tiff
fi

build_libavif
if [[ -z "$IOS_SDK" ]]; then
# Short term workaround; don't build libavif on iOS
build_libavif
fi
build_libpng
build_lcms2
build_openjpeg
Expand All @@ -201,14 +286,44 @@ function build {

build_brotli

if [ -n "$IS_MACOS" ]; then
if [[ -n "$IS_MACOS" ]]; then
# Custom freetype build
build_simple freetype $FREETYPE_VERSION https://download.savannah.gnu.org/releases/freetype tar.gz --with-harfbuzz=no
else
build_freetype
fi

build_harfbuzz
if [[ -z "$IOS_SDK" ]]; then
# On iOS, there's no vendor-provided raqm, and we can't ship it due to
# licensing, so there's no point building harfbuzz.
build_harfbuzz
fi
}

function create_meson_cross_config {
cat << EOF > $WORKDIR/meson-cross.txt
[binaries]
pkg-config = '$BUILD_PREFIX/bin/pkg-config'
cmake = '$(which cmake)'
c = '$CC'
cpp = '$CXX'
strip = '$STRIP'

[built-in options]
c_args = '$CFLAGS -I$BUILD_PREFIX/include'
cpp_args = '$CXXFLAGS -I$BUILD_PREFIX/include'
c_link_args = '$CFLAGS -L$BUILD_PREFIX/lib'
cpp_link_args = '$CFLAGS -L$BUILD_PREFIX/lib'

[host_machine]
system = 'darwin'
subsystem = 'ios'
kernel = 'xnu'
cpu_family = '$(uname -m)'
cpu = '$(uname -m)'
endian = 'little'

EOF
}

# Perform all dependency builds in the build subfolder.
Expand All @@ -227,24 +342,40 @@ if [[ ! -d $WORKDIR/pillow-depends-main ]]; then
fi

if [[ -n "$IS_MACOS" ]]; then
# Homebrew (or similar packaging environments) install can contain some of
# the libraries that we're going to build. However, they may be compiled
# with a MACOSX_DEPLOYMENT_TARGET that doesn't match what we want to use,
# and they may bring in other dependencies that we don't want. The same will
# be true of any other locations on the path. To avoid conflicts, strip the
# path down to the bare minimum (which, on macOS, won't include any
# development dependencies).
export PATH="$BUILD_PREFIX/bin:$(dirname $(which python3)):/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
export CMAKE_PREFIX_PATH=$BUILD_PREFIX

# Ensure the basic structure of the build prefix directory exists.
mkdir -p "$BUILD_PREFIX/bin"
mkdir -p "$BUILD_PREFIX/lib"

# Ensure pkg-config is available
# Ensure pkg-config is available. This is done *before* setting CC, CFLAGS
# etc. to ensure that the build is *always* a macOS build, even when building
# for iOS.
build_pkg_config
# Ensure cmake is available

# Ensure cmake is available, and that the default prefix used by CMake is
# the build prefix
python3 -m pip install cmake
export CMAKE_PREFIX_PATH=$BUILD_PREFIX

if [[ -n "$IOS_SDK" ]]; then
export AR="$(xcrun --find --sdk $IOS_SDK ar)"
export CPP="$(xcrun --find --sdk $IOS_SDK clang) -E"
export CC=$(xcrun --find --sdk $IOS_SDK clang)
export CXX=$(xcrun --find --sdk $IOS_SDK clang++)
export LD=$(xcrun --find --sdk $IOS_SDK ld)
export STRIP=$(xcrun --find --sdk $IOS_SDK strip)

CPPFLAGS="$CPPFLAGS --sysroot=$IOS_SDK_PATH"
CFLAGS="-target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET"
CXXFLAGS="-target $IOS_HOST_TRIPLE --sysroot=$IOS_SDK_PATH -mios-version-min=$IPHONEOS_DEPLOYMENT_TARGET"

# Having IPHONEOS_DEPLOYMENT_TARGET in the environment causes problems
# with some cross-building toolchains, because it introduces implicit
# behavior into clang.
unset IPHONEOS_DEPLOYMENT_TARGET

# Now that we know CC etc., we can create a meson cross-configuration file
create_meson_cross_config
fi
fi

wrap_wheel_builder build
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/wheels-test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@ if (Test-Path $venv\Scripts\pypy.exe) {
$python = "python.exe"
}
& reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\python.exe" /v "GlobalFlag" /t REG_SZ /d "0x02000000" /f
if ("$venv" -like "*\cibw-run-*-win_amd64\*") {
& $venv\Scripts\$python -m pip install numpy
}
cd $pillow
& $venv\Scripts\$python -VV
if (!$?) { exit $LASTEXITCODE }
& $venv\Scripts\$python selftest.py
if (!$?) { exit $LASTEXITCODE }
& $venv\Scripts\$python -m pytest -vv -x Tests\check_wheel.py
& $venv\Scripts\$python -m pytest -vv -x checks\check_wheel.py
if (!$?) { exit $LASTEXITCODE }
& $venv\Scripts\$python -m pytest -vv -x Tests
if (!$?) { exit $LASTEXITCODE }
4 changes: 1 addition & 3 deletions .github/workflows/wheels-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ else
yum install -y fribidi
fi

python3 -m pip install numpy

if [ ! -d "test-images-main" ]; then
curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip
unzip pillow-test-images.zip
Expand All @@ -35,5 +33,5 @@ fi

# Runs tests
python3 selftest.py
python3 -m pytest -vv -x Tests/check_wheel.py
python3 -m pytest -vv -x checks/check_wheel.py
python3 -m pytest -vv -x
Loading
Loading