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