Skip to content

Commit bfdbd5b

Browse files
authored
Use presets to build Apple frameworks (#11115)
### Summary * Use the Apple presets to build the frameworks * Make the script build without options by default. If people want to turn off features, they can use `CMAKE_ARGS` ### Test plan CI + ``` $ scripts/build_apple_frameworks.sh ``` ``` $ scripts/build_apple_frameworks.sh --portable --coreml ```
1 parent 58e99b9 commit bfdbd5b

File tree

3 files changed

+112
-161
lines changed

3 files changed

+112
-161
lines changed

.github/workflows/apple-perf.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ jobs:
386386
echo "::endgroup::"
387387
388388
echo "::group::Build ExecuTorch iOS frameworks"
389-
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
390-
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
389+
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh
391390
echo "::endgroup::"
392391
393392
# NB: Although exported models can be copied to this directory and bundled together with the

.github/workflows/apple.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,7 @@ jobs:
173173
backends/apple/mps/install_requirements.sh
174174
175175
# Build iOS Frameworks
176-
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
177-
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
176+
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh
178177
179178
# Bundle iOS Frameworks
180179
for FRAMEWORK in "${FRAMEWORKS[@]}"; do (
@@ -314,8 +313,7 @@ jobs:
314313
echo "::endgroup::"
315314
316315
echo "::group::Build ExecuTorch iOS frameworks"
317-
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
318-
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
316+
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh
319317
echo "::endgroup::"
320318
321319
echo "::group::Build ExecuTorch benchmark app"

scripts/build_apple_frameworks.sh

Lines changed: 109 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,18 @@
77

88
set -euxo pipefail
99

10-
SOURCE_ROOT_DIR=""
11-
OUTPUT="cmake-out"
12-
MODES=()
13-
TOOLCHAIN=""
14-
PYTHON=$(which python3)
15-
COREML=OFF
16-
CUSTOM=OFF
17-
MPS=OFF
18-
OPTIMIZED=OFF
19-
PORTABLE=OFF
20-
QUANTIZED=OFF
21-
XNNPACK=OFF
22-
HEADERS_PATH="include"
23-
24-
PLATFORMS=("ios" "simulator" "macos")
25-
PLATFORM_FLAGS=("OS64" "SIMULATORARM64" "MAC_ARM64")
26-
PLATFORM_TARGET=("17.0" "17.0" "10.15")
10+
MODES=("Release" "Debug")
11+
PRESETS=("ios" "ios-simulator" "macos")
12+
13+
SOURCE_ROOT_DIR=$(git rev-parse --show-toplevel)
14+
OUTPUT_DIR="${SOURCE_ROOT_DIR}/cmake-out"
15+
HEADERS_RELATIVE_PATH="include"
16+
HEADERS_ABSOLUTE_PATH="${OUTPUT_DIR}/${HEADERS_RELATIVE_PATH}"
17+
18+
BUCK2=$(python3 "$SOURCE_ROOT_DIR/tools/cmake/resolve_buck.py" --cache_dir="$SOURCE_ROOT_DIR/buck2-bin")
19+
if [[ "$BUCK2" == "buck2" ]]; then
20+
BUCK2=$(command -v buck2)
21+
fi
2722

2823
FRAMEWORK_EXECUTORCH="executorch:\
2924
libexecutorch.a,\
@@ -33,7 +28,7 @@ libextension_data_loader.a,\
3328
libextension_flat_tensor.a,\
3429
libextension_module.a,\
3530
libextension_tensor.a,\
36-
:$HEADERS_PATH:ExecuTorch"
31+
:$HEADERS_RELATIVE_PATH:ExecuTorch"
3732

3833
FRAMEWORK_BACKEND_COREML="backend_coreml:\
3934
libcoreml_util.a,\
@@ -75,33 +70,51 @@ libquantized_ops_lib.a,\
7570
:"
7671

7772
usage() {
78-
echo "Usage: $0 [SOURCE_ROOT_DIR] [OPTIONS]"
73+
echo "Usage: $0 [OPTIONS]"
7974
echo "Build frameworks for Apple platforms."
80-
echo "SOURCE_ROOT_DIR defaults to the current directory if not provided."
8175
echo
8276
echo "Options:"
83-
echo " --output=DIR Output directory. Default: 'cmake-out'"
8477
echo " --Debug Build Debug version."
8578
echo " --Release Build Release version."
86-
echo " --toolchain=FILE CMake toolchain file. Default: '\$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake'"
87-
echo " --python=FILE Python executable path. Default: Path of python3 in \$PATH"
88-
echo " --coreml Build the Core ML backend."
89-
echo " --custom Build the Custom kernels."
90-
echo " --mps Build the Metal Performance Shaders backend."
91-
echo " --optimized Build the Optimized kernels."
92-
echo " --portable Build the Portable kernels."
93-
echo " --quantized Build the Quantized kernels."
94-
echo " --xnnpack Build the XNNPACK backend."
79+
echo " --coreml Only build the Core ML backend."
80+
echo " --custom Only build the Custom kernels."
81+
echo " --mps Only build the Metal Performance Shaders backend."
82+
echo " --optimized Only build the Optimized kernels."
83+
echo " --portable Only build the Portable kernels."
84+
echo " --quantized Only build the Quantized kernels."
85+
echo " --xnnpack Only build the XNNPACK backend."
9586
echo
96-
echo "Example:"
97-
echo " $0 /path/to/source/root --output=cmake-out --toolchain=/path/to/toolchain --python=/path/to/python3 --coreml --mps --xnnpack"
9887
exit 0
9988
}
10089

90+
CMAKE_OPTIONS_OVERRIDE=()
91+
set_cmake_options_override() {
92+
local option_name="$1"
93+
94+
if [[ ${#CMAKE_OPTIONS_OVERRIDE[@]} -eq 0 ]]; then
95+
# Since the user wants specific options, turn everything off
96+
CMAKE_OPTIONS_OVERRIDE=(
97+
"-DEXECUTORCH_BUILD_COREML=OFF"
98+
"-DEXECUTORCH_BUILD_KERNELS_CUSTOM=OFF"
99+
"-DEXECUTORCH_BUILD_MPS=OFF"
100+
"-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=OFF"
101+
"-DEXECUTORCH_BUILD_PORTABLE_OPS=OFF"
102+
"-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=OFF"
103+
"-DEXECUTORCH_BUILD_XNNPACK=OFF"
104+
)
105+
fi
106+
107+
for i in "${!CMAKE_OPTIONS_OVERRIDE[@]}"; do
108+
if [[ "${CMAKE_OPTIONS_OVERRIDE[$i]}" =~ "-D${option_name}=OFF" ]]; then
109+
CMAKE_OPTIONS_OVERRIDE[$i]="-D${option_name}=ON"
110+
break
111+
fi
112+
done
113+
}
114+
101115
for arg in "$@"; do
102116
case $arg in
103117
-h|--help) usage ;;
104-
--output=*) OUTPUT="${arg#*=}" ;;
105118
--Release)
106119
if [[ ! " ${MODES[*]:-} " =~ \bRelease\b ]]; then
107120
MODES+=("Release")
@@ -112,119 +125,50 @@ for arg in "$@"; do
112125
MODES+=("Debug")
113126
fi
114127
;;
115-
--toolchain=*) TOOLCHAIN="${arg#*=}" ;;
116-
--python=*) PYTHON="${arg#*=}" ;;
117-
--coreml) COREML=ON ;;
118-
--custom) CUSTOM=ON ;;
119-
--mps) MPS=ON ;;
120-
--optimized) OPTIMIZED=ON ;;
121-
--portable) PORTABLE=ON ;;
122-
--quantized) QUANTIZED=ON ;;
123-
--xnnpack) XNNPACK=ON ;;
128+
--coreml) set_cmake_options_override "EXECUTORCH_BUILD_COREML";;
129+
--custom) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_CUSTOM" ;;
130+
--mps) set_cmake_options_override "EXECUTORCH_BUILD_MPS" ;;
131+
--optimized) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_OPTIMIZED" ;;
132+
--portable) set_cmake_options_override "EXECUTORCH_BUILD_PORTABLE_OPS" ;;
133+
--quantized) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_QUANTIZED" ;;
134+
--xnnpack) set_cmake_options_override "EXECUTORCH_BUILD_XNNPACK" ;;
124135
*)
125-
if [[ -z "$SOURCE_ROOT_DIR" ]]; then
126-
SOURCE_ROOT_DIR="$arg"
127-
else
128-
echo "Invalid argument: $arg"
129-
exit 1
130-
fi
136+
echo -e "\033[31m[error] unknown option: ${arg}\033[0m"
137+
exit 1
131138
;;
132139
esac
133140
done
134141

