Add tflite_ios_static_framework rule for hiding symbols
Exposed C++ symbols might cause collisions with other libraries. PiperOrigin-RevId: 316853905 Change-Id: Ib7fd3f14fa40bc5c3e2ece0bf244cfb6e0623770
This commit is contained in:
parent
17cacd3a21
commit
80e9a8d076
@ -1,7 +1,7 @@
|
|||||||
# TensorFlow Lite for iOS
|
# TensorFlow Lite for iOS
|
||||||
|
|
||||||
load("@bazel_skylib//rules:build_test.bzl", "build_test")
|
load("@bazel_skylib//rules:build_test.bzl", "build_test")
|
||||||
load("//tensorflow/lite/experimental/ios:ios.bzl", "TFL_MINIMUM_OS_VERSION")
|
load("//tensorflow/lite/experimental/ios:ios.bzl", "TFL_MINIMUM_OS_VERSION", "tflite_ios_static_framework")
|
||||||
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
|
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
|
||||||
|
|
||||||
package(
|
package(
|
||||||
@ -11,8 +11,15 @@ package(
|
|||||||
licenses = ["notice"], # Apache 2.0
|
licenses = ["notice"], # Apache 2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sh_binary(
|
||||||
|
name = "hide_symbols_with_whitelist",
|
||||||
|
srcs = [
|
||||||
|
"hide_symbols_with_whitelist.sh",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteC_framework
|
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteC_framework
|
||||||
ios_static_framework(
|
tflite_ios_static_framework(
|
||||||
name = "TensorFlowLiteC_framework",
|
name = "TensorFlowLiteC_framework",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"//tensorflow/lite/c:c_api.h",
|
"//tensorflow/lite/c:c_api.h",
|
||||||
@ -20,6 +27,7 @@ ios_static_framework(
|
|||||||
],
|
],
|
||||||
bundle_name = "TensorFlowLiteC",
|
bundle_name = "TensorFlowLiteC",
|
||||||
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
||||||
|
whitelist_symbols_file = ":whitelist_TensorFlowLiteC.txt",
|
||||||
deps = [
|
deps = [
|
||||||
":tensorflow_lite_c",
|
":tensorflow_lite_c",
|
||||||
],
|
],
|
||||||
@ -60,16 +68,14 @@ genrule(
|
|||||||
# TensorFlowLiteC framework above in a composable way.
|
# TensorFlowLiteC framework above in a composable way.
|
||||||
#
|
#
|
||||||
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteCCoreMl_framework
|
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteCCoreMl_framework
|
||||||
ios_static_framework(
|
tflite_ios_static_framework(
|
||||||
name = "TensorFlowLiteCCoreML_framework",
|
name = "TensorFlowLiteCCoreML_framework",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
":coreml_delegate.h",
|
":coreml_delegate.h",
|
||||||
],
|
],
|
||||||
avoid_deps = [
|
|
||||||
":tensorflow_lite_c",
|
|
||||||
],
|
|
||||||
bundle_name = "TensorFlowLiteCCoreML",
|
bundle_name = "TensorFlowLiteCCoreML",
|
||||||
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
||||||
|
whitelist_symbols_file = ":whitelist_TensorFlowLiteCCoreML.txt",
|
||||||
deps = [
|
deps = [
|
||||||
"//tensorflow/lite/experimental/delegates/coreml:coreml_delegate",
|
"//tensorflow/lite/experimental/delegates/coreml:coreml_delegate",
|
||||||
],
|
],
|
||||||
@ -81,16 +87,14 @@ ios_static_framework(
|
|||||||
# TensorFlowLiteC framework above in a composable way.
|
# TensorFlowLiteC framework above in a composable way.
|
||||||
#
|
#
|
||||||
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteCMetal_framework
|
# bazel build -c opt --config=ios_fat //tensorflow/lite/experimental/ios:TensorFlowLiteCMetal_framework
|
||||||
ios_static_framework(
|
tflite_ios_static_framework(
|
||||||
name = "TensorFlowLiteCMetal_framework",
|
name = "TensorFlowLiteCMetal_framework",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"//tensorflow/lite/delegates/gpu:metal_delegate.h",
|
"//tensorflow/lite/delegates/gpu:metal_delegate.h",
|
||||||
],
|
],
|
||||||
avoid_deps = [
|
|
||||||
":tensorflow_lite_c",
|
|
||||||
],
|
|
||||||
bundle_name = "TensorFlowLiteCMetal",
|
bundle_name = "TensorFlowLiteCMetal",
|
||||||
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
minimum_os_version = TFL_MINIMUM_OS_VERSION,
|
||||||
|
whitelist_symbols_file = ":whitelist_TensorFlowLiteCMetal.txt",
|
||||||
deps = [
|
deps = [
|
||||||
"//tensorflow/lite/delegates/gpu:metal_delegate",
|
"//tensorflow/lite/delegates/gpu:metal_delegate",
|
||||||
],
|
],
|
||||||
|
135
tensorflow/lite/experimental/ios/hide_symbols_with_whitelist.sh
Executable file
135
tensorflow/lite/experimental/ios/hide_symbols_with_whitelist.sh
Executable file
@ -0,0 +1,135 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2020 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
# ==============================================================================
|
||||||
|
#
|
||||||
|
# A script to merge Mach-O object files into a single object file and hide
|
||||||
|
# their internal symbols. Only whitelisted symbols will be visible in the
|
||||||
|
# symbol table after this script.
|
||||||
|
|
||||||
|
# To run this script, you must set several variables:
|
||||||
|
# INPUT_FRAMEWORK: a zip file containing the iOS static framework.
|
||||||
|
# BUNDLE_NAME: the pod/bundle name of the iOS static framework.
|
||||||
|
# WHITELIST_FILE_PATH: contains the whitelisted symbols.
|
||||||
|
# OUTPUT: the output zip file.
|
||||||
|
|
||||||
|
# Halt on any error or any unknown variable.
|
||||||
|
set -ue
|
||||||
|
|
||||||
|
LD_DEBUGGABLE_FLAGS="-x"
|
||||||
|
# Uncomment the below to get debuggable output. This can only be done for one
|
||||||
|
# library at a time.
|
||||||
|
# LD_DEBUGGABLE_FLAGS="-d"
|
||||||
|
|
||||||
|
# Exits if C++ symbols are found in the whitelist list.
|
||||||
|
if grep -q "^__Z" "${WHITELIST_FILE_PATH}"
|
||||||
|
then
|
||||||
|
echo "ERROR: Failed in symbol hiding. This rule does not permit hiding of" \
|
||||||
|
"C++ symbols due to possible serious problems mixing symbol hiding," \
|
||||||
|
"shared libraries and the C++ runtime." \
|
||||||
|
"More info can be found in go/ios-symbols-hiding." \
|
||||||
|
"Please recheck the whitelist list and remove C++ symbols:"
|
||||||
|
echo "$(grep "^__Z" "${WHITELIST_FILE_PATH}")"
|
||||||
|
exit 1 # terminate and indicate error
|
||||||
|
fi
|
||||||
|
# Unzips the framework zip file into a temp workspace.
|
||||||
|
framework=$(mktemp -t framework -d)
|
||||||
|
unzip "${INPUT_FRAMEWORK}" -d "${framework}"/
|
||||||
|
|
||||||
|
# Executable file in the framework.
|
||||||
|
executable_file="${BUNDLE_NAME}.framework/${BUNDLE_NAME}"
|
||||||
|
|
||||||
|
# Extracts architectures from the framework binary.
|
||||||
|
archs_str=$(xcrun lipo -info "${framework}/${executable_file}" |
|
||||||
|
sed -En -e 's/^(Non-|Architectures in the )fat file: .+( is architecture| are): (.*)$/\3/p')
|
||||||
|
|
||||||
|
IFS=' ' read -r -a archs <<< "${archs_str}"
|
||||||
|
|
||||||
|
merge_cmd=(xcrun lipo)
|
||||||
|
|
||||||
|
# Merges object files and hide symbols for each architecture.
|
||||||
|
for arch in "${archs[@]}"
|
||||||
|
do
|
||||||
|
archdir=$(mktemp -t "${arch}" -d)
|
||||||
|
arch_file="${archdir}/${arch}"
|
||||||
|
|
||||||
|
# Handles the binary differently if they are fat or thin.
|
||||||
|
if [[ "${#archs[@]}" -gt 1 ]]; then
|
||||||
|
xcrun lipo "${framework}/${executable_file}" -thin "${arch}" -output "${arch_file}"
|
||||||
|
else
|
||||||
|
mv "${framework}/${executable_file}" "${arch_file}"
|
||||||
|
fi
|
||||||
|
if [[ "$arch" == "armv7" ]]; then
|
||||||
|
# Check that there are no thread local variables in the input, as they get broken.
|
||||||
|
# See b/124533863.
|
||||||
|
thread_locals=$(xcrun nm -m -g "${arch_file}" | awk '/__DATA,__thread_vars/ { print $5 }' | c++filt)
|
||||||
|
if [[ -n "${thread_locals}" ]]; then
|
||||||
|
echo
|
||||||
|
echo "WARNING: This symbol hiding script breaks thread local variables on 32-bit arm, you had:"
|
||||||
|
echo "${thread_locals}"
|
||||||
|
echo
|
||||||
|
echo "Your build will crash if these variables are actually used at runtime."
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
xcrun ar -x "${arch_file}"
|
||||||
|
mv *.o "${archdir}"/
|
||||||
|
|
||||||
|
objects_file_list=$(mktemp)
|
||||||
|
# Hides the symbols except the whitelisted ones.
|
||||||
|
find "${archdir}" -name "*.o" >> "${objects_file_list}"
|
||||||
|
|
||||||
|
# Checks whether bitcode is enabled in the framework.
|
||||||
|
all_objects_have_bitcode=true
|
||||||
|
for object_file in $(cat "$objects_file_list"); do
|
||||||
|
if otool -arch "${arch}" -l "${object_file}" | grep -q __LLVM; then
|
||||||
|
: # Do nothing
|
||||||
|
else
|
||||||
|
echo "The ${arch} in ${object_file} is NOT bitcode-enabled."
|
||||||
|
all_objects_have_bitcode=false
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ "$all_objects_have_bitcode" = "true" ]]; then
|
||||||
|
echo "The ${arch} in ${executable_file} is fully bitcode-enabled."
|
||||||
|
xcrun ld -r -bitcode_bundle -exported_symbols_list \
|
||||||
|
"${WHITELIST_FILE_PATH}" \
|
||||||
|
$LD_DEBUGGABLE_FLAGS \
|
||||||
|
-filelist "${objects_file_list}" -o "${arch_file}_processed.o"
|
||||||
|
else
|
||||||
|
echo "The ${arch} in ${executable_file} is NOT fully bitcode-enabled."
|
||||||
|
xcrun ld -r -exported_symbols_list \
|
||||||
|
"${WHITELIST_FILE_PATH}" \
|
||||||
|
$LD_DEBUGGABLE_FLAGS \
|
||||||
|
-filelist "${objects_file_list}" -o "${arch_file}_processed.o"
|
||||||
|
fi
|
||||||
|
|
||||||
|
output_object="${framework}/${arch}"
|
||||||
|
|
||||||
|
mv "${arch_file}_processed.o" "${output_object}"
|
||||||
|
rm -rf "${archdir}"
|
||||||
|
rm "${objects_file_list}"
|
||||||
|
merge_cmd+=(-arch "${arch}" "${output_object}")
|
||||||
|
done
|
||||||
|
|
||||||
|
# Repackages the processed object files.
|
||||||
|
unzip "${INPUT_FRAMEWORK}"
|
||||||
|
merge_cmd+=(-create -output "${BUNDLE_NAME}")
|
||||||
|
"${merge_cmd[@]}"
|
||||||
|
|
||||||
|
chmod +x "${BUNDLE_NAME}"
|
||||||
|
rm "${executable_file}"
|
||||||
|
mv "${BUNDLE_NAME}" "${executable_file}"
|
||||||
|
( TZ=UTC find "${BUNDLE_NAME}.framework/" -exec touch -h -t 198001010000 {} \+ )
|
||||||
|
zip --compression-method store --symlinks --recurse-paths --quiet "${OUTPUT}" "${BUNDLE_NAME}.framework/"
|
@ -1,5 +1,8 @@
|
|||||||
"""TensorFlow Lite Build Configurations for iOS"""
|
"""TensorFlow Lite Build Configurations for iOS"""
|
||||||
|
|
||||||
|
# Placeholder for Google-internal load statements.
|
||||||
|
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
|
||||||
|
|
||||||
TFL_MINIMUM_OS_VERSION = "9.0"
|
TFL_MINIMUM_OS_VERSION = "9.0"
|
||||||
|
|
||||||
# Default tags for filtering iOS targets. Targets are restricted to Apple platforms.
|
# Default tags for filtering iOS targets. Targets are restricted to Apple platforms.
|
||||||
@ -13,3 +16,58 @@ TFL_DISABLED_SANITIZER_TAGS = [
|
|||||||
"nomsan",
|
"nomsan",
|
||||||
"notsan",
|
"notsan",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# iOS static framework with symbol whitelist. Exported C++ symbbols might cause
|
||||||
|
# symbol collision with other libraries. List of symbols to whitelist can be
|
||||||
|
# generated by running `nm -m -g FRAMEWORK_LIBRARY | grep _TfLite` for framework
|
||||||
|
# built with `ios_static_framework` rule.
|
||||||
|
def tflite_ios_static_framework(
|
||||||
|
name,
|
||||||
|
bundle_name,
|
||||||
|
whitelist_symbols_file,
|
||||||
|
exclude_resources = True,
|
||||||
|
**kwargs):
|
||||||
|
"""TFLite variant of ios_static_framework with symbol hiding.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the target.
|
||||||
|
bundle_name: The name to give to the framework bundle, without the
|
||||||
|
".framework" extension. If omitted, the target's name will be used.
|
||||||
|
whitelist_symbols_file: a file including a list of whitelisted symbols,
|
||||||
|
one symbol per line.
|
||||||
|
exclude_resources: Indicates whether resources should be excluded from the
|
||||||
|
bundle. This can be used to avoid unnecessarily bundling resources if
|
||||||
|
the static framework is being distributed in a different fashion, such
|
||||||
|
as a Cocoapod.
|
||||||
|
**kwargs: Pass-through arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
preprocessed_name = "Preprocessed_" + name
|
||||||
|
ios_static_framework(
|
||||||
|
name = preprocessed_name,
|
||||||
|
bundle_name = bundle_name,
|
||||||
|
exclude_resources = exclude_resources,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
framework_target = ":{}.zip".format(preprocessed_name)
|
||||||
|
|
||||||
|
srcs = [
|
||||||
|
framework_target,
|
||||||
|
whitelist_symbols_file,
|
||||||
|
]
|
||||||
|
cmd = ("INPUT_FRAMEWORK=\"$(location " + framework_target + ")\" " +
|
||||||
|
"BUNDLE_NAME=\"" + bundle_name + "\" " +
|
||||||
|
"WHITELIST_FILE_PATH=\"$(location " + whitelist_symbols_file + ")\" " +
|
||||||
|
"OUTPUT=\"$(OUTS)\" " +
|
||||||
|
"\"$(location //tensorflow/lite/experimental/ios:hide_symbols_with_whitelist)\"")
|
||||||
|
|
||||||
|
native.genrule(
|
||||||
|
name = name,
|
||||||
|
srcs = srcs,
|
||||||
|
outs = [name + ".zip"],
|
||||||
|
cmd = cmd,
|
||||||
|
tools = [
|
||||||
|
"//tensorflow/lite/experimental/ios:hide_symbols_with_whitelist",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
_TfLite*
|
@ -0,0 +1,2 @@
|
|||||||
|
_TfLiteCoreMlDelegateCreate
|
||||||
|
_TfLiteCoreMlDelegateDelete
|
@ -0,0 +1,2 @@
|
|||||||
|
_TFLGpuDelegateCreate
|
||||||
|
_TFLGpuDelegateDelete
|
Loading…
x
Reference in New Issue
Block a user