xref: /aosp_15_r20/external/webp/xcframeworkbuild.sh (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
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
13set -e
14
15# Set these variables based on the desired minimum deployment target.
16readonly IOS_MIN_VERSION=6.0
17readonly MACOSX_MIN_VERSION=10.15
18readonly MACOSX_CATALYST_MIN_VERSION=14.0
19
20# Extract Xcode version.
21readonly XCODE=$(xcodebuild -version | grep Xcode | cut -d " " -f2)
22if [[ -z "${XCODE}" ]] || [[ "${XCODE%%.*}" -lt 11 ]]; then
23  echo "Xcode 11.0 or higher is required!"
24  exit 1
25fi
26
27# Extract the latest SDK version from the final field of the form: iphoneosX.Y
28# / macosxX.Y
29readonly 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))
35readonly IOS=0
36readonly MACOS=1
37readonly IOS_SIMULATOR=2
38readonly MACOS_CATALYST=3
39readonly NUM_PLATFORMS=4
40
41readonly OLDPATH=${PATH}
42
43# Names should be of the form '<platform>-[<variant>-]<architecture>'.
44PLATFORMS[$IOS]="iPhoneOS-armv7 iPhoneOS-armv7s iPhoneOS-arm64"
45PLATFORMS[$IOS_SIMULATOR]="iPhoneSimulator-i386 iPhoneSimulator-x86_64"
46PLATFORMS[$MACOS]="MacOSX-x86_64"
47PLATFORMS[$MACOS_CATALYST]="MacOSX-Catalyst-x86_64"
48if [[ "${XCODE%%.*}" -ge 12 ]]; then
49  PLATFORMS[$MACOS]+=" MacOSX-arm64"
50  PLATFORMS[$MACOS_CATALYST]+=" MacOSX-Catalyst-arm64"
51  PLATFORMS[$IOS_SIMULATOR]+=" iPhoneSimulator-arm64"
52elif [[ "${XCODE%%.*}" -eq 11 ]]; then
53  cat << EOF
54WARNING: Xcode 12.0 or higher is required to build targets for
55WARNING: Apple Silicon (arm64). The XCFrameworks generated with Xcode 11 will
56WARNING: contain libraries for MacOS & Catalyst supporting x86_64 only.
57WARNING: The build will continue in 5 seconds...
58EOF
59  sleep 5
60else
61  echo "Xcode 11.0 or higher is required!"
62  exit 1
63fi
64readonly PLATFORMS
65readonly SRCDIR=$(dirname $0)
66readonly TOPDIR=$(pwd)
67readonly BUILDDIR="${TOPDIR}/xcframeworkbuild"
68readonly TARGETDIR="${TOPDIR}/WebP.xcframework"
69readonly DECTARGETDIR="${TOPDIR}/WebPDecoder.xcframework"
70readonly MUXTARGETDIR="${TOPDIR}/WebPMux.xcframework"
71readonly DEMUXTARGETDIR="${TOPDIR}/WebPDemux.xcframework"
72readonly SHARPYUVTARGETDIR="${TOPDIR}/SharpYuv.xcframework"
73readonly DEVELOPER=$(xcode-select --print-path)
74readonly DEVROOT="${DEVELOPER}/Toolchains/XcodeDefault.xctoolchain"
75readonly PLATFORMSROOT="${DEVELOPER}/Platforms"
76readonly LIPO=$(xcrun -sdk iphoneos${SDK[$IOS]} -find lipo)
77
78if [[ -z "${SDK[$IOS]}" ]] || [[ ${SDK[$IOS]%%.*} -lt 8 ]]; then
79  echo "iOS SDK version 8.0 or higher is required!"
80  exit 1
81fi
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#######################################
93update_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
110echo "Xcode Version: ${XCODE}"
111echo "iOS SDK Version: ${SDK[$IOS]}"
112echo "MacOS SDK Version: ${SDK[$MACOS]}"
113
114if [[ -e "${BUILDDIR}" || -e "${TARGETDIR}" || -e "${DECTARGETDIR}" \
115      || -e "${MUXTARGETDIR}" || -e "${DEMUXTARGETDIR}" \
116      || -e "${SHARPYUVTARGETDIR}" ]]; then
117  cat << EOF
118WARNING: The following directories will be deleted:
119WARNING:   ${BUILDDIR}
120WARNING:   ${TARGETDIR}
121WARNING:   ${DECTARGETDIR}
122WARNING:   ${MUXTARGETDIR}
123WARNING:   ${DEMUXTARGETDIR}
124WARNING:   ${SHARPYUVTARGETDIR}
125WARNING: The build will continue in 5 seconds...
126EOF
127  sleep 5
128fi
129rm -rf ${BUILDDIR} ${TARGETDIR} ${DECTARGETDIR} \
130  ${MUXTARGETDIR} ${DEMUXTARGETDIR} ${SHARPYUVTARGETDIR}
131
132if [[ ! -e ${SRCDIR}/configure ]]; then
133  if ! (cd ${SRCDIR} && sh autogen.sh); then
134    cat << EOF
135Error creating configure script!
136This script requires the autoconf/automake and libtool to build. MacPorts or
137Homebrew can be used to obtain these:
138https://www.macports.org/install.php
139https://brew.sh/
140EOF
141    exit 1
142  fi
143fi
144
145for (( 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        CFLAGS+=" -fembed-bitcode"
176        CFLAGS+=" -target ${ARCH}-apple-ios${IOS_MIN_VERSION}"
177        [[ "${PLATFORM}" == *Simulator* ]] && CFLAGS+="-simulator"
178        ;;
179      MacOSX-Catalyst*)
180        CFLAGS+=" -target"
181        CFLAGS+=" ${ARCH}-apple-ios${MACOSX_CATALYST_MIN_VERSION}-macabi"
182        ;;
183      MacOSX*)
184        CFLAGS+=" -mmacosx-version-min=${MACOSX_MIN_VERSION}"
185        ;;
186    esac
187
188    set -x
189    export PATH="${DEVROOT}/usr/bin:${OLDPATH}"
190    ${SRCDIR}/configure --host=${ARCH/arm64/aarch64}-apple-darwin \
191      --build=$(${SRCDIR}/config.guess) \
192      --prefix=${ROOTDIR} \
193      --disable-shared --enable-static \
194      --enable-libwebpdecoder --enable-swap-16bit-csp \
195      --enable-libwebpmux \
196      CC="clang -arch ${ARCH}" \
197      CFLAGS="${CFLAGS}"
198    set +x
199
200    # Build only the libraries, skip the examples.
201    make V=0 -C sharpyuv install
202    make V=0 -C src install
203
204    LIBLIST+=("${ROOTDIR}/lib/libwebp.a")
205    DECLIBLIST+=("${ROOTDIR}/lib/libwebpdecoder.a")
206    MUXLIBLIST+=("${ROOTDIR}/lib/libwebpmux.a")
207    DEMUXLIBLIST+=("${ROOTDIR}/lib/libwebpdemux.a")
208    SHARPYUVLIBLIST+=("${ROOTDIR}/lib/libsharpyuv.a")
209    # xcodebuild requires a directory for the -headers option, these will match
210    # for all builds.
211    make -C src install-data DESTDIR="${ROOTDIR}/lib-headers"
212    make -C src install-commonHEADERS DESTDIR="${ROOTDIR}/dec-headers"
213    make -C src/demux install-data DESTDIR="${ROOTDIR}/demux-headers"
214    make -C src/mux install-data DESTDIR="${ROOTDIR}/mux-headers"
215    make -C sharpyuv install-data DESTDIR="${ROOTDIR}/sharpyuv-headers"
216    LIB_HEADERS="${ROOTDIR}/lib-headers/${ROOTDIR}/include/webp"
217    DEC_HEADERS="${ROOTDIR}/dec-headers/${ROOTDIR}/include/webp"
218    DEMUX_HEADERS="${ROOTDIR}/demux-headers/${ROOTDIR}/include/webp"
219    MUX_HEADERS="${ROOTDIR}/mux-headers/${ROOTDIR}/include/webp"
220    SHARPYUV_HEADERS="${ROOTDIR}/sharpyuv-headers/${ROOTDIR}/include/webp"
221
222    make distclean
223
224    export PATH=${OLDPATH}
225  done
226
227  [[ -z "${LIBLIST[@]}" ]] && continue
228
229  # Create a temporary target directory for each <platform>[-<variant>].
230  target_dir="${BUILDDIR}/${PLATFORMS[$i]}"
231  target_dir="${target_dir%% *}"
232  target_dir="${target_dir%-*}"
233  target_lib="${target_dir}/$(basename ${LIBLIST[0]})"
234  target_declib="${target_dir}/$(basename ${DECLIBLIST[0]})"
235  target_demuxlib="${target_dir}/$(basename ${DEMUXLIBLIST[0]})"
236  target_muxlib="${target_dir}/$(basename ${MUXLIBLIST[0]})"
237  target_sharpyuvlib="${target_dir}/$(basename ${SHARPYUVLIBLIST[0]})"
238
239  mkdir -p "${target_dir}"
240  ${LIPO} -create ${LIBLIST[@]} -output "${target_lib}"
241  ${LIPO} -create ${DECLIBLIST[@]} -output "${target_declib}"
242  ${LIPO} -create ${DEMUXLIBLIST[@]} -output "${target_demuxlib}"
243  ${LIPO} -create ${MUXLIBLIST[@]} -output "${target_muxlib}"
244  ${LIPO} -create ${SHARPYUVLIBLIST[@]} -output "${target_sharpyuvlib}"
245  FAT_LIBLIST+=(-library "${target_lib}" -headers "${LIB_HEADERS}")
246  FAT_DECLIBLIST+=(-library "${target_declib}" -headers "${DEC_HEADERS}")
247  FAT_DEMUXLIBLIST+=(-library "${target_demuxlib}" -headers "${DEMUX_HEADERS}")
248  FAT_MUXLIBLIST+=(-library "${target_muxlib}" -headers "${MUX_HEADERS}")
249  FAT_SHARPYUVLIBLIST+=(-library "${target_sharpyuvlib}")
250  FAT_SHARPYUVLIBLIST+=(-headers "${SHARPYUV_HEADERS}")
251done
252
253# lipo will not put archives with the same architecture (e.g., x86_64
254# iPhoneSimulator & MacOS) in the same fat output file. xcodebuild
255# -create-xcframework requires universal archives to avoid e.g.:
256#   Both ios-x86_64-maccatalyst and ios-arm64-maccatalyst represent two
257#   equivalent library definitions
258set -x
259xcodebuild -create-xcframework "${FAT_LIBLIST[@]}" \
260  -output ${TARGETDIR}
261xcodebuild -create-xcframework "${FAT_DECLIBLIST[@]}" \
262  -output ${DECTARGETDIR}
263xcodebuild -create-xcframework "${FAT_DEMUXLIBLIST[@]}" \
264  -output ${DEMUXTARGETDIR}
265xcodebuild -create-xcframework "${FAT_MUXLIBLIST[@]}" \
266  -output ${MUXTARGETDIR}
267xcodebuild -create-xcframework "${FAT_SHARPYUVLIBLIST[@]}" \
268  -output ${SHARPYUVTARGETDIR}
269update_headers_path "${TARGETDIR}"
270update_headers_path "${DECTARGETDIR}"
271update_headers_path "${DEMUXTARGETDIR}"
272update_headers_path "${MUXTARGETDIR}"
273update_headers_path "${SHARPYUVTARGETDIR}"
274set +x
275
276echo  "SUCCESS"
277