Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/apple-perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,7 @@ jobs:
echo "::endgroup::"

echo "::group::Build ExecuTorch iOS frameworks"
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh
echo "::endgroup::"

# NB: Although exported models can be copied to this directory and bundled together with the
Expand Down
6 changes: 2 additions & 4 deletions .github/workflows/apple.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ jobs:
backends/apple/mps/install_requirements.sh

# Build iOS Frameworks
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh

# Bundle iOS Frameworks
for FRAMEWORK in "${FRAMEWORKS[@]}"; do (
Expand Down Expand Up @@ -314,8 +313,7 @@ jobs:
echo "::endgroup::"

echo "::group::Build ExecuTorch iOS frameworks"
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output \
scripts/build_apple_frameworks.sh --Release --Debug --coreml --custom --mps --optimized --portable --quantized --xnnpack
PYTHON_EXECUTABLE=python ${CONDA_RUN} --no-capture-output scripts/build_apple_frameworks.sh
echo "::endgroup::"

echo "::group::Build ExecuTorch benchmark app"
Expand Down
264 changes: 109 additions & 155 deletions scripts/build_apple_frameworks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,18 @@

set -euxo pipefail

SOURCE_ROOT_DIR=""
OUTPUT="cmake-out"
MODES=()
TOOLCHAIN=""
PYTHON=$(which python3)
COREML=OFF
CUSTOM=OFF
MPS=OFF
OPTIMIZED=OFF
PORTABLE=OFF
QUANTIZED=OFF
XNNPACK=OFF
HEADERS_PATH="include"

PLATFORMS=("ios" "simulator" "macos")
PLATFORM_FLAGS=("OS64" "SIMULATORARM64" "MAC_ARM64")
PLATFORM_TARGET=("17.0" "17.0" "10.15")
MODES=("Release" "Debug")
PRESETS=("ios" "ios-simulator" "macos")

SOURCE_ROOT_DIR=$(git rev-parse --show-toplevel)
OUTPUT_DIR="${SOURCE_ROOT_DIR}/cmake-out"
HEADERS_RELATIVE_PATH="include"
HEADERS_ABSOLUTE_PATH="${OUTPUT_DIR}/${HEADERS_RELATIVE_PATH}"

BUCK2=$(python3 "$SOURCE_ROOT_DIR/tools/cmake/resolve_buck.py" --cache_dir="$SOURCE_ROOT_DIR/buck2-bin")
if [[ "$BUCK2" == "buck2" ]]; then
BUCK2=$(command -v buck2)
fi

FRAMEWORK_EXECUTORCH="executorch:\
libexecutorch.a,\
Expand All @@ -33,7 +28,7 @@ libextension_data_loader.a,\
libextension_flat_tensor.a,\
libextension_module.a,\
libextension_tensor.a,\
:$HEADERS_PATH:ExecuTorch"
:$HEADERS_RELATIVE_PATH:ExecuTorch"

FRAMEWORK_BACKEND_COREML="backend_coreml:\
libcoreml_util.a,\
Expand Down Expand Up @@ -75,33 +70,51 @@ libquantized_ops_lib.a,\
:"

usage() {
echo "Usage: $0 [SOURCE_ROOT_DIR] [OPTIONS]"
echo "Usage: $0 [OPTIONS]"
echo "Build frameworks for Apple platforms."
echo "SOURCE_ROOT_DIR defaults to the current directory if not provided."
echo
echo "Options:"
echo " --output=DIR Output directory. Default: 'cmake-out'"
echo " --Debug Build Debug version."
echo " --Release Build Release version."
echo " --toolchain=FILE CMake toolchain file. Default: '\$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake'"
echo " --python=FILE Python executable path. Default: Path of python3 in \$PATH"
echo " --coreml Build the Core ML backend."
echo " --custom Build the Custom kernels."
echo " --mps Build the Metal Performance Shaders backend."
echo " --optimized Build the Optimized kernels."
echo " --portable Build the Portable kernels."
echo " --quantized Build the Quantized kernels."
echo " --xnnpack Build the XNNPACK backend."
echo " --coreml Only build the Core ML backend."
echo " --custom Only build the Custom kernels."
echo " --mps Only build the Metal Performance Shaders backend."
echo " --optimized Only build the Optimized kernels."
echo " --portable Only build the Portable kernels."
echo " --quantized Only build the Quantized kernels."
echo " --xnnpack Only build the XNNPACK backend."
echo
echo "Example:"
echo " $0 /path/to/source/root --output=cmake-out --toolchain=/path/to/toolchain --python=/path/to/python3 --coreml --mps --xnnpack"
exit 0
}

CMAKE_OPTIONS_OVERRIDE=()
set_cmake_options_override() {
local option_name="$1"

if [[ ${#CMAKE_OPTIONS_OVERRIDE[@]} -eq 0 ]]; then
# Since the user wants specific options, turn everything off
CMAKE_OPTIONS_OVERRIDE=(
"-DEXECUTORCH_BUILD_COREML=OFF"
"-DEXECUTORCH_BUILD_KERNELS_CUSTOM=OFF"
"-DEXECUTORCH_BUILD_MPS=OFF"
"-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=OFF"
"-DEXECUTORCH_BUILD_PORTABLE_OPS=OFF"
"-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=OFF"
"-DEXECUTORCH_BUILD_XNNPACK=OFF"
)
fi

for i in "${!CMAKE_OPTIONS_OVERRIDE[@]}"; do
if [[ "${CMAKE_OPTIONS_OVERRIDE[$i]}" =~ "-D${option_name}=OFF" ]]; then
CMAKE_OPTIONS_OVERRIDE[$i]="-D${option_name}=ON"
break
fi
done
}

for arg in "$@"; do
case $arg in
-h|--help) usage ;;
--output=*) OUTPUT="${arg#*=}" ;;
--Release)
if [[ ! " ${MODES[*]:-} " =~ \bRelease\b ]]; then
MODES+=("Release")
Expand All @@ -112,119 +125,50 @@ for arg in "$@"; do
MODES+=("Debug")
fi
;;
--toolchain=*) TOOLCHAIN="${arg#*=}" ;;
--python=*) PYTHON="${arg#*=}" ;;
--coreml) COREML=ON ;;
--custom) CUSTOM=ON ;;
--mps) MPS=ON ;;
--optimized) OPTIMIZED=ON ;;
--portable) PORTABLE=ON ;;
--quantized) QUANTIZED=ON ;;
--xnnpack) XNNPACK=ON ;;
--coreml) set_cmake_options_override "EXECUTORCH_BUILD_COREML";;
--custom) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_CUSTOM" ;;
--mps) set_cmake_options_override "EXECUTORCH_BUILD_MPS" ;;
--optimized) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_OPTIMIZED" ;;
--portable) set_cmake_options_override "EXECUTORCH_BUILD_PORTABLE_OPS" ;;
--quantized) set_cmake_options_override "EXECUTORCH_BUILD_KERNELS_QUANTIZED" ;;
--xnnpack) set_cmake_options_override "EXECUTORCH_BUILD_XNNPACK" ;;
*)
if [[ -z "$SOURCE_ROOT_DIR" ]]; then
SOURCE_ROOT_DIR="$arg"
else
echo "Invalid argument: $arg"
exit 1
fi
echo -e "\033[31m[error] unknown option: ${arg}\033[0m"
exit 1
;;
esac
done

