1#!/bin/bash 2# Copyright (c) Meta Platforms, Inc. and affiliates. 3# All rights reserved. 4# 5# This source code is licensed under the BSD-style license found in the 6# LICENSE file in the root directory of this source tree. 7 8set -euo pipefail 9 10SOURCE_ROOT_DIR="" 11OUTPUT="cmake-out" 12MODE="Release" 13TOOLCHAIN="" 14PYTHON=$(which python3) 15FLATC=$(which flatc) 16COREML=OFF 17CUSTOM=OFF 18MPS=OFF 19OPTIMIZED=OFF 20PORTABLE=OFF 21QUANTIZED=OFF 22XNNPACK=OFF 23HEADERS_PATH="include" 24 25PLATFORMS=("ios" "simulator" "macos") 26PLATFORM_FLAGS=("OS64" "SIMULATORARM64" "MAC_ARM64") 27PLATFORM_TARGET=("17.0" "17.0" "10.15") 28 29FRAMEWORK_EXECUTORCH="executorch:\ 30libexecutorch.a,\ 31libexecutorch_core.a,\ 32libextension_apple.a,\ 33libextension_data_loader.a,\ 34libextension_module.a,\ 35libextension_tensor.a,\ 36:$HEADERS_PATH" 37 38FRAMEWORK_BACKEND_COREML="backend_coreml:\ 39libcoremldelegate.a,\ 40:" 41 42FRAMEWORK_BACKEND_MPS="backend_mps:\ 43libmpsdelegate.a,\ 44:" 45 46FRAMEWORK_BACKEND_XNNPACK="backend_xnnpack:\ 47libXNNPACK.a,\ 48libcpuinfo.a,\ 49libpthreadpool.a,\ 50libxnnpack_backend.a,\ 51libmicrokernels-prod.a,\ 52:" 53 54FRAMEWORK_KERNELS_CUSTOM="kernels_custom:\ 55libcustom_ops.a,\ 56:" 57 58FRAMEWORK_KERNELS_OPTIMIZED="kernels_optimized:\ 59liboptimized_kernels.a,\ 60liboptimized_native_cpu_ops_lib.a,\ 61:" 62 63FRAMEWORK_KERNELS_PORTABLE="kernels_portable:\ 64libportable_kernels.a,\ 65libportable_ops_lib.a,\ 66:" 67 68FRAMEWORK_KERNELS_QUANTIZED="kernels_quantized:\ 69libquantized_kernels.a,\ 70libquantized_ops_lib.a,\ 71:" 72 73usage() { 74 echo "Usage: $0 [SOURCE_ROOT_DIR] [OPTIONS]" 75 echo "Build frameworks for Apple platforms." 76 echo "SOURCE_ROOT_DIR defaults to the current directory if not provided." 77 echo 78 echo "Options:" 79 echo " --output=DIR Output directory. Default: 'cmake-out'" 80 echo " --Debug Use Debug build mode. Default: Uses Release build mode." 81 echo " --toolchain=FILE Cmake toolchain file. Default: '\$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake'" 82 echo " --python=FILE Python executable path. Default: Path of python3 found in the current \$PATH" 83 echo " --flatc=FILE FlatBuffers Compiler executable path. Default: Path of flatc found in the current \$PATH" 84 echo " --coreml Include this flag to build the Core ML backend." 85 echo " --custom Include this flag to build the Custom kernels." 86 echo " --mps Include this flag to build the Metal Performance Shaders backend." 87 echo " --optimized Include this flag to build the Optimized kernels." 88 echo " --portable Include this flag to build the Portable kernels." 89 echo " --quantized Include this flag to build the Quantized kernels." 90 echo " --xnnpack Include this flag to build the XNNPACK backend." 91 echo 92 echo "Example:" 93 echo " $0 /path/to/source/root --output=cmake-out --toolchain=/path/to/cmake/toolchain --python=/path/to/python3 --coreml --mps --xnnpack" 94 exit 0 95} 96 97for arg in "$@"; do 98 case $arg in 99 -h|--help) usage ;; 100 --output=*) OUTPUT="${arg#*=}" ;; 101 --Debug) MODE="Debug" ;; 102 --toolchain=*) TOOLCHAIN="${arg#*=}" ;; 103 --python=*) PYTHON="${arg#*=}" ;; 104 --flatc=*) FLATC="${arg#*=}" ;; 105 --coreml) COREML=ON ;; 106 --custom) CUSTOM=ON ;; 107 --mps) MPS=ON ;; 108 --optimized) OPTIMIZED=ON ;; 109 --portable) PORTABLE=ON ;; 110 --quantized) QUANTIZED=ON ;; 111 --xnnpack) XNNPACK=ON ;; 112 *) 113 if [[ -z "$SOURCE_ROOT_DIR" ]]; then 114 SOURCE_ROOT_DIR="$arg" 115 else 116 echo "Invalid argument: $arg" 117 exit 1 118 fi 119 ;; 120 esac 121done 122 123if [[ -z "$SOURCE_ROOT_DIR" ]]; then 124 SOURCE_ROOT_DIR=$(pwd) 125fi 126 127if [[ -z "$TOOLCHAIN" ]]; then 128 TOOLCHAIN="$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake" 129fi 130[[ -f "$TOOLCHAIN" ]] || { echo >&2 "Toolchain file $TOOLCHAIN does not exist."; exit 1; } 131 132check_command() { 133 command -v "$1" >/dev/null 2>&1 || { echo >&2 "$1 is not installed"; exit 1; } 134} 135 136check_command cmake 137check_command rsync 138check_command "$PYTHON" 139check_command "$FLATC" 140 141echo "Building libraries" 142 143rm -rf "$OUTPUT" && mkdir -p "$OUTPUT" && cd "$OUTPUT" || exit 1 144 145cmake_build() { 146 local platform=$1 147 local platform_flag=$2 148 local platform_target=$3 149 echo "Building for $platform with flag $platform_flag" 150 mkdir "$platform" && cd "$platform" || exit 1 151 cmake "$SOURCE_ROOT_DIR" -G Xcode \ 152 -DCMAKE_BUILD_TYPE="$MODE" \ 153 -DCMAKE_PREFIX_PATH="$($PYTHON -c 'import torch as _; print(_.__path__[0])')" \ 154 -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" \ 155 -DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD="c++17" \ 156 -DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY="libc++" \ 157 -DCMAKE_C_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \ 158 -DCMAKE_CXX_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \ 159 -DPYTHON_EXECUTABLE="$PYTHON" \ 160 -DFLATC_EXECUTABLE="$FLATC" \ 161 -DEXECUTORCH_BUILD_COREML=$COREML \ 162 -DEXECUTORCH_BUILD_MPS=$MPS \ 163 -DEXECUTORCH_BUILD_XNNPACK=$XNNPACK \ 164 -DEXECUTORCH_XNNPACK_SHARED_WORKSPACE=ON \ 165 -DEXECUTORCH_BUILD_EXTENSION_APPLE=ON \ 166 -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \ 167 -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \ 168 -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \ 169 -DEXECUTORCH_BUILD_KERNELS_CUSTOM=$CUSTOM \ 170 -DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=$OPTIMIZED \ 171 -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=$QUANTIZED \ 172 -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)" \ 173 ${platform_flag:+-DPLATFORM=$platform_flag} \ 174 ${platform_target:+-DDEPLOYMENT_TARGET=$platform_target} \ 175 --log-level=VERBOSE 176 cmake --build . \ 177 --config $MODE \ 178 --verbose 179 cd .. 180} 181 182for index in ${!PLATFORMS[*]}; do 183 cmake_build "${PLATFORMS[$index]}" "${PLATFORM_FLAGS[$index]}" "${PLATFORM_TARGET[$index]}" 184done 185 186echo "Exporting headers" 187 188mkdir -p "$HEADERS_PATH" 189 190# Set BUCK2 to the path of the buck2 executable in $OUTPUT/*/buck2-bin/buck2-* 191BUCK2=$(find . -type f -path '*/buck2-bin/buck2-*' | head -n 1) 192if [[ -z "$BUCK2" ]]; then 193 echo "Could not find buck2 executable in any buck2-bin directory under $OUTPUT" 194 BUCK2=$(which buck2) 195fi 196 197check_command "$BUCK2" 198 199"$SOURCE_ROOT_DIR"/build/print_exported_headers.py --buck2=$(realpath "$BUCK2") --targets \ 200 //extension/module: \ 201 //extension/tensor: \ 202| rsync -av --files-from=- "$SOURCE_ROOT_DIR" "$HEADERS_PATH/executorch" 203 204cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.h "$HEADERS_PATH/executorch" 205cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.modulemap "$HEADERS_PATH" 206 207echo "Creating frameworks" 208 209for platform in "${PLATFORMS[@]}"; do 210 echo "Directory: $platform/$MODE" 211 FRAMEWORK_FLAGS+=("--directory=$platform/$MODE") 212done 213 214append_framework_flag() { 215 local flag="$1" 216 local framework="$2" 217 if [[ $flag == ON ]]; then 218 echo "Framework: $framework" 219 FRAMEWORK_FLAGS+=("--framework=$framework") 220 fi 221} 222 223append_framework_flag "ON" "$FRAMEWORK_EXECUTORCH" 224append_framework_flag "$COREML" "$FRAMEWORK_BACKEND_COREML" 225append_framework_flag "$MPS" "$FRAMEWORK_BACKEND_MPS" 226append_framework_flag "$XNNPACK" "$FRAMEWORK_BACKEND_XNNPACK" 227append_framework_flag "$CUSTOM" "$FRAMEWORK_KERNELS_CUSTOM" 228append_framework_flag "$OPTIMIZED" "$FRAMEWORK_KERNELS_OPTIMIZED" 229append_framework_flag "$PORTABLE" "$FRAMEWORK_KERNELS_PORTABLE" 230append_framework_flag "$QUANTIZED" "$FRAMEWORK_KERNELS_QUANTIZED" 231 232"$SOURCE_ROOT_DIR"/build/create_frameworks.sh "${FRAMEWORK_FLAGS[@]}" 233 234echo "Cleaning up" 235 236for platform in "${PLATFORMS[@]}"; do 237 rm -rf "$platform" 238done 239 240rm -rf "$HEADERS_PATH" 241 242echo "Build succeeded!" 243