135-
if [ ${#MODES[@]} -eq 0 ]; then
136-
MODES=("Release")
137-
fi
138-
139-
if [[ -z "$SOURCE_ROOT_DIR" ]]; then
140-
SOURCE_ROOT_DIR=$(pwd)
141-
fi
142-
143-
if [[ -z "$TOOLCHAIN" ]]; then
144-
TOOLCHAIN="$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake"
145-
fi
146-
[[ -f "$TOOLCHAIN" ]] || { echo >&2 "Toolchain file $TOOLCHAIN does not exist."; exit 1; }
147-
148-
BUCK2=$("$PYTHON" "$SOURCE_ROOT_DIR/tools/cmake/resolve_buck.py" --cache_dir="$SOURCE_ROOT_DIR/buck2-bin")
149-
150-
if [[ "$BUCK2" == "buck2" ]]; then
151-
BUCK2=$(command -v buck2)
152-
fi
153-
154-
check_command() {
155-
if [[ "$1" == */* ]]; then
156-
if [[ ! -x "$1" ]]; then
157-
echo "Error: Command not found or not executable at '$1'" >&2
158-
exit 1
159-
fi
160-
else
161-
if ! command -v "$1" >/dev/null 2>&1; then
162-
echo "Error: Command '$1' not found in PATH" >&2
163-
exit 1
164-
fi
165-
fi
166-
}
167-
168-
check_command cmake
169-
check_command rsync
170-
check_command "$PYTHON"
171-
check_command "$BUCK2"
172-
173142
echo "Building libraries"
174143

175-
rm -rf "$OUTPUT" && mkdir -p "$OUTPUT" && cd "$OUTPUT" || exit 1
176-
177-
cmake_build() {
178-
local platform=$1
179-
local platform_flag=$2
180-
local platform_target=$3
181-
local mode=$4
182-
echo "Building for $platform ($mode) with flag $platform_flag"
183-
mkdir -p "$platform" && cd "$platform" || exit 1
184-
cmake "$SOURCE_ROOT_DIR" -G Xcode \
185-
-DCMAKE_BUILD_TYPE="$mode" \
186-
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" \
187-
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD="c++17" \
188-
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY="libc++" \
189-
-DCMAKE_C_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \
190-
-DCMAKE_CXX_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \
191-
-DPYTHON_EXECUTABLE="$PYTHON" \
192-
-DEXECUTORCH_BUILD_COREML=$COREML \
193-
-DEXECUTORCH_BUILD_MPS=$MPS \
194-
-DEXECUTORCH_BUILD_XNNPACK=$XNNPACK \
195-
-DEXECUTORCH_XNNPACK_SHARED_WORKSPACE=ON \
196-
-DEXECUTORCH_BUILD_EXECUTOR_RUNNER=OFF \
197-
-DEXECUTORCH_BUILD_EXTENSION_APPLE=ON \
198-
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
199-
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
200-
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
201-
-DEXECUTORCH_BUILD_KERNELS_CUSTOM=$CUSTOM \
202-
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=$OPTIMIZED \
203-
-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=$QUANTIZED \
204-
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)" \
205-
${platform_flag:+-DPLATFORM=$platform_flag} \
206-
${platform_target:+-DDEPLOYMENT_TARGET=$platform_target} \
207-
--log-level=VERBOSE
208-
cmake --build . \
209-
--config "$mode" \
210-
--verbose
211-
cd -
212-
}
213-
214-
for index in ${!PLATFORMS[*]}; do
144+
rm -rf "${OUTPUT_DIR}"
145+
for preset in "${PRESETS[@]}"; do
215146
for mode in "${MODES[@]}"; do
216-
cmake_build "${PLATFORMS[$index]}" "${PLATFORM_FLAGS[$index]}" "${PLATFORM_TARGET[$index]}" "$mode"
147+
output_dir="${OUTPUT_DIR}/${preset}"
148+
echo "Building preset ${preset} (${mode}) in ${output_dir}..."
149+
150+
# Do NOT add options here. Update the respective presets instead.
151+
cmake -S "${SOURCE_ROOT_DIR}" \
152+
-B "${output_dir}" \
153+
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="${output_dir}" \
154+
-DCMAKE_BUILD_TYPE="${mode}" \
155+
${CMAKE_OPTIONS_OVERRIDE[@]:-} \
156+
--preset "${preset}"
157+
158+
cmake --build "${output_dir}" \
159+
--config "${mode}" \
160+
-j$(sysctl -n hw.ncpu)
217161
done
218162
done
219163

220164
echo "Exporting headers"
221165

222-
mkdir -p "$HEADERS_PATH"
166+
mkdir -p "$HEADERS_ABSOLUTE_PATH"
223167

224168
"$SOURCE_ROOT_DIR"/scripts/print_exported_headers.py --buck2=$(realpath "$BUCK2") --targets \
225169
//extension/module: \
226170
//extension/tensor: \
227-
| rsync -av --files-from=- "$SOURCE_ROOT_DIR" "$HEADERS_PATH/executorch"
171+
| rsync -av --files-from=- "$SOURCE_ROOT_DIR" "$HEADERS_ABSOLUTE_PATH/executorch"
228172

229173
# HACK: XCFrameworks don't appear to support exporting any build
230174
# options, but we need the following:
@@ -234,13 +178,14 @@ mkdir -p "$HEADERS_PATH"
234178
sed -i '' '1i\
235179
#define C10_USING_CUSTOM_GENERATED_MACROS
236180
' \
237-
"$HEADERS_PATH/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h" \
238-
"$HEADERS_PATH/executorch/runtime/core/portable_type/c10/c10/macros/Export.h"
181+
"$HEADERS_ABSOLUTE_PATH/executorch/runtime/core/portable_type/c10/c10/macros/Macros.h" \
182+
"$HEADERS_ABSOLUTE_PATH/executorch/runtime/core/portable_type/c10/c10/macros/Export.h"
239183

240-
cp -r $HEADERS_PATH/executorch/runtime/core/portable_type/c10/c10 "$HEADERS_PATH/"
184+
cp -r $HEADERS_ABSOLUTE_PATH/executorch/runtime/core/portable_type/c10/c10 "$HEADERS_ABSOLUTE_PATH/"
241185

242-
cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.h "$HEADERS_PATH/executorch"
243-
cat > "$HEADERS_PATH/module.modulemap" << 'EOF'
186+
cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.h "$HEADERS_ABSOLUTE_PATH/executorch"
187+
188+
cat > "$HEADERS_ABSOLUTE_PATH/module.modulemap" << 'EOF'
244189
module ExecuTorch {
245190
umbrella header "ExecuTorch/ExecuTorch.h"
246191
export *
@@ -250,47 +195,56 @@ EOF
250195
echo "Creating frameworks"
251196

252197
append_framework_flag() {
253-
local flag="$1"
198+
local option_name="$1"
254199
local framework="$2"
255-
local mode="${3:-}"
256-
if [[ $flag == ON ]]; then
257-
if [[ -n "$mode" && "$mode" != "Release" ]]; then
200+
local mode="$3"
201+
202+
if [[ ${#CMAKE_OPTIONS_OVERRIDE[@]} -gt 0 && -n "$option_name" ]]; then
203+
for cmake_option in "${CMAKE_OPTIONS_OVERRIDE[@]}"; do
204+
if [[ "$cmake_option" =~ "-D${option_name}=OFF" ]]; then
205+
echo "Skipping framework: ${framework}"
206+
return
207+
fi
208+
done
209+
fi
210+
211+
if [[ -n "$mode" && "$mode" != "Release" ]]; then
258212
local name spec
259213
name=$(echo "$framework" | cut -d: -f1)
260214
spec=$(echo "$framework" | cut -d: -f2-)
261215
framework="${name}_$(echo "$mode" | tr '[:upper:]' '[:lower:]'):${spec}"
262-
fi
263-
echo "Framework: $framework"
264-
FRAMEWORK_FLAGS+=("--framework=$framework")
265216
fi
217+
echo "Adding framework: ${framework}"
218+
FRAMEWORK_FLAGS+=("--framework=$framework")
266219
}
267220

268221
for mode in "${MODES[@]}"; do
269222
FRAMEWORK_FLAGS=()
270-
for platform in "${PLATFORMS[@]}"; do
271-
echo "Directory: $platform/$mode"
272-
FRAMEWORK_FLAGS+=("--directory=$platform/$mode")
223+
for preset in "${PRESETS[@]}"; do
224+
echo "Framework directory: ${preset}/${mode}"
225+
FRAMEWORK_FLAGS+=("--directory=${preset}/${mode}")
273226
done
274227

275-
append_framework_flag "ON" "$FRAMEWORK_EXECUTORCH" "$mode"
276-
append_framework_flag "$COREML" "$FRAMEWORK_BACKEND_COREML" "$mode"
277-
append_framework_flag "$MPS" "$FRAMEWORK_BACKEND_MPS" "$mode"
278-
append_framework_flag "$XNNPACK" "$FRAMEWORK_BACKEND_XNNPACK" "$mode"
279-
append_framework_flag "$CUSTOM" "$FRAMEWORK_KERNELS_CUSTOM" "$mode"
280-
append_framework_flag "$OPTIMIZED" "$FRAMEWORK_KERNELS_OPTIMIZED" "$mode"
281-
append_framework_flag "$PORTABLE" "$FRAMEWORK_KERNELS_PORTABLE" "$mode"
282-
append_framework_flag "$QUANTIZED" "$FRAMEWORK_KERNELS_QUANTIZED" "$mode"
228+
append_framework_flag "" "$FRAMEWORK_EXECUTORCH" "$mode"
229+
append_framework_flag "EXECUTORCH_BUILD_COREML" "$FRAMEWORK_BACKEND_COREML" "$mode"
230+
append_framework_flag "EXECUTORCH_BUILD_MPS" "$FRAMEWORK_BACKEND_MPS" "$mode"
231+
append_framework_flag "EXECUTORCH_BUILD_XNNPACK" "$FRAMEWORK_BACKEND_XNNPACK" "$mode"
232+
append_framework_flag "EXECUTORCH_BUILD_KERNELS_CUSTOM" "$FRAMEWORK_KERNELS_CUSTOM" "$mode"
233+
append_framework_flag "EXECUTORCH_BUILD_KERNELS_OPTIMIZED" "$FRAMEWORK_KERNELS_OPTIMIZED" "$mode"
234+
append_framework_flag "EXECUTORCH_BUILD_PORTABLE_OPS" "$FRAMEWORK_KERNELS_PORTABLE" "$mode"
235+
append_framework_flag "EXECUTORCH_BUILD_KERNELS_QUANTIZED" "$FRAMEWORK_KERNELS_QUANTIZED" "$mode"
283236

237+
cd "${OUTPUT_DIR}"
284238
"$SOURCE_ROOT_DIR"/scripts/create_frameworks.sh "${FRAMEWORK_FLAGS[@]}"
285239
done
286240

287241
echo "Cleaning up"
288242

289-
for platform in "${PLATFORMS[@]}"; do
290-
rm -rf "$platform"
243+
for preset in "${PRESETS[@]}"; do
244+
rm -rf "${OUTPUT_DIR}/${preset}/$preset"
291245
done
292246

293-
rm -rf "$HEADERS_PATH"
247+
rm -rf "$HEADERS_ABSOLUTE_PATH"
294248

295249
echo "Running tests"
296250

0 commit comments

Comments
 (0)