if [ ${#MODES[@]} -eq 0 ]; then
MODES=("Release")
fi

if [[ -z "$SOURCE_ROOT_DIR" ]]; then
SOURCE_ROOT_DIR=$(pwd)
fi

if [[ -z "$TOOLCHAIN" ]]; then
TOOLCHAIN="$SOURCE_ROOT_DIR/third-party/ios-cmake/ios.toolchain.cmake"
fi
[[ -f "$TOOLCHAIN" ]] || { echo >&2 "Toolchain file $TOOLCHAIN does not exist."; exit 1; }

BUCK2=$("$PYTHON" "$SOURCE_ROOT_DIR/tools/cmake/resolve_buck.py" --cache_dir="$SOURCE_ROOT_DIR/buck2-bin")

if [[ "$BUCK2" == "buck2" ]]; then
BUCK2=$(command -v buck2)
fi

check_command() {
if [[ "$1" == */* ]]; then
if [[ ! -x "$1" ]]; then
echo "Error: Command not found or not executable at '$1'" >&2
exit 1
fi
else
if ! command -v "$1" >/dev/null 2>&1; then
echo "Error: Command '$1' not found in PATH" >&2
exit 1
fi
fi
}

check_command cmake
check_command rsync
check_command "$PYTHON"
check_command "$BUCK2"

echo "Building libraries"

rm -rf "$OUTPUT" && mkdir -p "$OUTPUT" && cd "$OUTPUT" || exit 1

cmake_build() {
local platform=$1
local platform_flag=$2
local platform_target=$3
local mode=$4
echo "Building for $platform ($mode) with flag $platform_flag"
mkdir -p "$platform" && cd "$platform" || exit 1
cmake "$SOURCE_ROOT_DIR" -G Xcode \
-DCMAKE_BUILD_TYPE="$mode" \
-DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD="c++17" \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY="libc++" \
-DCMAKE_C_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \
-DCMAKE_CXX_FLAGS="-ffile-prefix-map=$SOURCE_ROOT_DIR=/executorch -fdebug-prefix-map=$SOURCE_ROOT_DIR=/executorch" \
-DPYTHON_EXECUTABLE="$PYTHON" \
-DEXECUTORCH_BUILD_COREML=$COREML \
-DEXECUTORCH_BUILD_MPS=$MPS \
-DEXECUTORCH_BUILD_XNNPACK=$XNNPACK \
-DEXECUTORCH_XNNPACK_SHARED_WORKSPACE=ON \
-DEXECUTORCH_BUILD_EXECUTOR_RUNNER=OFF \
-DEXECUTORCH_BUILD_EXTENSION_APPLE=ON \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_BUILD_KERNELS_CUSTOM=$CUSTOM \
-DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=$OPTIMIZED \
-DEXECUTORCH_BUILD_KERNELS_QUANTIZED=$QUANTIZED \
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)" \
${platform_flag:+-DPLATFORM=$platform_flag} \
${platform_target:+-DDEPLOYMENT_TARGET=$platform_target} \
--log-level=VERBOSE
cmake --build . \
--config "$mode" \
--verbose
cd -
}

for index in ${!PLATFORMS[*]}; do
rm -rf "${OUTPUT_DIR}"
for preset in "${PRESETS[@]}"; do
for mode in "${MODES[@]}"; do
cmake_build "${PLATFORMS[$index]}" "${PLATFORM_FLAGS[$index]}" "${PLATFORM_TARGET[$index]}" "$mode"
output_dir="${OUTPUT_DIR}/${preset}"
echo "Building preset ${preset} (${mode}) in ${output_dir}..."

# Do NOT add options here. Update the respective presets instead.
cmake -S "${SOURCE_ROOT_DIR}" \
-B "${output_dir}" \
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="${output_dir}" \
-DCMAKE_BUILD_TYPE="${mode}" \
${CMAKE_OPTIONS_OVERRIDE[@]:-} \
--preset "${preset}"

cmake --build "${output_dir}" \
--config "${mode}" \
-j$(sysctl -n hw.ncpu)
done
done

echo "Exporting headers"

mkdir -p "$HEADERS_PATH"
mkdir -p "$HEADERS_ABSOLUTE_PATH"

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

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

cp -r $HEADERS_PATH/executorch/runtime/core/portable_type/c10/c10 "$HEADERS_PATH/"
cp -r $HEADERS_ABSOLUTE_PATH/executorch/runtime/core/portable_type/c10/c10 "$HEADERS_ABSOLUTE_PATH/"

cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.h "$HEADERS_PATH/executorch"
cat > "$HEADERS_PATH/module.modulemap" << 'EOF'
cp "$SOURCE_ROOT_DIR/extension/apple/ExecuTorch/Exported/"*.h "$HEADERS_ABSOLUTE_PATH/executorch"

cat > "$HEADERS_ABSOLUTE_PATH/module.modulemap" << 'EOF'
module ExecuTorch {
umbrella header "ExecuTorch/ExecuTorch.h"
export *
Expand All @@ -250,47 +195,56 @@ EOF
echo "Creating frameworks"

append_framework_flag() {
local flag="$1"
local option_name="$1"
local framework="$2"
local mode="${3:-}"
if [[ $flag == ON ]]; then
if [[ -n "$mode" && "$mode" != "Release" ]]; then
local mode="$3"

if [[ ${#CMAKE_OPTIONS_OVERRIDE[@]} -gt 0 && -n "$option_name" ]]; then
for cmake_option in "${CMAKE_OPTIONS_OVERRIDE[@]}"; do
if [[ "$cmake_option" =~ "-D${option_name}=OFF" ]]; then
echo "Skipping framework: ${framework}"
return
fi
done
fi

if [[ -n "$mode" && "$mode" != "Release" ]]; then
local name spec
name=$(echo "$framework" | cut -d: -f1)
spec=$(echo "$framework" | cut -d: -f2-)
framework="${name}_$(echo "$mode" | tr '[:upper:]' '[:lower:]'):${spec}"
fi
echo "Framework: $framework"
FRAMEWORK_FLAGS+=("--framework=$framework")
fi
echo "Adding framework: ${framework}"
FRAMEWORK_FLAGS+=("--framework=$framework")
}

for mode in "${MODES[@]}"; do
FRAMEWORK_FLAGS=()
for platform in "${PLATFORMS[@]}"; do
echo "Directory: $platform/$mode"
FRAMEWORK_FLAGS+=("--directory=$platform/$mode")
for preset in "${PRESETS[@]}"; do
echo "Framework directory: ${preset}/${mode}"
FRAMEWORK_FLAGS+=("--directory=${preset}/${mode}")
done

append_framework_flag "ON" "$FRAMEWORK_EXECUTORCH" "$mode"
append_framework_flag "$COREML" "$FRAMEWORK_BACKEND_COREML" "$mode"
append_framework_flag "$MPS" "$FRAMEWORK_BACKEND_MPS" "$mode"
append_framework_flag "$XNNPACK" "$FRAMEWORK_BACKEND_XNNPACK" "$mode"
append_framework_flag "$CUSTOM" "$FRAMEWORK_KERNELS_CUSTOM" "$mode"
append_framework_flag "$OPTIMIZED" "$FRAMEWORK_KERNELS_OPTIMIZED" "$mode"
append_framework_flag "$PORTABLE" "$FRAMEWORK_KERNELS_PORTABLE" "$mode"
append_framework_flag "$QUANTIZED" "$FRAMEWORK_KERNELS_QUANTIZED" "$mode"
append_framework_flag "" "$FRAMEWORK_EXECUTORCH" "$mode"
append_framework_flag "EXECUTORCH_BUILD_COREML" "$FRAMEWORK_BACKEND_COREML" "$mode"
append_framework_flag "EXECUTORCH_BUILD_MPS" "$FRAMEWORK_BACKEND_MPS" "$mode"
append_framework_flag "EXECUTORCH_BUILD_XNNPACK" "$FRAMEWORK_BACKEND_XNNPACK" "$mode"
append_framework_flag "EXECUTORCH_BUILD_KERNELS_CUSTOM" "$FRAMEWORK_KERNELS_CUSTOM" "$mode"
append_framework_flag "EXECUTORCH_BUILD_KERNELS_OPTIMIZED" "$FRAMEWORK_KERNELS_OPTIMIZED" "$mode"
append_framework_flag "EXECUTORCH_BUILD_PORTABLE_OPS" "$FRAMEWORK_KERNELS_PORTABLE" "$mode"
append_framework_flag "EXECUTORCH_BUILD_KERNELS_QUANTIZED" "$FRAMEWORK_KERNELS_QUANTIZED" "$mode"

cd "${OUTPUT_DIR}"
"$SOURCE_ROOT_DIR"/scripts/create_frameworks.sh "${FRAMEWORK_FLAGS[@]}"
done

echo "Cleaning up"

for platform in "${PLATFORMS[@]}"; do
rm -rf "$platform"
for preset in "${PRESETS[@]}"; do
rm -rf "${OUTPUT_DIR}/${preset}/$preset"
done

rm -rf "$HEADERS_PATH"
rm -rf "$HEADERS_ABSOLUTE_PATH"

echo "Running tests"

Expand Down
Loading