|
| 1 | +#!/bin/bash -e |
| 2 | +# |
| 3 | +# Script to build iOS XCFrameworks |
| 4 | +# If built for all architectures (arm64 armv7 x86_64 i386), |
| 5 | +# it will build universal framework as well |
| 6 | +# |
| 7 | + |
| 8 | +usage(){ |
| 9 | + echo "Usage: $0 [options] |
| 10 | + options: |
| 11 | + -b, build path default: tvos_build |
| 12 | + -s, source path default: . |
| 13 | + -p, framework platform default: ${SUPPORTED_PLATFORMS[@]} |
| 14 | + -a, framework architecture default: ${SUPPORTED_ARCHITECTURES[@]} |
| 15 | + -t, CMake target default: ${SUPPORTED_TARGETS[@]} |
| 16 | + -g, generate Makefiles default: true |
| 17 | + -c, CMake build default: true |
| 18 | + example: |
| 19 | + build_scripts/tvos/build.sh -b tvos_build -s . -a arm64,x86_64 -t firebase_admob,firebase_auth -c false" |
| 20 | +} |
| 21 | + |
| 22 | +set -e |
| 23 | + |
| 24 | +readonly SUPPORTED_PLATFORMS=(device simulator) |
| 25 | +readonly SUPPORTED_ARCHITECTURES=(arm64 x86_64) |
| 26 | +readonly DEVICE_ARCHITECTURES=(arm64) |
| 27 | +readonly SIMULATOR_ARCHITECTURES=(arm64 x86_64) |
| 28 | +readonly SUPPORTED_TARGETS=(firebase_analytics firebase_auth firebase_database firebase_firestore firebase_functions firebase_installations firebase_messaging firebase_remote_config firebase_storage) |
| 29 | + |
| 30 | +# build default value |
| 31 | +buildpath="tvos_build" |
| 32 | +sourcepath="." |
| 33 | +platforms=("${SUPPORTED_PLATFORMS[@]}") |
| 34 | +architectures=("${SUPPORTED_ARCHITECTURES[@]}") |
| 35 | +targets=("${SUPPORTED_TARGETS[@]}") |
| 36 | +generateMakefiles=true |
| 37 | +cmakeBuild=true |
| 38 | + |
| 39 | +# check options |
| 40 | +IFS=',' # split options on ',' characters |
| 41 | +while getopts ":b:s:a:t:g:ch" opt; do |
| 42 | + case $opt in |
| 43 | + h) |
| 44 | + usage |
| 45 | + exit 0 |
| 46 | + ;; |
| 47 | + b) |
| 48 | + buildpath=$OPTARG |
| 49 | + ;; |
| 50 | + s) |
| 51 | + sourcepath=$OPTARG |
| 52 | + if [[ ! -d "${sourcepath}" ]]; then |
| 53 | + echo "Source path ${sourcepath} not found." |
| 54 | + exit 2 |
| 55 | + fi |
| 56 | + ;; |
| 57 | + p) |
| 58 | + platforms=($OPTARG) |
| 59 | + for platform in ${platforms[@]}; do |
| 60 | + if [[ ! " ${SUPPORTED_PLATFORMS[@]} " =~ " ${platform} " ]]; then |
| 61 | + echo "invalid platform: ${platform}" |
| 62 | + echo "Supported platforms are: ${SUPPORTED_PLATFORMS[@]}" |
| 63 | + exit 2 |
| 64 | + fi |
| 65 | + done |
| 66 | + ;; |
| 67 | + a) |
| 68 | + architectures=($OPTARG) |
| 69 | + for arch in ${architectures[@]}; do |
| 70 | + if [[ ! " ${SUPPORTED_ARCHITECTURES[@]} " =~ " ${arch} " ]]; then |
| 71 | + echo "invalid architecture: ${arch}" |
| 72 | + echo "Supported architectures are: ${SUPPORTED_ARCHITECTURES[@]}" |
| 73 | + exit 2 |
| 74 | + fi |
| 75 | + done |
| 76 | + ;; |
| 77 | + t) |
| 78 | + targets=($OPTARG) |
| 79 | + for t in ${targets[@]}; do |
| 80 | + if [[ ! " ${SUPPORTED_TARGETS[@]} " =~ " ${t} " ]]; then |
| 81 | + echo "invalid target: ${t}" |
| 82 | + echo "Supported targets are: ${SUPPORTED_TARGETS[@]}" |
| 83 | + exit 2 |
| 84 | + fi |
| 85 | + done |
| 86 | + ;; |
| 87 | + g) |
| 88 | + if [[ $OPTARG == true ]]; then |
| 89 | + generateMakefiles=true |
| 90 | + else |
| 91 | + generateMakefiles=false |
| 92 | + fi |
| 93 | + ;; |
| 94 | + c) |
| 95 | + if [[ $OPTARG == true ]]; then |
| 96 | + cmakeBuild=true |
| 97 | + else |
| 98 | + cmakeBuild=false |
| 99 | + fi |
| 100 | + ;; |
| 101 | + *) |
| 102 | + echo "unknown parameter" |
| 103 | + exit 2 |
| 104 | + ;; |
| 105 | + esac |
| 106 | +done |
| 107 | +echo "build path: ${buildpath}" |
| 108 | +echo "source path: ${sourcepath}" |
| 109 | +echo "build platforms: ${platforms[@]}" |
| 110 | +echo "build architectures: ${architectures[@]}" |
| 111 | +echo "build targets: ${targets[@]}" |
| 112 | +echo "generate Makefiles: ${generateMakefiles}" |
| 113 | +echo "CMake Build: ${cmakeBuild}" |
| 114 | +sourcepath=$(cd ${sourcepath} && pwd) #full path |
| 115 | +buildpath=$(mkdir -p ${buildpath} && cd ${buildpath} && pwd) #full path |
| 116 | + |
| 117 | +# generate Makefiles for each architecture and target |
| 118 | +frameworkspath="frameworks/tvos" |
| 119 | +tvos_toolchain_platform="TVOS" |
| 120 | +if ${generateMakefiles}; then |
| 121 | + for platform in ${platforms[@]}; do |
| 122 | + for arch in ${architectures[@]}; do |
| 123 | + if [[ "${platform}" == "device" && " ${DEVICE_ARCHITECTURES[@]} " =~ " ${arch} " ]]; then |
| 124 | + toolchain="cmake/toolchains/apple.toolchain.cmake" |
| 125 | + elif [[ "${platform}" == "simulator" && " ${SIMULATOR_ARCHITECTURES[@]} " =~ " ${arch} " ]]; then |
| 126 | + toolchain="cmake/toolchains/apple.toolchain.cmake" |
| 127 | + tvos_toolchain_platform="SIMULATOR_TVOS" |
| 128 | + else |
| 129 | + continue |
| 130 | + fi |
| 131 | + |
| 132 | + echo "generate Makefiles start" |
| 133 | + mkdir -p ${buildpath}/tvos_build_file/${platform}-${arch} && cd ${buildpath}/tvos_build_file/${platform}-${arch} |
| 134 | + cmake -DCMAKE_TOOLCHAIN_FILE=${sourcepath}/${toolchain} \ |
| 135 | + -DPLATFORM=${tvos_toolchain_platform} \ |
| 136 | + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${buildpath}/${frameworkspath}/${platform}-${arch} \ |
| 137 | + ${sourcepath} |
| 138 | + echo "generate Makefiles end" |
| 139 | + done |
| 140 | + done |
| 141 | +fi |
| 142 | + |
| 143 | +# build framework for each architecture and target |
| 144 | +IFS=$'\n' # split $(ls) on \n characters |
| 145 | +if ${cmakeBuild}; then |
| 146 | + for platform in ${platforms[@]}; do |
| 147 | + for arch in ${architectures[@]}; do |
| 148 | + if [ -d "${buildpath}/tvos_build_file/${platform}-${arch}" ]; then |
| 149 | + { |
| 150 | + cd ${buildpath}/tvos_build_file/${platform}-${arch} |
| 151 | + echo "build ${platform} ${arch} ${targets[@]} framework start" |
| 152 | + cmake --build . --target ${targets[@]} |
| 153 | + echo "build ${platform} ${arch} ${targets[@]} framework end" |
| 154 | + |
| 155 | + } & |
| 156 | + fi |
| 157 | + done |
| 158 | + done |
| 159 | + subprocess_fail=0 |
| 160 | + for job in $(jobs -p); do |
| 161 | + wait $job || let "subprocess_fail+=1" |
| 162 | + done |
| 163 | + if [ "${subprocess_fail}" == "0" ]; then |
| 164 | + echo "frameworks build end" |
| 165 | + else |
| 166 | + echo "frameworks build error, ${subprocess_fail} architecture(s) build failed" |
| 167 | + exit 2 |
| 168 | + fi |
| 169 | + |
| 170 | + # arrange the framework |
| 171 | + cd ${buildpath}/${frameworkspath} |
| 172 | + for platform in ${platforms[@]}; do |
| 173 | + for arch in ${architectures[@]}; do |
| 174 | + if [[ ! -d "${platform}-${arch}" ]]; then |
| 175 | + continue |
| 176 | + fi |
| 177 | + |
| 178 | + # rename firebase_app to firebase |
| 179 | + if [[ ! -d "${platform}-${arch}/firebase.framework" ]]; then |
| 180 | + mv ${platform}-${arch}/firebase_app.framework ${platform}-${arch}/firebase.framework |
| 181 | + mv ${platform}-${arch}/firebase.framework/firebase_app ${platform}-${arch}/firebase.framework/firebase |
| 182 | + rm ${platform}-${arch}/firebase.framework/Info.plist |
| 183 | + fi |
| 184 | + |
| 185 | + # delete useless Info.plist |
| 186 | + for target in ${targets[@]}; do |
| 187 | + if [[ -f "${platform}-${arch}/${target}.framework/Info.plist" ]]; then |
| 188 | + rm ${platform}-${arch}/${target}.framework/Info.plist |
| 189 | + fi |
| 190 | + done |
| 191 | + |
| 192 | + # delete non-framework dir |
| 193 | + for dir in $(ls ${platform}-${arch}); do |
| 194 | + if [[ ! ${dir} =~ ".framework" ]]; then |
| 195 | + rm -rf ${platform}-${arch}/${dir} |
| 196 | + fi |
| 197 | + done |
| 198 | + done |
| 199 | + done |
| 200 | + |
| 201 | + # if we built for all architectures (arm64 armv7 x86_64 i386) |
| 202 | + # build universal framework as well |
| 203 | + if [[ ${#architectures[@]} < ${#SUPPORTED_ARCHITECTURES[@]} ]]; then |
| 204 | + exit 0 |
| 205 | + fi |
| 206 | + |
| 207 | + targets+=('firebase') |
| 208 | + for target in ${targets[@]}; do |
| 209 | + mkdir -p universal/${target}.framework |
| 210 | + libsubpath="${target}.framework/${target}" |
| 211 | + lipo -create "device-arm64/${libsubpath}" \ |
| 212 | + "simulator-x86_64/${libsubpath}" \ |
| 213 | + -output "universal/${libsubpath}" |
| 214 | + done |
| 215 | + if [[ ! -d "universal/firebase.framework/Headers" ]]; then |
| 216 | + cp -R device-arm64/firebase.framework/Headers universal/firebase.framework |
| 217 | + fi |
| 218 | + echo "universal frameworks build end & ready to use" |
| 219 | + |
| 220 | + # covert framework into xcframework |
| 221 | + cd ${buildpath} |
| 222 | + xcframeworkspath="xcframeworks" |
| 223 | + mkdir -p ${xcframeworkspath} |
| 224 | + # create library for xcframework |
| 225 | + for platform in ${platforms[@]}; do |
| 226 | + for target in ${targets[@]}; do |
| 227 | + libsubpath="${target}.framework/${target}" |
| 228 | + if [[ "${platform}" == "device" ]]; then |
| 229 | + outputdir="${xcframeworkspath}/${target}.xcframework/tvos-arm64/${target}.framework" |
| 230 | + mkdir -p ${outputdir} |
| 231 | + lipo -create "${frameworkspath}/device-arm64/${libsubpath}" \ |
| 232 | + -output "${outputdir}/${target}" |
| 233 | + |
| 234 | + elif [[ "${platform}" == "simulator" ]]; then |
| 235 | + outputdir="${xcframeworkspath}/${target}.xcframework/tvos-x86_64-simulator/${target}.framework" |
| 236 | + mkdir -p ${outputdir} |
| 237 | + lipo -create "${frameworkspath}/simulator-x86_64/${libsubpath}" \ |
| 238 | + -output "${outputdir}/${target}" |
| 239 | + fi |
| 240 | + done |
| 241 | + done |
| 242 | + |
| 243 | + # create Info.plist for xcframework |
| 244 | + for target in ${targets[@]}; do |
| 245 | + cp ${sourcepath}/build_scripts/tvos/Info.plist ${xcframeworkspath}/${target}.xcframework |
| 246 | + sed -i "" "s/LIBRARY_PATH/${target}.framework/" ${xcframeworkspath}/${target}.xcframework/Info.plist |
| 247 | + done |
| 248 | + |
| 249 | + # create Headers for xcframework |
| 250 | + if [[ ! -d "${xcframeworkspath}/firebase.xcframework/tvos-arm64/firebase.framework/Headers" ]]; then |
| 251 | + cp -R ${frameworkspath}/device-arm64/firebase.framework/Headers \ |
| 252 | + ${xcframeworkspath}/firebase.xcframework/tvos-arm64/firebase.framework/Headers |
| 253 | + cp -R ${frameworkspath}/device-arm64/firebase.framework/Headers \ |
| 254 | + ${xcframeworkspath}/firebase.xcframework/tvos-x86_64-simulator/firebase.framework/Headers |
| 255 | + fi |
| 256 | + echo "xcframeworks build end & ready to use" |
| 257 | +fi |
0 commit comments