1#!/bin/bash 2# Copyright 2020 The TensorFlow Authors. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# ============================================================================== 16 17set -e 18 19SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 20ROOT_DIR="$(cd "${SCRIPT_DIR}/../../../" && pwd)" 21TMP_DIR="tensorflow/lite/ios/tmp" 22 23function print_usage { 24 echo "Usage:" 25 echo " $(basename ${BASH_SOURCE}) \\" 26 echo " --input_models=model1.tflite,model2.tflite \\" 27 echo " --target_archs=x86_64,armv7,arm64" 28 echo "" 29 echo "Where: " 30 echo " --input_models: Supported TFLite models." 31 echo " --target_archs: Supported arches included in the frameworks." 32 echo " Default: x86_64,armv7,arm64. i386 architecture is currently not" 33 echo " supported." 34 echo "" 35 exit 1 36} 37 38# generate_list_field takes two positional arguments: 39# - Name of the field in the build rule. 40# - Comma-separated list of values of this field. 41# The function returns a string represents that field in the BUILD file. Ex: 42# 'name = ["value1", "value2"],' 43function generate_list_field { 44 local name="$1" 45 local list_string="$2" 46 IFS="," 47 read -ra list <<< "$list_string" 48 49 local message=("$name=[") 50 for item in "${list[@]}" 51 do 52 message+=("\"$item\",") 53 done 54 message+=('],') 55 printf '%s' "${message[@]}" 56} 57 58function print_output { 59 echo "Output can be found here:" 60 for i in "$@" 61 do 62 # ls command returns failure if the file does not exist. 63 ls -1a ${ROOT_DIR}/$i 64 done 65} 66 67function generate_tflite_framework { 68 pushd ${TMP_DIR} > /dev/null 69 # Generate the BUILD file. 70 message=( 71 'load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")' 72 'load("//tensorflow/lite:build_def.bzl", "tflite_custom_c_library")' 73 'load("//tensorflow/lite/ios:ios.bzl", "TFL_MINIMUM_OS_VERSION")' 74 'tflite_custom_c_library(' 75 ' name = "custom_c_api",' 76 ' '"$(generate_list_field "models" "$MODEL_NAMES")" 77 ')' 78 'ios_static_framework(' 79 ' name = "TensorFlowLiteC_framework",' 80 ' hdrs = [' 81 ' "//tensorflow/lite/c:c_api_types.h",' 82 ' "//tensorflow/lite/ios:common.h",' 83 ' "//tensorflow/lite/ios:c_api.h",' 84 ' "//tensorflow/lite/ios:xnnpack_delegate.h",' 85 ' ],' 86 ' bundle_name = "TensorFlowLiteC",' 87 ' minimum_os_version = TFL_MINIMUM_OS_VERSION,' 88 ' deps = [' 89 ' ":custom_c_api",' 90 ' "//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",' 91 ' ],' 92 ')' 93 ) 94 printf '%s\n' "${message[@]}" >> BUILD 95 96 # Build the framework package. 97 popd > /dev/null 98 bazel build -c opt --config=ios --ios_multi_cpus=${TARGET_ARCHS} \ 99 //${TMP_DIR}:TensorFlowLiteC_framework 100 101 OUT_FILES="${OUT_FILES} bazel-bin/${TMP_DIR}/TensorFlowLiteC_framework.zip" 102} 103 104function generate_flex_framework { 105 pushd ${TMP_DIR} 106 # Generating the BUILD file. 107 message=( 108 'load("//tensorflow/lite/delegates/flex:build_def.bzl", "tflite_flex_cc_library")' 109 'tflite_flex_cc_library(' 110 ' name = "custom_flex_delegate",' 111 ' '"$(generate_list_field "models" "$MODEL_NAMES")" 112 ')' 113 'ios_static_framework(' 114 ' name = "TensorFlowLiteSelectTfOps_framework",' 115 ' avoid_deps = ["//tensorflow/lite/c:common"],' 116 ' bundle_name = "TensorFlowLiteSelectTfOps",' 117 ' minimum_os_version = TFL_MINIMUM_OS_VERSION,' 118 ' deps = [' 119 ' ":custom_flex_delegate",' 120 ' ],' 121 ')' 122 ) 123 printf '%s\n' "${message[@]}" >> BUILD 124 popd 125 126 # Build the framework. 127 bazel build -c opt --config=ios --ios_multi_cpus=${TARGET_ARCHS} \ 128 //${TMP_DIR}:TensorFlowLiteSelectTfOps_framework 129 130 OUT_FILES="${OUT_FILES} bazel-bin/${TMP_DIR}/TensorFlowLiteSelectTfOps_framework.zip" 131} 132 133# Check command line flags. 134TARGET_ARCHS=x86_64,armv7,arm64 135 136if [ "$#" -gt 2 ]; then 137 echo "ERROR: Too many arguments." 138 print_usage 139fi 140 141for i in "$@" 142do 143case $i in 144 --input_models=*) 145 FLAG_MODELS="${i#*=}" 146 shift;; 147 --target_archs=*) 148 TARGET_ARCHS="${i#*=}" 149 shift;; 150 *) 151 echo "ERROR: Unrecognized argument: ${i}" 152 print_usage;; 153esac 154done 155 156cd $ROOT_DIR 157 158# Bazel v3.4 is required to build tensorflow python. 159if ! grep -q "3.4.0" ".bazelversion"; then 160 mv .bazelversion .bazelversion_old 161 echo "3.4.0" > .bazelversion 162fi 163 164# Check if users already run configure 165if [ ! -f "$ROOT_DIR/.tf_configure.bazelrc" ]; then 166 echo "ERROR: Please run ./configure first." 167 exit 1 168else 169 if ! grep -q "TF_CONFIGURE_IOS=\"1\"" "$ROOT_DIR/.tf_configure.bazelrc"; then 170 echo "ERROR: Please run ./configure with iOS config." 171 exit 1 172 fi 173fi 174 175# Prepare the tmp directory. 176rm -rf ${TMP_DIR} && mkdir -p ${TMP_DIR} 177 178# Copy models to tmp directory. 179MODEL_NAMES="" 180IFS="," 181read -ra MODEL_PATHS <<< "${FLAG_MODELS}" 182for model in "${MODEL_PATHS[@]}" 183do 184 cp ${model} ${TMP_DIR} 185 if [ -z "$MODEL_NAMES" ]; then 186 MODEL_NAMES="$(basename ${model})" 187 else 188 MODEL_NAMES="${MODEL_NAMES},$(basename ${model})" 189 fi 190done 191 192# Build the custom framework. 193generate_tflite_framework 194if [ -z ${FLAG_MODELS} ]; then 195 print_output ${OUT_FILES} 196 exit 0 197fi 198 199# Build flex framework if one of the models contain flex ops. 200bazel build -c opt --config=monolithic //tensorflow/lite/tools:list_flex_ops_no_kernel_main 201bazel-bin/tensorflow/lite/tools/list_flex_ops_no_kernel_main --graphs=${FLAG_MODELS} > ${TMP_DIR}/ops_list.txt 202if [[ `cat ${TMP_DIR}/ops_list.txt` != "[]" ]]; then 203 generate_flex_framework 204fi 205 206# List the output files. 207if [ ! -f ".bazelversion_old" ]; then 208 rm .bazelversion 209 mv -f .bazelversion_old .bazelversion 210fi 211rm -rf ${TMP_DIR} 212print_output ${OUT_FILES} 213