Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 1 | #!/bin/bash |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 2 | # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | RunCommand() { |
xster | d401bd7 | 2018-02-13 01:56:13 -0800 | [diff] [blame] | 7 | if [[ -n "$VERBOSE_SCRIPT_LOGGING" ]]; then |
| 8 | echo "♦ $*" |
| 9 | fi |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 10 | "$@" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 11 | return $? |
| 12 | } |
| 13 | |
| 14 | EchoError() { |
| 15 | echo "$@" 1>&2 |
| 16 | } |
| 17 | |
| 18 | AssertExists() { |
Chris Bracken | 0294cf8 | 2017-02-09 13:45:39 -0800 | [diff] [blame] | 19 | if [[ ! -e "$1" ]]; then |
| 20 | if [[ -h "$1" ]]; then |
| 21 | EchoError "The path $1 is a symlink to a path that does not exist" |
| 22 | else |
| 23 | EchoError "The path $1 does not exist" |
| 24 | fi |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 25 | exit -1 |
| 26 | fi |
| 27 | return 0 |
| 28 | } |
| 29 | |
| 30 | BuildApp() { |
Adam Barth | 8171aa8 | 2016-06-03 12:20:54 -0700 | [diff] [blame] | 31 | local project_path="${SOURCE_ROOT}/.." |
| 32 | if [[ -n "$FLUTTER_APPLICATION_PATH" ]]; then |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 33 | project_path="${FLUTTER_APPLICATION_PATH}" |
Adam Barth | 8171aa8 | 2016-06-03 12:20:54 -0700 | [diff] [blame] | 34 | fi |
| 35 | |
| 36 | local target_path="lib/main.dart" |
| 37 | if [[ -n "$FLUTTER_TARGET" ]]; then |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 38 | target_path="${FLUTTER_TARGET}" |
Adam Barth | 8171aa8 | 2016-06-03 12:20:54 -0700 | [diff] [blame] | 39 | fi |
| 40 | |
Chris Bracken | acdbe45 | 2017-10-27 18:23:50 -0700 | [diff] [blame] | 41 | # Archive builds (ACTION=install) should always run in release mode. |
| 42 | if [[ "$ACTION" == "install" && "$FLUTTER_BUILD_MODE" != "release" ]]; then |
| 43 | EchoError "========================================================================" |
| 44 | EchoError "ERROR: Flutter archive builds must be run in Release mode." |
| 45 | EchoError "" |
| 46 | EchoError "To correct, run:" |
| 47 | EchoError "flutter build ios --release" |
| 48 | EchoError "" |
| 49 | EchoError "then re-run Archive from Xcode." |
| 50 | EchoError "========================================================================" |
| 51 | exit -1 |
| 52 | fi |
| 53 | |
Adam Barth | 8f03ebe | 2016-06-06 12:56:04 -0700 | [diff] [blame] | 54 | local build_mode="release" |
| 55 | if [[ -n "$FLUTTER_BUILD_MODE" ]]; then |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 56 | build_mode="${FLUTTER_BUILD_MODE}" |
Adam Barth | 29af5c0 | 2016-06-03 17:01:18 -0700 | [diff] [blame] | 57 | fi |
| 58 | |
| 59 | local artifact_variant="unknown" |
Adam Barth | 8f03ebe | 2016-06-06 12:56:04 -0700 | [diff] [blame] | 60 | case "$build_mode" in |
Adam Barth | 29af5c0 | 2016-06-03 17:01:18 -0700 | [diff] [blame] | 61 | release) artifact_variant="ios-release";; |
| 62 | profile) artifact_variant="ios-profile";; |
| 63 | debug) artifact_variant="ios";; |
Adam Barth | 8f03ebe | 2016-06-06 12:56:04 -0700 | [diff] [blame] | 64 | *) echo "Unknown FLUTTER_BUILD_MODE: $FLUTTER_BUILD_MODE";; |
Adam Barth | 29af5c0 | 2016-06-03 17:01:18 -0700 | [diff] [blame] | 65 | esac |
| 66 | |
| 67 | local framework_path="${FLUTTER_ROOT}/bin/cache/artifacts/engine/${artifact_variant}" |
Adam Barth | 8171aa8 | 2016-06-03 12:20:54 -0700 | [diff] [blame] | 68 | if [[ -n "$FLUTTER_FRAMEWORK_DIR" ]]; then |
| 69 | framework_path="${FLUTTER_FRAMEWORK_DIR}" |
| 70 | fi |
| 71 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 72 | AssertExists "${project_path}" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 73 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 74 | local derived_dir="${SOURCE_ROOT}/Flutter" |
| 75 | RunCommand mkdir -p -- "$derived_dir" |
| 76 | AssertExists "$derived_dir" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 77 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 78 | RunCommand rm -rf -- "${derived_dir}/Flutter.framework" |
Chris Bracken | 0ee3f57 | 2017-03-22 17:41:49 -0700 | [diff] [blame] | 79 | RunCommand rm -rf -- "${derived_dir}/App.framework" |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 80 | RunCommand rm -f -- "${derived_dir}/app.flx" |
| 81 | RunCommand cp -r -- "${framework_path}/Flutter.framework" "${derived_dir}" |
Chris Bracken | e22d0e6 | 2017-03-14 09:31:31 -0700 | [diff] [blame] | 82 | RunCommand find "${derived_dir}/Flutter.framework" -type f -exec chmod a-w "{}" \; |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 83 | RunCommand pushd "${project_path}" > /dev/null |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 84 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 85 | AssertExists "${target_path}" |
Adam Barth | 8171aa8 | 2016-06-03 12:20:54 -0700 | [diff] [blame] | 86 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 87 | local build_dir="${FLUTTER_BUILD_DIR:-build}" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 88 | local local_engine_flag="" |
| 89 | if [[ -n "$LOCAL_ENGINE" ]]; then |
| 90 | local_engine_flag="--local-engine=$LOCAL_ENGINE" |
| 91 | fi |
| 92 | |
Alexander Aprelev | 4447c0a | 2017-11-29 18:11:34 -0800 | [diff] [blame] | 93 | local preview_dart_2_flag="" |
| 94 | if [[ -n "$PREVIEW_DART_2" ]]; then |
| 95 | preview_dart_2_flag="--preview-dart-2" |
| 96 | fi |
| 97 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 98 | if [[ "$CURRENT_ARCH" != "x86_64" ]]; then |
Chinmay Garde | 8756a09 | 2016-06-03 13:55:57 -0700 | [diff] [blame] | 99 | local aot_flags="" |
Adam Barth | 8f03ebe | 2016-06-06 12:56:04 -0700 | [diff] [blame] | 100 | if [[ "$build_mode" == "debug" ]]; then |
Chinmay Garde | 8756a09 | 2016-06-03 13:55:57 -0700 | [diff] [blame] | 101 | aot_flags="--interpreter --debug" |
| 102 | else |
Adam Barth | 8f03ebe | 2016-06-06 12:56:04 -0700 | [diff] [blame] | 103 | aot_flags="--${build_mode}" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 104 | fi |
| 105 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 106 | RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics build aot \ |
| 107 | --output-dir="${build_dir}/aot" \ |
| 108 | --target-platform=ios \ |
| 109 | --target="${target_path}" \ |
| 110 | ${aot_flags} \ |
Alexander Aprelev | 4447c0a | 2017-11-29 18:11:34 -0800 | [diff] [blame] | 111 | ${local_engine_flag} \ |
Alexander Aprelev | bedf987 | 2018-01-11 14:08:28 -0800 | [diff] [blame] | 112 | ${preview_dart_2_flag} \ |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 113 | |
| 114 | if [[ $? -ne 0 ]]; then |
| 115 | EchoError "Failed to build ${project_path}." |
| 116 | exit -1 |
| 117 | fi |
| 118 | |
Chris Bracken | 0ee3f57 | 2017-03-22 17:41:49 -0700 | [diff] [blame] | 119 | RunCommand cp -r -- "${build_dir}/aot/App.framework" "${derived_dir}" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 120 | else |
Chris Bracken | 0ee3f57 | 2017-03-22 17:41:49 -0700 | [diff] [blame] | 121 | RunCommand mkdir -p -- "${derived_dir}/App.framework" |
| 122 | RunCommand eval "$(echo "static const int Moo = 88;" | xcrun clang -x c \ |
| 123 | -dynamiclib \ |
| 124 | -Xlinker -rpath -Xlinker '@executable_path/Frameworks' \ |
| 125 | -Xlinker -rpath -Xlinker '@loader_path/Frameworks' \ |
| 126 | -install_name '@rpath/App.framework/App' \ |
| 127 | -o "${derived_dir}/App.framework/App" -)" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 128 | fi |
Chris Bracken | 0ee3f57 | 2017-03-22 17:41:49 -0700 | [diff] [blame] | 129 | RunCommand cp -- "${derived_dir}/AppFrameworkInfo.plist" "${derived_dir}/App.framework/Info.plist" |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 130 | |
| 131 | local precompilation_flag="" |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 132 | if [[ "$CURRENT_ARCH" != "x86_64" ]] && [[ "$build_mode" != "debug" ]]; then |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 133 | precompilation_flag="--precompiled" |
| 134 | fi |
| 135 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 136 | RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics build flx \ |
| 137 | --target="${target_path}" \ |
| 138 | --output-file="${derived_dir}/app.flx" \ |
| 139 | --snapshot="${build_dir}/snapshot_blob.bin" \ |
| 140 | --depfile="${build_dir}/snapshot_blob.bin.d" \ |
Sarah Zakarias | 5e18c07 | 2017-12-14 17:27:25 +0100 | [diff] [blame] | 141 | --working-dir="${derived_dir}/flutter_assets" \ |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 142 | ${precompilation_flag} \ |
| 143 | ${local_engine_flag} \ |
Alexander Aprelev | 4447c0a | 2017-11-29 18:11:34 -0800 | [diff] [blame] | 144 | ${preview_dart_2_flag} \ |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 145 | |
| 146 | if [[ $? -ne 0 ]]; then |
| 147 | EchoError "Failed to package ${project_path}." |
| 148 | exit -1 |
| 149 | fi |
| 150 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 151 | RunCommand popd > /dev/null |
Adam Barth | aee3269 | 2016-05-27 15:30:42 -0700 | [diff] [blame] | 152 | |
| 153 | echo "Project ${project_path} built and packaged successfully." |
| 154 | return 0 |
| 155 | } |
| 156 | |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 157 | # Returns the CFBundleExecutable for the specified framework directory. |
| 158 | GetFrameworkExecutablePath() { |
| 159 | local framework_dir="$1" |
| 160 | |
| 161 | local plist_path="${framework_dir}/Info.plist" |
| 162 | local executable="$(defaults read "${plist_path}" CFBundleExecutable)" |
| 163 | echo "${framework_dir}/${executable}" |
| 164 | } |
| 165 | |
| 166 | # Destructively thins the specified executable file to include only the |
| 167 | # specified architectures. |
| 168 | LipoExecutable() { |
| 169 | local executable="$1" |
| 170 | shift |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 171 | local archs=("$@") |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 172 | |
| 173 | # Extract architecture-specific framework executables. |
| 174 | local all_executables=() |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 175 | for arch in "${archs[@]}"; do |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 176 | local output="${executable}_${arch}" |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 177 | local lipo_info="$(lipo -info "${executable}")" |
Chris Bracken | b16a515 | 2017-02-07 15:57:16 -0800 | [diff] [blame] | 178 | if [[ "${lipo_info}" == "Non-fat file:"* ]]; then |
| 179 | if [[ "${lipo_info}" != *"${arch}" ]]; then |
| 180 | echo "Non-fat binary ${executable} is not ${arch}. Running lipo -info:" |
| 181 | echo "${lipo_info}" |
| 182 | exit 1 |
| 183 | fi |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 184 | else |
Chris Bracken | b16a515 | 2017-02-07 15:57:16 -0800 | [diff] [blame] | 185 | lipo -output "${output}" -extract "${arch}" "${executable}" |
| 186 | if [[ $? == 0 ]]; then |
| 187 | all_executables+=("${output}") |
| 188 | else |
| 189 | echo "Failed to extract ${arch} for ${executable}. Running lipo -info:" |
| 190 | lipo -info "${executable}" |
| 191 | exit 1 |
| 192 | fi |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 193 | fi |
| 194 | done |
| 195 | |
Chris Bracken | 36e3260 | 2017-02-17 13:38:47 -0800 | [diff] [blame] | 196 | # Generate a merged binary from the architecture-specific executables. |
| 197 | # Skip this step for non-fat executables. |
| 198 | if [[ ${#all_executables[@]} > 0 ]]; then |
| 199 | local merged="${executable}_merged" |
| 200 | lipo -output "${merged}" -create "${all_executables[@]}" |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 201 | |
Chris Bracken | 36e3260 | 2017-02-17 13:38:47 -0800 | [diff] [blame] | 202 | cp -f -- "${merged}" "${executable}" > /dev/null |
| 203 | rm -f -- "${merged}" "${all_executables[@]}" |
| 204 | fi |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 205 | } |
| 206 | |
| 207 | # Destructively thins the specified framework to include only the specified |
| 208 | # architectures. |
| 209 | ThinFramework() { |
| 210 | local framework_dir="$1" |
| 211 | shift |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 212 | local archs=("$@") |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 213 | |
| 214 | local plist_path="${framework_dir}/Info.plist" |
| 215 | local executable="$(GetFrameworkExecutablePath "${framework_dir}")" |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 216 | LipoExecutable "${executable}" "${archs[@]}" |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | ThinAppFrameworks() { |
| 220 | local app_path="${TARGET_BUILD_DIR}/${WRAPPER_NAME}" |
| 221 | local frameworks_dir="${app_path}/Frameworks" |
| 222 | |
| 223 | [[ -d "$frameworks_dir" ]] || return 0 |
Chris Bracken | 1a2e6f3 | 2017-03-10 09:32:58 -0800 | [diff] [blame] | 224 | find "${app_path}" -type d -name "*.framework" | while read framework_dir; do |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 225 | ThinFramework "$framework_dir" "$ARCHS" |
| 226 | done |
| 227 | } |
| 228 | |
| 229 | # Main entry point. |
| 230 | |
Chris Bracken | 3449545 | 2017-02-09 15:08:33 -0800 | [diff] [blame] | 231 | # TODO(cbracken) improve error handling, then enable set -e |
| 232 | |
Chris Bracken | 1926d11 | 2017-02-07 12:04:36 -0800 | [diff] [blame] | 233 | if [[ $# == 0 ]]; then |
| 234 | # Backwards-comptibility: if no args are provided, build. |
| 235 | BuildApp |
| 236 | else |
| 237 | case $1 in |
| 238 | "build") |
| 239 | BuildApp ;; |
| 240 | "thin") |
| 241 | ThinAppFrameworks ;; |
| 242 | esac |
| 243 | fi |