From e8e8db985a1cfa550a41f9a92f2d204da967297a Mon Sep 17 00:00:00 2001 From: James Zern Date: Mon, 30 Nov 2020 11:03:59 -0800 Subject: [PATCH 1/2] add xcframeworkbuild.sh this is similar to iosbuild.sh, but will create .xcframework variants to support Catalyst targets. currently it includes libs for: ios-arm64_armv7_armv7s ios-arm64_x86_64-maccatalyst ios-i386_x86_64-simulator macos-arm64_x86_64 this script requires Xcode 12+ to target arm64 for mac/catalyst, Xcode 11 builds will create x86_64 libraries only. iosbuild.sh remains for compatibility purposes Change-Id: I289c54c4b85848392a99bea698d45d54a9781f49 --- .gitignore | 4 +- xcframeworkbuild.sh | 221 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100755 xcframeworkbuild.sh diff --git a/.gitignore b/.gitignore index a4bbd7b4..f74e51d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.l[ao] *.[ao] *.pc +.DS_Store .deps .libs /aclocal.m4 @@ -33,7 +34,8 @@ src/webp/stamp-h1 *.idb *.pdb /iosbuild -/WebP.framework +/xcframeworkbuild +/WebP*.*framework CMakeCache.txt CMakeFiles/ cmake_install.cmake diff --git a/xcframeworkbuild.sh b/xcframeworkbuild.sh new file mode 100755 index 00000000..70770e7e --- /dev/null +++ b/xcframeworkbuild.sh @@ -0,0 +1,221 @@ +#!/bin/bash +# +# This script generates 'WebP.xcframework', 'WebPDecoder.xcframework', +# 'WebPDemux.xcframework' and 'WebPMux.xcframework'. +# An iOS, Mac or Mac Catalyst app can decode WebP images by including +# 'WebPDecoder.xcframework' and both encode and decode WebP images by including +# 'WebP.xcframework'. +# +# Run ./xcframeworkbuild.sh to generate the frameworks under the current +# directory (the previous build will be erased if it exists). +# + +set -e + +# Extract Xcode version. +readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2) +if [[ -z "${XCODE}" ]] || [[ "${XCODE%%.*}" -lt 11 ]]; then + echo "Xcode 11.0 or higher is required!" + exit 1 +fi + +# Extract the latest SDK version from the final field of the form: iphoneosX.Y +# / macosxX.Y +readonly SDK=($( + xcodebuild -showsdks \ + | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' + xcodebuild -showsdks \ + | grep macosx | sort | tail -n 1 | awk '{print substr($NF, 7)}' +)) +readonly IOS=0 +readonly MACOS=1 +readonly IOS_SIMULATOR=2 +readonly MACOS_CATALYST=3 +readonly NUM_PLATFORMS=4 + +readonly OLDPATH=${PATH} + +# Names should be of the form '-[-]'. +PLATFORMS[$IOS]="iPhoneOS-armv7 iPhoneOS-armv7s iPhoneOS-arm64" +PLATFORMS[$IOS_SIMULATOR]="iPhoneSimulator-i386 iPhoneSimulator-x86_64" +PLATFORMS[$MACOS]="MacOSX-x86_64" +PLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64" +if [[ "${XCODE%%.*}" -ge 12 ]]; then + PLATFORMS[$MACOS]+=" MacOSX-arm64" + PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64" +elif [[ "${XCODE%%.*}" -eq 11 ]]; then + cat << EOF +WARNING: Xcode 12.0 or higher is required to build targets for +WARNING: Apple Silicon (arm64). The XCFrameworks generated with Xcode 11 will +WARNING: contain libraries for MacOS & Catalyst supporting x86_64 only. +WARNING: The build will continue in 5 seconds... +EOF + sleep 5 +else + echo "Xcode 11.0 or higher is required!" + exit 1 +fi +readonly PLATFORMS +readonly SRCDIR=$(dirname $0) +readonly TOPDIR=$(pwd) +readonly BUILDDIR="${TOPDIR}/xcframeworkbuild" +readonly TARGETDIR="${TOPDIR}/WebP.xcframework" +readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework" +readonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework" +readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework" +readonly DEVELOPER=$(xcode-select --print-path) +readonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain" +readonly PLATFORMSROOT="${DEVELOPER}/Platforms" +readonly LIPO=$(xcrun -sdk iphoneos${SDK[$IOS]} -find lipo) + +if [[ -z "${SDK[$IOS]}" ]] || [[ ${SDK[$IOS]%%.*} -lt 8 ]]; then + echo "iOS SDK version 8.0 or higher is required!" + exit 1 +fi + +echo "Xcode Version: ${XCODE}" +echo "iOS SDK Version: ${SDK[$IOS]}" +echo "MacOS SDK Version: ${SDK[$MACOS]}" + +if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \ + || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then + cat << EOF +WARNING: The following directories will be deleted: +WARNING: ${BUILDDIR} +WARNING: ${TARGETDIR} +WARNING: ${DECTARGETDIR} +WARNING: ${MUXTARGETDIR} +WARNING: ${DEMUXTARGETDIR} +WARNING: The build will continue in 5 seconds... +EOF + sleep 5 +fi +rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ + ${MUXTARGETDIR} ${DEMUXTARGETDIR} + +if [[ ! -e ${SRCDIR}/configure ]]; then + if ! (cd ${SRCDIR} && sh autogen.sh); then + cat << EOF +Error creating configure script! +This script requires the autoconf/automake and libtool to build. MacPorts or +Homebrew can be used to obtain these: +http://www.macports.org/install.php +https://brew.sh/ +EOF + exit 1 + fi +fi + +for (( i = 0; i < $NUM_PLATFORMS; ++i )); do + LIBLIST=() + DECLIBLIST=() + MUXLIBLIST=() + DEMUXLIBLIST=() + + for PLATFORM in ${PLATFORMS[$i]}; do + ROOTDIR="${BUILDDIR}/${PLATFORM}" + mkdir -p "${ROOTDIR}" + + ARCH="${PLATFORM##*-}" + case "${PLATFORM}" in + iPhone*) + sdk="${SDK[$IOS]}" + ;; + MacOS*) + sdk="${SDK[$MACOS]}" + ;; + *) + echo "Unrecognized platform: ${PLATFORM}!" + exit 1 + ;; + esac + + SDKROOT="${PLATFORMSROOT}/${PLATFORM%%-*}.platform/" + SDKROOT+="Developer/SDKs/${PLATFORM%%-*}${sdk}.sdk/" + CFLAGS="-pipe -isysroot ${SDKROOT} -O3 -DNDEBUG" + case "${PLATFORM}" in + iPhone*) + CFLAGS+=" -miphoneos-version-min=6.0 -fembed-bitcode" + ;; + MacOSX-Catalyst*) + CFLAGS+=" -target ${ARCH}-apple-ios13.0-macabi" + ;; + esac + + set -x + export PATH="${DEVROOT}/usr/bin:${OLDPATH}" + ${SRCDIR}/configure --host=${ARCH/arm64/aarch64}-apple-darwin \ + --build=$(${SRCDIR}/config.guess) \ + --prefix=${ROOTDIR} \ + --disable-shared --enable-static \ + --enable-libwebpdecoder --enable-swap-16bit-csp \ + --enable-libwebpmux \ + CC="clang -arch ${ARCH}" \ + CFLAGS="${CFLAGS}" + set +x + + # run make only in the src/ directory to create libwebp.a/libwebpdecoder.a + cd src/ + make V=0 + make install + + LIBLIST+=("${ROOTDIR}/lib/libwebp.a") + DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a") + MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a") + DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a") + # xcodebuild requires a directory for the -headers option, these will match + # for all builds. + make install-data DESTDIR="${ROOTDIR}/lib-headers" + make install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers" + make -C demux install-data DESTDIR="${ROOTDIR}/demux-headers" + make -C mux install-data DESTDIR="${ROOTDIR}/mux-headers" + LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp" + DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp" + DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp" + MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp" + + make distclean + cd .. + + export PATH=${OLDPATH} + done + + [[ -z "${LIBLIST[@]}" ]] && continue + + # Create a temporary target directory for each [-]. + target_dir="${BUILDDIR}/${PLATFORMS[$i]}" + target_dir="${target_dir%% *}" + target_dir="${target_dir%-*}" + target_lib="${target_dir}/$(basename ${LIBLIST[0]})" + target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})" + target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})" + target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})" + + mkdir -p "${target_dir}" + ${LIPO} -create ${LIBLIST[@]} -output "${target_lib}" + ${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}" + ${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}" + ${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}" + FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}") + FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}") + FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}") + FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}") +done + +# lipo will not put archives with the same architecture (e.g., x86_64 +# iPhoneSimulator & MacOS) in the same fat output file. xcodebuild +# -create-xcframework requires universal archives to avoid e.g.: +# Both ios-x86_64-maccatalyst and ios-arm64-maccatalyst represent two +# equivalent library definitions +set -x +xcodebuild -create-xcframework "${FAT_LIBLIST[@]}" \ + -output ${TARGETDIR} +xcodebuild -create-xcframework "${FAT_DECLIBLIST[@]}" \ + -output ${DECTARGETDIR} +xcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \ + -output ${DEMUXTARGETDIR} +xcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \ + -output ${MUXTARGETDIR} +set +x + +echo "SUCCESS" From 319f56f1a1614c3ec142263ee02ef00782b8d740 Mon Sep 17 00:00:00 2001 From: James Zern Date: Tue, 8 Dec 2020 18:30:54 -0800 Subject: [PATCH 2/2] iosbuild.sh: sync some aspects of xcframeworkbuild.sh Change-Id: Ie29f986767132fe980d71e43f6b8d367a9e2e6a9 --- iosbuild.sh | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/iosbuild.sh b/iosbuild.sh index e4031de0..044745f0 100755 --- a/iosbuild.sh +++ b/iosbuild.sh @@ -1,8 +1,9 @@ #!/bin/bash # -# This script generates 'WebP.framework' and 'WebPDecoder.framework'. An iOS -# app can decode WebP images by including 'WebPDecoder.framework' and both -# encode and decode WebP images by including 'WebP.framework'. +# This script generates 'WebP.framework' and 'WebPDecoder.framework', +# 'WebPDemux.framework' and 'WebPMux.framework'. +# An iOS app can decode WebP images by including 'WebPDecoder.framework' and +# both encode and decode WebP images by including 'WebP.framework'. # # Run ./iosbuild.sh to generate the frameworks under the current directory # (the previous build will be erased if it exists). @@ -50,13 +51,27 @@ if [[ -z "${SDK}" ]]; then exit 1 elif [[ ${SDK%%.*} -gt 8 ]]; then EXTRA_CFLAGS="-fembed-bitcode" -elif [[ ${SDK} < 6.0 ]]; then +elif [[ ${SDK%%.*} -le 6 ]]; then echo "You need iOS SDK version 6.0 or above" exit 1 -else - echo "iOS SDK Version ${SDK}" fi +echo "Xcode Version: ${XCODE}" +echo "iOS SDK Version: ${SDK}" + +if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \ + || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" ]]; then + cat << EOF +WARNING: The following directories will be deleted: +WARNING: ${BUILDDIR} +WARNING: ${TARGETDIR} +WARNING: ${DECTARGETDIR} +WARNING: ${MUXTARGETDIR} +WARNING: ${DEMUXTARGETDIR} +WARNING: The build will continue in 5 seconds... +EOF + sleep 5 +fi rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ ${MUXTARGETDIR} ${DEMUXTARGETDIR} mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \ @@ -64,12 +79,12 @@ mkdir -p ${BUILDDIR} ${TARGETDIR}/Headers/ ${DECTARGETDIR}/Headers/ \ if [[ ! -e ${SRCDIR}/configure ]]; then if ! (cd ${SRCDIR} && sh autogen.sh); then - cat <