1*b2055c35SXin Li#!/bin/bash 2*b2055c35SXin Li# 3*b2055c35SXin Li# This script generates 'WebP.xcframework', 'WebPDecoder.xcframework', 4*b2055c35SXin Li# 'WebPDemux.xcframework' and 'WebPMux.xcframework'. 5*b2055c35SXin Li# An iOS, Mac or Mac Catalyst app can decode WebP images by including 6*b2055c35SXin Li# 'WebPDecoder.xcframework' and both encode and decode WebP images by including 7*b2055c35SXin Li# 'WebP.xcframework'. 8*b2055c35SXin Li# 9*b2055c35SXin Li# Run ./xcframeworkbuild.sh to generate the frameworks under the current 10*b2055c35SXin Li# directory (the previous build will be erased if it exists). 11*b2055c35SXin Li# 12*b2055c35SXin Li 13*b2055c35SXin Liset -e 14*b2055c35SXin Li 15*b2055c35SXin Li# Set these variables based on the desired minimum deployment target. 16*b2055c35SXin Lireadonly IOS_MIN_VERSION=6.0 17*b2055c35SXin Lireadonly MACOSX_MIN_VERSION=10.15 18*b2055c35SXin Lireadonly MACOSX_CATALYST_MIN_VERSION=14.0 19*b2055c35SXin Li 20*b2055c35SXin Li# Extract Xcode version. 21*b2055c35SXin Lireadonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2) 22*b2055c35SXin Liif [[ -z "${XCODE}" ]] || [[ "${XCODE%%.*}" -lt 11 ]]; then 23*b2055c35SXin Li echo "Xcode 11.0 or higher is required!" 24*b2055c35SXin Li exit 1 25*b2055c35SXin Lifi 26*b2055c35SXin Li 27*b2055c35SXin Li# Extract the latest SDK version from the final field of the form: iphoneosX.Y 28*b2055c35SXin Li# / macosxX.Y 29*b2055c35SXin Lireadonly SDK=($( 30*b2055c35SXin Li xcodebuild -showsdks \ 31*b2055c35SXin Li | grep iphoneos | sort | tail -n 1 | awk '{print substr($NF, 9)}' 32*b2055c35SXin Li xcodebuild -showsdks \ 33*b2055c35SXin Li | grep macosx | sort | tail -n 1 | awk '{print substr($NF, 7)}' 34*b2055c35SXin Li)) 35*b2055c35SXin Lireadonly IOS=0 36*b2055c35SXin Lireadonly MACOS=1 37*b2055c35SXin Lireadonly IOS_SIMULATOR=2 38*b2055c35SXin Lireadonly MACOS_CATALYST=3 39*b2055c35SXin Lireadonly NUM_PLATFORMS=4 40*b2055c35SXin Li 41*b2055c35SXin Lireadonly OLDPATH=${PATH} 42*b2055c35SXin Li 43*b2055c35SXin Li# Names should be of the form '<platform>-[<variant>-]<architecture>'. 44*b2055c35SXin LiPLATFORMS[$IOS]="iPhoneOS-armv7 iPhoneOS-armv7s iPhoneOS-arm64" 45*b2055c35SXin LiPLATFORMS[$IOS_SIMULATOR]="iPhoneSimulator-i386 iPhoneSimulator-x86_64" 46*b2055c35SXin LiPLATFORMS[$MACOS]="MacOSX-x86_64" 47*b2055c35SXin LiPLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64" 48*b2055c35SXin Liif [[ "${XCODE%%.*}" -ge 12 ]]; then 49*b2055c35SXin Li PLATFORMS[$MACOS]+=" MacOSX-arm64" 50*b2055c35SXin Li PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64" 51*b2055c35SXin Li PLATFORMS[$IOS_SIMULATOR]+=" iPhoneSimulator-arm64" 52*b2055c35SXin Lielif [[ "${XCODE%%.*}" -eq 11 ]]; then 53*b2055c35SXin Li cat << EOF 54*b2055c35SXin LiWARNING: Xcode 12.0 or higher is required to build targets for 55*b2055c35SXin LiWARNING: Apple Silicon (arm64). The XCFrameworks generated with Xcode 11 will 56*b2055c35SXin LiWARNING: contain libraries for MacOS & Catalyst supporting x86_64 only. 57*b2055c35SXin LiWARNING: The build will continue in 5 seconds... 58*b2055c35SXin LiEOF 59*b2055c35SXin Li sleep 5 60*b2055c35SXin Lielse 61*b2055c35SXin Li echo "Xcode 11.0 or higher is required!" 62*b2055c35SXin Li exit 1 63*b2055c35SXin Lifi 64*b2055c35SXin Lireadonly PLATFORMS 65*b2055c35SXin Lireadonly SRCDIR=$(dirname $0) 66*b2055c35SXin Lireadonly TOPDIR=$(pwd) 67*b2055c35SXin Lireadonly BUILDDIR="${TOPDIR}/xcframeworkbuild" 68*b2055c35SXin Lireadonly TARGETDIR="${TOPDIR}/WebP.xcframework" 69*b2055c35SXin Lireadonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework" 70*b2055c35SXin Lireadonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework" 71*b2055c35SXin Lireadonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework" 72*b2055c35SXin Lireadonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.xcframework" 73*b2055c35SXin Lireadonly DEVELOPER=$(xcode-select --print-path) 74*b2055c35SXin Lireadonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain" 75*b2055c35SXin Lireadonly PLATFORMSROOT="${DEVELOPER}/Platforms" 76*b2055c35SXin Lireadonly LIPO=$(xcrun -sdk iphoneos${SDK[$IOS]} -find lipo) 77*b2055c35SXin Li 78*b2055c35SXin Liif [[ -z "${SDK[$IOS]}" ]] || [[ ${SDK[$IOS]%%.*} -lt 8 ]]; then 79*b2055c35SXin Li echo "iOS SDK version 8.0 or higher is required!" 80*b2055c35SXin Li exit 1 81*b2055c35SXin Lifi 82*b2055c35SXin Li 83*b2055c35SXin Li####################################### 84*b2055c35SXin Li# Moves Headers/*.h to Headers/<framework>/ 85*b2055c35SXin Li# 86*b2055c35SXin Li# Places framework headers in a subdirectory to avoid Xcode errors when using 87*b2055c35SXin Li# multiple frameworks: 88*b2055c35SXin Li# error: Multiple commands produce 89*b2055c35SXin Li# '.../Build/Products/Debug-iphoneos/include/types.h' 90*b2055c35SXin Li# Arguments: 91*b2055c35SXin Li# $1 - path to framework 92*b2055c35SXin Li####################################### 93*b2055c35SXin Liupdate_headers_path() { 94*b2055c35SXin Li local framework_name="$(basename ${1%.xcframework})" 95*b2055c35SXin Li local subdir 96*b2055c35SXin Li for d in $(find "$1" -path "*/Headers"); do 97*b2055c35SXin Li subdir="$d/$framework_name" 98*b2055c35SXin Li if [[ -d "$subdir" ]]; then 99*b2055c35SXin Li # SharpYuv will have a sharpyuv subdirectory. macOS is case insensitive, 100*b2055c35SXin Li # but for consistency with the other frameworks, rename the directory to 101*b2055c35SXin Li # match the case of the framework name. 102*b2055c35SXin Li mv "$(echo ${subdir} | tr 'A-Z' 'a-z')" "$subdir" 103*b2055c35SXin Li else 104*b2055c35SXin Li mkdir "$subdir" 105*b2055c35SXin Li mv "$d/"*.h "$subdir" 106*b2055c35SXin Li fi 107*b2055c35SXin Li done 108*b2055c35SXin Li} 109*b2055c35SXin Li 110*b2055c35SXin Liecho "Xcode Version: ${XCODE}" 111*b2055c35SXin Liecho "iOS SDK Version: ${SDK[$IOS]}" 112*b2055c35SXin Liecho "MacOS SDK Version: ${SDK[$MACOS]}" 113*b2055c35SXin Li 114*b2055c35SXin Liif [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \ 115*b2055c35SXin Li || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \ 116*b2055c35SXin Li || -e "${SHARPYUVTARGETDIR}" ]]; then 117*b2055c35SXin Li cat << EOF 118*b2055c35SXin LiWARNING: The following directories will be deleted: 119*b2055c35SXin LiWARNING: ${BUILDDIR} 120*b2055c35SXin LiWARNING: ${TARGETDIR} 121*b2055c35SXin LiWARNING: ${DECTARGETDIR} 122*b2055c35SXin LiWARNING: ${MUXTARGETDIR} 123*b2055c35SXin LiWARNING: ${DEMUXTARGETDIR} 124*b2055c35SXin LiWARNING: ${SHARPYUVTARGETDIR} 125*b2055c35SXin LiWARNING: The build will continue in 5 seconds... 126*b2055c35SXin LiEOF 127*b2055c35SXin Li sleep 5 128*b2055c35SXin Lifi 129*b2055c35SXin Lirm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \ 130*b2055c35SXin Li ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR} 131*b2055c35SXin Li 132*b2055c35SXin Liif [[ ! -e ${SRCDIR}/configure ]]; then 133*b2055c35SXin Li if ! (cd ${SRCDIR} && sh autogen.sh); then 134*b2055c35SXin Li cat << EOF 135*b2055c35SXin LiError creating configure script! 136*b2055c35SXin LiThis script requires the autoconf/automake and libtool to build. MacPorts or 137*b2055c35SXin LiHomebrew can be used to obtain these: 138*b2055c35SXin Lihttps://www.macports.org/install.php 139*b2055c35SXin Lihttps://brew.sh/ 140*b2055c35SXin LiEOF 141*b2055c35SXin Li exit 1 142*b2055c35SXin Li fi 143*b2055c35SXin Lifi 144*b2055c35SXin Li 145*b2055c35SXin Lifor (( i = 0; i < $NUM_PLATFORMS; ++i )); do 146*b2055c35SXin Li LIBLIST=() 147*b2055c35SXin Li DECLIBLIST=() 148*b2055c35SXin Li MUXLIBLIST=() 149*b2055c35SXin Li DEMUXLIBLIST=() 150*b2055c35SXin Li SHARPYUVLIBLIST=() 151*b2055c35SXin Li 152*b2055c35SXin Li for PLATFORM in ${PLATFORMS[$i]}; do 153*b2055c35SXin Li ROOTDIR="${BUILDDIR}/${PLATFORM}" 154*b2055c35SXin Li mkdir -p "${ROOTDIR}" 155*b2055c35SXin Li 156*b2055c35SXin Li ARCH="${PLATFORM##*-}" 157*b2055c35SXin Li case "${PLATFORM}" in 158*b2055c35SXin Li iPhone*) 159*b2055c35SXin Li sdk="${SDK[$IOS]}" 160*b2055c35SXin Li ;; 161*b2055c35SXin Li MacOS*) 162*b2055c35SXin Li sdk="${SDK[$MACOS]}" 163*b2055c35SXin Li ;; 164*b2055c35SXin Li *) 165*b2055c35SXin Li echo "Unrecognized platform: ${PLATFORM}!" 166*b2055c35SXin Li exit 1 167*b2055c35SXin Li ;; 168*b2055c35SXin Li esac 169*b2055c35SXin Li 170*b2055c35SXin Li SDKROOT="${PLATFORMSROOT}/${PLATFORM%%-*}.platform/" 171*b2055c35SXin Li SDKROOT+="Developer/SDKs/${PLATFORM%%-*}${sdk}.sdk/" 172*b2055c35SXin Li CFLAGS="-pipe -isysroot ${SDKROOT} -O3 -DNDEBUG" 173*b2055c35SXin Li case "${PLATFORM}" in 174*b2055c35SXin Li iPhone*) 175*b2055c35SXin Li CFLAGS+=" -fembed-bitcode" 176*b2055c35SXin Li CFLAGS+=" -target ${ARCH}-apple-ios${IOS_MIN_VERSION}" 177*b2055c35SXin Li [[ "${PLATFORM}" == *Simulator* ]] && CFLAGS+="-simulator" 178*b2055c35SXin Li ;; 179*b2055c35SXin Li MacOSX-Catalyst*) 180*b2055c35SXin Li CFLAGS+=" -target" 181*b2055c35SXin Li CFLAGS+=" ${ARCH}-apple-ios${MACOSX_CATALYST_MIN_VERSION}-macabi" 182*b2055c35SXin Li ;; 183*b2055c35SXin Li MacOSX*) 184*b2055c35SXin Li CFLAGS+=" -mmacosx-version-min=${MACOSX_MIN_VERSION}" 185*b2055c35SXin Li ;; 186*b2055c35SXin Li esac 187*b2055c35SXin Li 188*b2055c35SXin Li set -x 189*b2055c35SXin Li export PATH="${DEVROOT}/usr/bin:${OLDPATH}" 190*b2055c35SXin Li ${SRCDIR}/configure --host=${ARCH/arm64/aarch64}-apple-darwin \ 191*b2055c35SXin Li --build=$(${SRCDIR}/config.guess) \ 192*b2055c35SXin Li --prefix=${ROOTDIR} \ 193*b2055c35SXin Li --disable-shared --enable-static \ 194*b2055c35SXin Li --enable-libwebpdecoder --enable-swap-16bit-csp \ 195*b2055c35SXin Li --enable-libwebpmux \ 196*b2055c35SXin Li CC="clang -arch ${ARCH}" \ 197*b2055c35SXin Li CFLAGS="${CFLAGS}" 198*b2055c35SXin Li set +x 199*b2055c35SXin Li 200*b2055c35SXin Li # Build only the libraries, skip the examples. 201*b2055c35SXin Li make V=0 -C sharpyuv install 202*b2055c35SXin Li make V=0 -C src install 203*b2055c35SXin Li 204*b2055c35SXin Li LIBLIST+=("${ROOTDIR}/lib/libwebp.a") 205*b2055c35SXin Li DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a") 206*b2055c35SXin Li MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a") 207*b2055c35SXin Li DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a") 208*b2055c35SXin Li SHARPYUVLIBLIST+=("${ROOTDIR}/lib/libsharpyuv.a") 209*b2055c35SXin Li # xcodebuild requires a directory for the -headers option, these will match 210*b2055c35SXin Li # for all builds. 211*b2055c35SXin Li make -C src install-data DESTDIR="${ROOTDIR}/lib-headers" 212*b2055c35SXin Li make -C src install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers" 213*b2055c35SXin Li make -C src/demux install-data DESTDIR="${ROOTDIR}/demux-headers" 214*b2055c35SXin Li make -C src/mux install-data DESTDIR="${ROOTDIR}/mux-headers" 215*b2055c35SXin Li make -C sharpyuv install-data DESTDIR="${ROOTDIR}/sharpyuv-headers" 216*b2055c35SXin Li LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp" 217*b2055c35SXin Li DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp" 218*b2055c35SXin Li DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp" 219*b2055c35SXin Li MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp" 220*b2055c35SXin Li SHARPYUV_HEADERS="${ROOTDIR}/sharpyuv-headers/${ROOTDIR}/include/webp" 221*b2055c35SXin Li 222*b2055c35SXin Li make distclean 223*b2055c35SXin Li 224*b2055c35SXin Li export PATH=${OLDPATH} 225*b2055c35SXin Li done 226*b2055c35SXin Li 227*b2055c35SXin Li [[ -z "${LIBLIST[@]}" ]] && continue 228*b2055c35SXin Li 229*b2055c35SXin Li # Create a temporary target directory for each <platform>[-<variant>]. 230*b2055c35SXin Li target_dir="${BUILDDIR}/${PLATFORMS[$i]}" 231*b2055c35SXin Li target_dir="${target_dir%% *}" 232*b2055c35SXin Li target_dir="${target_dir%-*}" 233*b2055c35SXin Li target_lib="${target_dir}/$(basename ${LIBLIST[0]})" 234*b2055c35SXin Li target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})" 235*b2055c35SXin Li target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})" 236*b2055c35SXin Li target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})" 237*b2055c35SXin Li target_sharpyuvlib="${target_dir}/$(basename ${SHARPYUVLIBLIST[0]})" 238*b2055c35SXin Li 239*b2055c35SXin Li mkdir -p "${target_dir}" 240*b2055c35SXin Li ${LIPO} -create ${LIBLIST[@]} -output "${target_lib}" 241*b2055c35SXin Li ${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}" 242*b2055c35SXin Li ${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}" 243*b2055c35SXin Li ${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}" 244*b2055c35SXin Li ${LIPO} -create ${SHARPYUVLIBLIST[@]} -output "${target_sharpyuvlib}" 245*b2055c35SXin Li FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}") 246*b2055c35SXin Li FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}") 247*b2055c35SXin Li FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}") 248*b2055c35SXin Li FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}") 249*b2055c35SXin Li FAT_SHARPYUVLIBLIST+=(-library "${target_sharpyuvlib}") 250*b2055c35SXin Li FAT_SHARPYUVLIBLIST+=(-headers "${SHARPYUV_HEADERS}") 251*b2055c35SXin Lidone 252*b2055c35SXin Li 253*b2055c35SXin Li# lipo will not put archives with the same architecture (e.g., x86_64 254*b2055c35SXin Li# iPhoneSimulator & MacOS) in the same fat output file. xcodebuild 255*b2055c35SXin Li# -create-xcframework requires universal archives to avoid e.g.: 256*b2055c35SXin Li# Both ios-x86_64-maccatalyst and ios-arm64-maccatalyst represent two 257*b2055c35SXin Li# equivalent library definitions 258*b2055c35SXin Liset -x 259*b2055c35SXin Lixcodebuild -create-xcframework "${FAT_LIBLIST[@]}" \ 260*b2055c35SXin Li -output ${TARGETDIR} 261*b2055c35SXin Lixcodebuild -create-xcframework "${FAT_DECLIBLIST[@]}" \ 262*b2055c35SXin Li -output ${DECTARGETDIR} 263*b2055c35SXin Lixcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \ 264*b2055c35SXin Li -output ${DEMUXTARGETDIR} 265*b2055c35SXin Lixcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \ 266*b2055c35SXin Li -output ${MUXTARGETDIR} 267*b2055c35SXin Lixcodebuild -create-xcframework "${FAT_SHARPYUVLIBLIST[@]}" \ 268*b2055c35SXin Li -output ${SHARPYUVTARGETDIR} 269*b2055c35SXin Liupdate_headers_path "${TARGETDIR}" 270*b2055c35SXin Liupdate_headers_path "${DECTARGETDIR}" 271*b2055c35SXin Liupdate_headers_path "${DEMUXTARGETDIR}" 272*b2055c35SXin Liupdate_headers_path "${MUXTARGETDIR}" 273*b2055c35SXin Liupdate_headers_path "${SHARPYUVTARGETDIR}" 274*b2055c35SXin Liset +x 275*b2055c35SXin Li 276*b2055c35SXin Liecho "SUCCESS" 277