chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
+311
View File
@@ -0,0 +1,311 @@
# TensorFlow Lite for iOS
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
load("//tensorflow:pytype.default.bzl", "pytype_strict_binary", "pytype_strict_library")
load("//tensorflow:strict.default.bzl", "py_strict_test")
load(
"//tensorflow/lite/ios:ios.bzl",
"TFL_MINIMUM_OS_VERSION",
"strip_common_include_path_prefix",
"tflite_ios_framework",
"tflite_ios_xcframework",
)
package(
default_visibility = [
"//tensorflow/lite:__subpackages__",
],
licenses = ["notice"],
)
sh_binary(
name = "hide_symbols_with_allowlist",
srcs = [
"hide_symbols_with_allowlist.sh",
],
visibility = [
"//tensorflow/lite:__subpackages__",
"@org_tensorflow_lite_support//tensorflow_lite_support:__subpackages__",
],
)
sh_binary(
name = "hide_xcframework_symbols_with_allowlist",
srcs = [
"hide_xcframework_symbols_with_allowlist.sh",
],
visibility = [
"//tensorflow/lite:__subpackages__",
"@org_tensorflow_lite_support//tensorflow_lite_support:__subpackages__",
],
)
pytype_strict_library(
name = "extract_object_files",
srcs = [
"extract_object_files.py",
],
)
pytype_strict_binary(
name = "extract_object_files_main",
srcs = [
"extract_object_files_main.py",
],
python_version = "PY3",
srcs_version = "PY3",
visibility = [
"//tensorflow/lite:__subpackages__",
"@org_tensorflow_lite_support//tensorflow_lite_support:__subpackages__",
],
deps = [
":extract_object_files",
],
)
filegroup(
name = "extract_object_files_testdata",
srcs = glob(["testdata/**"]),
)
py_strict_test(
name = "extract_object_files_test",
srcs = [
"extract_object_files_test.py",
],
data = [
":extract_object_files_testdata",
],
python_version = "PY3",
srcs_version = "PY3",
deps = [
":extract_object_files",
"//tensorflow/python/platform:client_testlib",
"//tensorflow/python/platform:resource_loader",
"@absl_py//absl/testing:parameterized",
],
)
strip_common_include_path_prefix(
name = "strip_common_include_path_core",
hdr_labels = [
"//tensorflow/lite:builtin_ops.h",
# Here we include the paths of the actual c library headers in tensorflow/lite/core/c instead of the shim headers in tensorflow/lite/c.
"//tensorflow/lite/core/c:c_api.h",
"//tensorflow/lite/core/c:c_api_experimental.h",
"//tensorflow/lite/core/c:c_api_opaque.h",
"//tensorflow/lite/core/c:c_api_types.h",
"//tensorflow/compiler/mlir/lite/core/c:tflite_types.h",
"//tensorflow/lite/core/c:common.h",
"//tensorflow/lite/core/c:operator.h",
"//tensorflow/lite/core/async/c:types.h",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate.h",
"//tensorflow/lite/profiling/telemetry/c:profiler.h",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting.h",
],
)
strip_common_include_path_prefix(
name = "strip_common_include_path_subspecs",
hdr_labels = [
"//tensorflow/lite/delegates/coreml:coreml_delegate.h",
"//tensorflow/lite/delegates/gpu:metal_delegate.h",
],
prefix = "TensorFlowLiteC/",
)
# bazel build -c opt --config=ios_fat //tensorflow/lite/ios:TensorFlowLiteC_framework
tflite_ios_framework(
name = "TensorFlowLiteC_framework",
hdrs = [
":builtin_ops.h",
":c_api.h",
":c_api_experimental.h",
":c_api_opaque.h",
":c_api_types.h",
":common.h",
":operator.h",
":profiler.h",
":telemetry_setting.h",
":tflite_types.h",
":types.h",
":xnnpack_delegate.h",
],
allowlist_symbols_file = ":allowlist_TensorFlowLiteC.txt",
bundle_name = "TensorFlowLiteC",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
":tensorflow_lite_c",
],
)
# bazel build -c opt --config=ios //tensorflow/lite/ios:TensorFlowLiteC_xcframework
tflite_ios_xcframework(
name = "TensorFlowLiteC_xcframework",
allowlist_symbols_file = ":allowlist_TensorFlowLiteC.txt",
bundle_name = "TensorFlowLiteC",
ios = {
"simulator": [
"x86_64",
"arm64",
],
"device": ["arm64"],
},
minimum_os_versions = {"ios": TFL_MINIMUM_OS_VERSION},
public_hdrs = [
":builtin_ops.h",
":c_api.h",
":c_api_experimental.h",
":c_api_types.h",
":common.h",
":profiler.h",
":telemetry_setting.h",
":xnnpack_delegate.h",
],
tags = ["manual"], # TODO: Remove once tf is on bazel 6.x+
deps = [
":tensorflow_lite_c",
],
)
# Similar to TensorFlowLiteC_framework but this is a static framework and symbol
# hiding is not applied. Note both have the same bundle name.
ios_static_framework(
name = "TensorFlowLiteC_static_framework",
hdrs = [
":builtin_ops.h",
":c_api.h",
":c_api_experimental.h",
":c_api_opaque.h",
":c_api_types.h",
":common.h",
":operator.h",
":profiler.h",
":telemetry_setting.h",
":tflite_types.h",
":types.h",
":xnnpack_delegate.h",
],
bundle_name = "TensorFlowLiteC",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
":tensorflow_lite_c",
],
)
# This target builds the flex delegate as a separate static framework, which
# does not include the TensorFlow Lite runtime. As this target does not contain
# TensorFlow Lite runtime, it is intended to be linked along with the
# TensorFlowLiteC framework above in a composable way.
#
# The flex delegate cannot be built for i386, so it can't be built with ios_fat
# config.
#
# bazel build -c opt --config=ios --ios_multi_cpus=armv7,arm64,x86_64 //tensorflow/lite/ios:TensorFlowLiteSelectTfOps_framework
ios_static_framework(
name = "TensorFlowLiteSelectTfOps_framework",
avoid_deps = [
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/async/interop/c:types",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
],
bundle_name = "TensorFlowLiteSelectTfOps",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
"//tensorflow/lite/delegates/flex:delegate",
],
)
# This target builds the Core ML delegate as a separate static framework, which
# does not include the TensorFlow Lite runtime. As this target does not contain
# TensorFlow Lite runtime, it is intended to be linked along with the
# TensorFlowLiteC framework above in a composable way.
#
# bazel build -c opt --config=ios_fat //tensorflow/lite/ios:TensorFlowLiteCCoreML_framework
tflite_ios_framework(
name = "TensorFlowLiteCCoreML_framework",
hdrs = [
":coreml_delegate.h",
],
allowlist_symbols_file = ":allowlist_TensorFlowLiteCCoreML.txt",
bundle_name = "TensorFlowLiteCCoreML",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
"//tensorflow/lite/delegates/coreml:coreml_delegate",
],
)
# This target builds the Metal delegate as a separate static framework, which
# does not include the TensorFlow Lite runtime. As this target does not contain
# TensorFlow Lite runtime, it is intended to be linked along with the
# TensorFlowLiteC framework above in a composable way.
#
# bazel build -c opt --config=ios_fat //tensorflow/lite/ios:TensorFlowLiteCMetal_framework
tflite_ios_framework(
name = "TensorFlowLiteCMetal_framework",
hdrs = [
":metal_delegate.h",
],
allowlist_symbols_file = ":allowlist_TensorFlowLiteCMetal.txt",
bundle_name = "TensorFlowLiteCMetal",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
"//tensorflow/lite/delegates/gpu:metal_delegate",
],
)
cc_library(
name = "tensorflow_lite_c",
hdrs = [
"//tensorflow/compiler/mlir/lite/core/c:tflite_types.h",
"//tensorflow/lite:builtin_ops.h",
"//tensorflow/lite/core/async/c:types.h",
"//tensorflow/lite/core/c:c_api.h",
"//tensorflow/lite/core/c:c_api_experimental.h",
"//tensorflow/lite/core/c:c_api_opaque.h",
"//tensorflow/lite/core/c:c_api_types.h",
"//tensorflow/lite/core/c:common.h",
"//tensorflow/lite/core/c:operator.h",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate.h",
"//tensorflow/lite/profiling/telemetry/c:profiler.h",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting.h",
],
tags = [
"nobuilder",
"swift_module=TensorFlowLiteC",
],
deps = [
"//tensorflow/compiler/mlir/lite/core/c:tflite_types",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite/core/async/c:types",
"//tensorflow/lite/core/c:c_api",
"//tensorflow/lite/core/c:c_api_experimental",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
"//tensorflow/lite/profiling/telemetry/c:profiler",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
],
)
# Used for building TensorFlowLiteC framework.
build_test(
name = "framework_build_test",
# build_test targets are not meant to be run with sanitizers.
tags = [
"noasan",
"nomsan",
"notsan",
# TODO(b/176993122): restore once the apple_genrule issue is resolved.
"notap",
"nozapfhahn",
],
targets = [
":TensorFlowLiteCCoreML_framework",
":TensorFlowLiteCMetal_framework",
":TensorFlowLiteC_framework",
":TensorFlowLiteSelectTfOps_framework",
":TensorFlowLiteC_static_framework",
],
)
+31
View File
@@ -0,0 +1,31 @@
/* Copyright 2022 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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_IOS_TENSORFLOWLITEC_H_
#define TENSORFLOW_LITE_IOS_TENSORFLOWLITEC_H_
#include "tensorflow/compiler/mlir/lite/core/c/tflite_types.h"
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/core/async/c/types.h"
#include "tensorflow/lite/core/c/c_api.h"
#include "tensorflow/lite/core/c/c_api_experimental.h"
#include "tensorflow/lite/core/c/c_api_opaque.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/c/operator.h"
#include "tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h"
#include "tensorflow/lite/profiling/telemetry/c/profiler.h"
#endif // TENSORFLOW_LITE_IOS_TENSORFLOWLITEC_H_
+7
View File
@@ -0,0 +1,7 @@
# TensorFlow Lite for iOS
- For Swift developers, add the `TensorFlowLiteSwift` pod to your Podfile. For
Objective-C developers, add `TensorFlowLiteObjC`. See the TensorFlow Lite
[Swift](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/swift)
and
[ObjC](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/objc)
directories for more details.
@@ -0,0 +1,49 @@
Pod::Spec.new do |s|
s.name = 'TensorFlowLiteC'
s.version = '2.14.0'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache' }
s.homepage = 'https://github.com/tensorflow/tensorflow'
s.source = { :http => "https://dl.google.com/tflite-release/ios/prod/tensorflow/lite/release/ios/release/30/20231002-210715/TensorFlowLiteC/2.14.0/883c6fc838e0354b/TensorFlowLiteC-2.14.0.tar.gz" }
s.summary = 'TensorFlow Lite'
s.description = <<-DESC
An internal-only pod containing the TensorFlow Lite C library that the public
`TensorFlowLiteSwift` and `TensorFlowLiteObjC` pods depend on. This pod is not
intended to be used directly. Swift developers should use the
`TensorFlowLiteSwift` pod and Objective-C developers should use the
`TensorFlowLiteObjC` pod.
DESC
s.cocoapods_version = '>= 1.9.0'
s.ios.deployment_target = '12.0'
s.module_name = 'TensorFlowLiteC'
s.library = 'c++'
s.pod_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386'
}
s.user_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386'
}
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.vendored_frameworks = 'Frameworks/TensorFlowLiteC.xcframework'
end
s.subspec 'CoreML' do |coreml|
coreml.weak_framework = 'CoreML'
coreml.dependency 'TensorFlowLiteC/Core'
coreml.vendored_frameworks = 'Frameworks/TensorFlowLiteCCoreML.xcframework'
end
s.subspec 'Metal' do |metal|
metal.weak_framework = 'Metal'
metal.dependency 'TensorFlowLiteC/Core'
metal.vendored_frameworks = 'Frameworks/TensorFlowLiteCMetal.xcframework'
end
end
@@ -0,0 +1,56 @@
Pod::Spec.new do |s|
s.name = '${POD_NAME}'
s.version = '${TFL_BUILD_VERSION}'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache' }
s.homepage = 'https://github.com/tensorflow/tensorflow'
s.source = { :http => "${TFL_DOWNLOAD_URL}" }
s.summary = 'TensorFlow Lite'
s.description = <<-DESC
An internal-only pod containing the TensorFlow Lite C library that the public
`TensorFlowLiteSwift` and `TensorFlowLiteObjC` pods depend on. This pod is not
intended to be used directly. Swift developers should use the
`TensorFlowLiteSwift` pod and Objective-C developers should use the
`TensorFlowLiteObjC` pod.
DESC
s.cocoapods_version = '>= ${TFL_MIN_COCOAPODS_VERSION}'
s.ios.deployment_target = '12.0'
s.module_name = 'TensorFlowLiteC'
s.library = 'c++'
# TODO: Remove this after adding support for arm64 simulator.
s.pod_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO',
}
# TODO: Remove this after adding support for arm64 simulator.
s.user_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386',
'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO',
}
s.default_subspec = 'Core'
s.subspec 'Core' do |core|
core.vendored_frameworks = 'Frameworks/TensorFlowLiteC.xcframework'
core.resource_bundle = { 'TensorFlowLiteC' => 'Frameworks/TensorFlowLiteC.xcframework/PrivacyInfo.xcprivacy' }
end
s.subspec 'CoreML' do |coreml|
coreml.weak_framework = 'CoreML'
coreml.dependency "#{s.name}/Core"
coreml.vendored_frameworks = 'Frameworks/TensorFlowLiteCCoreML.xcframework'
coreml.resource_bundle = { 'TensorFlowLiteCCoreML' => 'Frameworks/TensorFlowLiteCCoreML.xcframework/PrivacyInfo.xcprivacy' }
end
s.subspec 'Metal' do |metal|
metal.weak_framework = 'Metal'
metal.dependency "#{s.name}/Core"
metal.vendored_frameworks = 'Frameworks/TensorFlowLiteCMetal.xcframework'
metal.resource_bundle = { 'TensorFlowLiteCMetal' => 'Frameworks/TensorFlowLiteCMetal.xcframework/PrivacyInfo.xcprivacy' }
end
end
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,19 @@
# TensorFlow Lite with Select TensorFlow ops
For enabling the Select TensorFlow ops for your TensorFlow Lite app, please add
the `TensorFlowLiteSelectTfOps` pod to your Podfile, in addition to
`TensorFlowLiteSwift` or `TensorFlowLiteObjC` pod, depending on your primary
language.
After that, you should also force load the framework from your project. Add the
following line to the `Other Linker Flags` under your project's Build Settings
page.
```
-force_load "$(PROJECT_DIR)/Pods/TensorFlowLiteSelectTfOps/Frameworks/TensorFlowLiteSelectTfOps.framework/TensorFlowLiteSelectTfOps"
```
Please refer to the [Select operators from TensorFlow][ops-select] guide for
more details.
[ops-select]: https://www.tensorflow.org/lite/guide/ops_select#ios
@@ -0,0 +1,33 @@
Pod::Spec.new do |s|
s.name = 'TensorFlowLiteSelectTfOps'
s.version = '2.14.0'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache' }
s.homepage = 'https://github.com/tensorflow/tensorflow'
s.source = { :http => "https://dl.google.com/tflite-release/ios/prod/tensorflow/lite/release/ios/release/30/20231002-210715/TensorFlowLiteSelectTfOps/2.14.0/e43d76a7247eec5c/TensorFlowLiteSelectTfOps-2.14.0.tar.gz" }
s.summary = 'TensorFlow Lite'
s.description = <<-DESC
This pod can be used in addition to `TensorFlowLiteSwift` or
`TensorFlowLiteObjC` pod, in order to enable Select TensorFlow ops. The
resulting binary should also be force-loaded to the final app binary.
DESC
s.cocoapods_version = '>= 1.9.0'
s.ios.deployment_target = '11.0'
s.module_name = 'TensorFlowLiteSelectTfOps'
s.library = 'c++'
s.vendored_frameworks = 'Frameworks/TensorFlowLiteSelectTfOps.xcframework'
s.weak_frameworks = 'CoreML'
# TODO(b/149803849): Remove this after adding support for simulators.
s.pod_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386 x86_64 arm64'
}
# TODO(b/149803849): Remove this after adding support for simulators.
s.user_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386 x86_64 arm64'
}
end
@@ -0,0 +1,36 @@
Pod::Spec.new do |s|
s.name = '${POD_NAME}'
s.version = '${TFL_BUILD_VERSION}'
s.authors = 'Google Inc.'
s.license = { :type => 'Apache' }
s.homepage = 'https://github.com/tensorflow/tensorflow'
s.source = { :http => "${TFL_DOWNLOAD_URL}" }
s.summary = 'TensorFlow Lite'
s.description = <<-DESC
This pod can be used in addition to `TensorFlowLiteSwift` or
`TensorFlowLiteObjC` pod, in order to enable Select TensorFlow ops. The
resulting binary should also be force-loaded to the final app binary.
DESC
s.cocoapods_version = '>= ${TFL_MIN_COCOAPODS_VERSION}'
s.ios.deployment_target = '12.0'
s.module_name = 'TensorFlowLiteSelectTfOps'
s.library = 'c++'
s.vendored_frameworks = 'Frameworks/TensorFlowLiteSelectTfOps.xcframework'
s.resource_bundle = { 'TensorFlowLiteSelectTfOps' => 'Frameworks/TensorFlowLiteSelectTfOps.xcframework/PrivacyInfo.xcprivacy' }
s.weak_frameworks = 'CoreML'
# TODO(b/149803849): Remove this after adding support for simulators.
s.pod_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386 x86_64 arm64',
'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO',
}
# TODO(b/149803849): Remove this after adding support for simulators.
s.user_target_xcconfig = {
'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386 x86_64 arm64',
'ENABLE_USER_SCRIPT_SANDBOXING' => 'NO',
}
end
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,2 @@
_TfLite*
*AcquireFlexDelegate*
@@ -0,0 +1,2 @@
_TfLiteCoreMlDelegateCreate
_TfLiteCoreMlDelegateDelete
@@ -0,0 +1,4 @@
_TFLGpuDelegateOptionsDefault
_TFLGpuDelegateCreate
_TFLGpuDelegateDelete
_TFLGpuDelegateBindMetalBufferToTensor
+212
View File
@@ -0,0 +1,212 @@
#!/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.
# ==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/../../../" && pwd)"
TMP_DIR="tensorflow/lite/ios/tmp"
OUT_FILES=()
function print_usage {
echo "Usage:"
echo " $(basename ${BASH_SOURCE}) \\"
echo " --input_models=model1.tflite,model2.tflite \\"
echo " --target_archs=x86_64,armv7,arm64"
echo ""
echo "Where: "
echo " --input_models: Supported TFLite models."
echo " --target_archs: Supported arches included in the frameworks."
echo " Default: x86_64,armv7,arm64. i386 architecture is currently not"
echo " supported."
echo ""
exit 1
}
# generate_list_field takes two positional arguments:
# - Name of the field in the build rule.
# - Comma-separated list of values of this field.
# The function returns a string represents that field in the BUILD file. Ex:
# 'name = ["value1", "value2"],'
function generate_list_field {
local name="$1"
local list_string="$2"
IFS=","
read -ra list <<< "$list_string"
local message=("$name=[")
for item in "${list[@]}"
do
message+=("\"$item\",")
done
message+=('],')
printf '%s' "${message[@]}"
}
# get_output_file_path takes one bazel target label as an argument, and prints
# the path of the first output file of the specified target.
function get_output_file_path {
local starlark_file="${TMP_DIR}/print_output_file.starlark"
cat > "${starlark_file}" << EOF
def format(target):
return target.files.to_list()[0].path
EOF
bazel cquery --config=ios $1 \
--output=starlark --starlark:file="${starlark_file}" 2> /dev/null
}
function print_output {
echo "Output can be found here:"
for i in "${OUT_FILES[@]}"
do
# ls command returns failure if the file does not exist.
ls -1a ${ROOT_DIR}/$i
done
}
function generate_tflite_framework {
pushd ${TMP_DIR} > /dev/null
# Generate the BUILD file.
message=(
'load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")'
'load("//tensorflow/lite:build_def.bzl", "tflite_custom_cc_library")'
'load("//tensorflow/lite/ios:ios.bzl", "TFL_MINIMUM_OS_VERSION")'
'tflite_custom_cc_library('
' name = "custom_c_api",'
' deps = ['
' "//tensorflow/lite/kernels:builtin_ops_list",'
' ],'
' '"$(generate_list_field "models" "$MODEL_NAMES")"
')'
'ios_static_framework('
' name = "TensorFlowLiteC_framework",'
' hdrs = ['
' "//tensorflow/lite/c:c_api_types.h",'
' "//tensorflow/lite/ios:common.h",'
' "//tensorflow/lite/ios:c_api.h",'
' "//tensorflow/lite/ios:xnnpack_delegate.h",'
' ],'
' bundle_name = "TensorFlowLiteC",'
' minimum_os_version = TFL_MINIMUM_OS_VERSION,'
' deps = ['
' ":custom_c_api",'
' "//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",'
' ],'
')'
)
printf '%s\n' "${message[@]}" >> BUILD
# Build the framework package.
local target="//${TMP_DIR}:TensorFlowLiteC_framework"
popd > /dev/null
bazel build -c opt --config=ios --ios_multi_cpus="${TARGET_ARCHS}" "${target}"
OUT_FILES+=($(get_output_file_path "${target}"))
}
function generate_flex_framework {
pushd ${TMP_DIR}
# Generating the BUILD file.
message=(
'load("//tensorflow/lite/delegates/flex:build_def.bzl", "tflite_flex_cc_library")'
'tflite_flex_cc_library('
' name = "custom_flex_delegate",'
' '"$(generate_list_field "models" "$MODEL_NAMES")"
')'
'ios_static_framework('
' name = "TensorFlowLiteSelectTfOps_framework",'
' avoid_deps = ["//tensorflow/lite/c:common"],'
' bundle_name = "TensorFlowLiteSelectTfOps",'
' minimum_os_version = TFL_MINIMUM_OS_VERSION,'
' deps = ['
' ":custom_flex_delegate",'
' ],'
')'
)
printf '%s\n' "${message[@]}" >> BUILD
popd
# Build the framework.
local target="//${TMP_DIR}:TensorFlowLiteSelectTfOps_framework"
bazel build -c opt --config=ios --ios_multi_cpus="${TARGET_ARCHS}" "${target}"
OUT_FILES+=($(get_output_file_path "${target}"))
}
# Check command line flags.
TARGET_ARCHS=x86_64,armv7,arm64
if [ "$#" -gt 2 ]; then
echo "ERROR: Too many arguments."
print_usage
fi
for i in "$@"
do
case $i in
--input_models=*)
FLAG_MODELS="${i#*=}"
shift;;
--target_archs=*)
TARGET_ARCHS="${i#*=}"
shift;;
*)
echo "ERROR: Unrecognized argument: ${i}"
print_usage;;
esac
done
cd $ROOT_DIR
# Check if users ran configure with iOS enabled.
if [ ! -f "$ROOT_DIR/TensorFlowLiteObjC.podspec" ]; then
echo "ERROR: Please run ./configure with iOS config."
exit 1
fi
# Prepare the tmp directory.
rm -rf ${TMP_DIR} && mkdir -p ${TMP_DIR}
# Copy models to tmp directory.
MODEL_NAMES=""
IFS=","
read -ra MODEL_PATHS <<< "${FLAG_MODELS}"
for model in "${MODEL_PATHS[@]}"
do
cp ${model} ${TMP_DIR}
if [ -z "$MODEL_NAMES" ]; then
MODEL_NAMES="$(basename ${model})"
else
MODEL_NAMES="${MODEL_NAMES},$(basename ${model})"
fi
done
# Build the custom framework.
generate_tflite_framework
if [ -z ${FLAG_MODELS} ]; then
print_output
exit 0
fi
# Build flex framework if one of the models contain flex ops.
bazel build -c opt --config=monolithic //tensorflow/lite/tools:list_flex_ops_no_kernel_main
bazel-bin/tensorflow/lite/tools/list_flex_ops_no_kernel_main --graphs=${FLAG_MODELS} > ${TMP_DIR}/ops_list.txt
if [[ `cat ${TMP_DIR}/ops_list.txt` != "[]" ]]; then
generate_flex_framework
fi
rm -rf ${TMP_DIR}
print_output
+177
View File
@@ -0,0 +1,177 @@
# Copyright 2021 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.
# ==============================================================================
"""Module for extracting object files from a compiled archive (.a) file.
This module provides functionality almost identical to the 'ar -x' command,
which extracts out all object files from a given archive file. This module
assumes the archive is in the BSD variant format used in Apple platforms.
See: https://en.wikipedia.org/wiki/Ar_(Unix)#BSD_variant
This extractor has two important differences compared to the 'ar -x' command
shipped with Xcode.
1. When there are multiple object files with the same name in a given archive,
each file is renamed so that they are all correctly extracted without
overwriting each other.
2. This module takes the destination directory as an additional parameter.
Example Usage:
archive_path = ...
dest_dir = ...
extract_object_files(archive_path, dest_dir)
"""
import hashlib
import io
import itertools
import os
import struct
from typing import Iterator, Tuple
def extract_object_files(archive_file: io.BufferedIOBase,
dest_dir: str) -> None:
"""Extracts object files from the archive path to the destination directory.
Extracts object files from the given BSD variant archive file. The extracted
files are written to the destination directory, which will be created if the
directory does not exist.
Colliding object file names are automatically renamed upon extraction in order
to avoid unintended overwriting.
Args:
archive_file: The archive file object pointing at its beginning.
dest_dir: The destination directory path in which the extracted object files
will be written. The directory will be created if it does not exist.
"""
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
_check_archive_signature(archive_file)
# Keep the extracted file names and their content hash values, in order to
# handle duplicate names correctly.
extracted_files = dict()
for name, file_content in _extract_next_file(archive_file):
digest = hashlib.md5(file_content).digest()
# Check if the name is already used. If so, come up with a different name by
# incrementing the number suffix until it finds an unused one.
# For example, if 'foo.o' is used, try 'foo_1.o', 'foo_2.o', and so on.
for final_name in _generate_modified_filenames(name):
if final_name not in extracted_files:
extracted_files[final_name] = digest
# Write the file content to the desired final path.
with open(os.path.join(dest_dir, final_name), 'wb') as object_file:
object_file.write(file_content)
break
# Skip writing this file if the same file was already extracted.
elif extracted_files[final_name] == digest:
break
def _generate_modified_filenames(filename: str) -> Iterator[str]:
"""Generates the modified filenames with incremental name suffix added.
This helper function first yields the given filename itself, and subsequently
yields modified filenames by incrementing number suffix to the basename.
Args:
filename: The original filename to be modified.
Yields:
The original filename and then modified filenames with incremental suffix.
"""
yield filename
base, ext = os.path.splitext(filename)
for name_suffix in itertools.count(1, 1):
yield '{}_{}{}'.format(base, name_suffix, ext)
def _check_archive_signature(archive_file: io.BufferedIOBase) -> None:
"""Checks if the file has the correct archive header signature.
The cursor is moved to the first available file header section after
successfully checking the signature.
Args:
archive_file: The archive file object pointing at its beginning.
Raises:
RuntimeError: The archive signature is invalid.
"""
signature = archive_file.read(8)
if signature != b'!<arch>\n':
raise RuntimeError('Invalid archive file format.')
def _extract_next_file(
archive_file: io.BufferedIOBase) -> Iterator[Tuple[str, bytes]]:
"""Extracts the next available file from the archive.
Reads the next available file header section and yields its filename and
content in bytes as a tuple. Stops when there are no more available files in
the provided archive_file.
Args:
archive_file: The archive file object, of which cursor is pointing to the
next available file header section.
Yields:
The name and content of the next available file in the given archive file.
Raises:
RuntimeError: The archive_file is in an unknown format.
"""
while True:
header = archive_file.read(60)
if not header:
return
elif len(header) < 60:
raise RuntimeError('Invalid file header format.')
# For the details of the file header format, see:
# https://en.wikipedia.org/wiki/Ar_(Unix)#File_header
# We only need the file name and the size values.
name, _, _, _, _, size, end = struct.unpack('=16s12s6s6s8s10s2s', header)
if end != b'`\n':
raise RuntimeError('Invalid file header format.')
# Convert the bytes into more natural types.
name = name.decode('ascii').strip()
size = int(size, base=10)
odd_size = size % 2 == 1
# Handle the extended filename scheme.
if name.startswith('#1/'):
filename_size = int(name[3:])
name = archive_file.read(filename_size).decode('utf-8').strip(' \x00')
size -= filename_size
file_content = archive_file.read(size)
# The file contents are always 2 byte aligned, and 1 byte is padded at the
# end in case the size is odd.
if odd_size:
archive_file.read(1)
yield (name, file_content)
@@ -0,0 +1,37 @@
# Copyright 2021 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.
# ==============================================================================
"""Command line tool version of the extract_object_files module.
This command line tool version takes the archive file path and the destination
directory path as the positional command line arguments.
"""
import sys
from typing import Sequence
from tensorflow.lite.ios import extract_object_files
def main(argv: Sequence[str]) -> None:
if len(argv) != 3:
raise RuntimeError('Usage: {} <archive_file> <dest_dir>'.format(argv[0]))
archive_path = argv[1]
dest_dir = argv[2]
with open(archive_path, 'rb') as archive_file:
extract_object_files.extract_object_files(archive_file, dest_dir)
if __name__ == '__main__':
main(sys.argv)
@@ -0,0 +1,78 @@
# Copyright 2021 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.
# ==============================================================================
"""Tests for the extract_object_files module."""
import io
import os
import pathlib
from typing import List
from absl.testing import parameterized
from tensorflow.lite.ios import extract_object_files
from tensorflow.python.platform import resource_loader
from tensorflow.python.platform import test
class ExtractObjectFilesTest(parameterized.TestCase):
@parameterized.named_parameters(
dict(
testcase_name='Simple extraction',
dirname='simple',
object_files=['foo.o', 'bar.o']),
dict(
testcase_name='Extended filename',
dirname='extended_filename',
object_files=['short.o', 'long_file_name_with_extended_format.o']),
dict(
testcase_name='Odd bytes pad handling',
dirname='odd_bytes',
object_files=['odd.o', 'even.o']),
dict(
testcase_name='Duplicate object names should be separated out',
dirname='duplicate_names',
object_files=['foo.o', 'foo_1.o', 'foo_2.o']),
dict(
testcase_name='Exact same file should not be extracted again',
dirname='skip_same_file',
object_files=['foo.o']))
def test_extract_object_files(self, dirname: str, object_files: List[str]):
dest_dir = self.create_tempdir().full_path
input_file_relpath = os.path.join('testdata', dirname, 'input.a')
archive_path = resource_loader.get_path_to_datafile(input_file_relpath)
with open(archive_path, 'rb') as archive_file:
extract_object_files.extract_object_files(archive_file, dest_dir)
# Only the expected files should be extracted and no more.
self.assertCountEqual(object_files, os.listdir(dest_dir))
# Compare the extracted files against the expected file content.
for file in object_files:
actual = pathlib.Path(os.path.join(dest_dir, file)).read_bytes()
expected = pathlib.Path(
resource_loader.get_path_to_datafile(
os.path.join('testdata', dirname, file))).read_bytes()
self.assertEqual(actual, expected)
def test_invalid_archive(self):
with io.BytesIO(b'this is an invalid archive file') as archive_file:
with self.assertRaises(RuntimeError):
extract_object_files.extract_object_files(
archive_file,
self.create_tempdir().full_path)
if __name__ == '__main__':
test.main()
+146
View File
@@ -0,0 +1,146 @@
#!/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 allowed 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.
# ALLOWLIST_FILE_PATH: contains the allowed symbols.
# EXTRACT_SCRIPT_PATH: path to the extract_object_files script.
# OUTPUT: the output zip file.
# Halt on any error or any unknown variable.
set -ue
# mktemp from coreutils has different flags. Make sure we get the iOS one.
MKTEMP=/usr/bin/mktemp
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 allowlist.
if grep -q "^__Z" "${ALLOWLIST_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 allowlist and remove C++ symbols:"
echo "$(grep "^__Z" "${ALLOWLIST_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
if [[ ! -z "${EXTRACT_SCRIPT_PATH}" ]]; then
"${EXTRACT_SCRIPT_PATH}" "${arch_file}" "${archdir}"
else
# ar tool extracts the objects in the current working directory. Since the
# default working directory for a genrule is always the same, there can be
# a race condition when this script is called for multiple targets
# simultaneously.
pushd "${archdir}" > /dev/null
xcrun ar -x "${arch_file}"
popd > /dev/null
fi
objects_file_list=$($MKTEMP)
# Hides the symbols except the allowed 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 \
"${ALLOWLIST_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 \
"${ALLOWLIST_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/"
@@ -0,0 +1,150 @@
#!/bin/bash
# Copyright 2023 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 allowed 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.
# ALLOWLIST_FILE_PATH: contains the allowed symbols.
# EXTRACT_SCRIPT_PATH: path to the extract_object_files script.
# OUTPUT: the output zip file.
# Halt on any error or any unknown variable.
set -ue
# mktemp from coreutils has different flags. Make sure we get the iOS one.
MKTEMP=/usr/bin/mktemp
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 allowlist.
if grep -q "^__Z" "${ALLOWLIST_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 allowlist and remove C++ symbols:"
echo "$(grep "^__Z" "${ALLOWLIST_FILE_PATH}")"
exit 1 # terminate and indicate error
fi
# Unzips the framework zip file into a temp workspace.
xcframework=$($MKTEMP -t framework -d)
unzip "${INPUT_FRAMEWORK}" -d "${xcframework}"/
unzip -oqq "${INPUT_FRAMEWORK}"
for framework in "$xcframework"/*.xcframework/ios-*; do
echo "fw is $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
if [[ ! -z "${EXTRACT_SCRIPT_PATH}" ]]; then
"${EXTRACT_SCRIPT_PATH}" "${arch_file}" "${archdir}"
else
# ar tool extracts the objects in the current working directory. Since the
# default working directory for a genrule is always the same, there can be
# a race condition when this script is called for multiple targets
# simultaneously.
pushd "${archdir}" > /dev/null
xcrun ar -x "${arch_file}"
popd > /dev/null
fi
objects_file_list=$($MKTEMP)
# Hides the symbols except the allowed 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 \
"${ALLOWLIST_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 \
"${ALLOWLIST_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
merge_cmd+=(-create -output "${BUNDLE_NAME}")
"${merge_cmd[@]}"
chmod +x "${BUNDLE_NAME}"
executable_slice="${BUNDLE_NAME}.xcframework/$(basename "${framework}")/${BUNDLE_NAME}.framework/${BUNDLE_NAME}"
rm "$executable_slice"
mv "${BUNDLE_NAME}" "${executable_slice}"
done
( TZ=UTC find "${BUNDLE_NAME}.xcframework/" -exec touch -h -t 198001010000 {} \+ )
zip --compression-method store --symlinks --recurse-paths --quiet "${OUTPUT}" "${BUNDLE_NAME}.xcframework/"
+174
View File
@@ -0,0 +1,174 @@
"""TensorFlow Lite Build Configurations for iOS"""
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
# copybara:uncomment_begin(google-only)
# load("//tensorflow:tensorflow.bzl", "clean_dep")
# copybara:uncomment_end_and_comment_begin
load("//tensorflow/lite:build_def.bzl", "clean_dep")
# copybara:comment_end
# Placeholder for Google-internal load statements.
load("//tools/build_defs/apple:apple_xcframework.bzl", "apple_static_xcframework")
# LINT.IfChange
TFL_MINIMUM_OS_VERSION = "15.0"
# LINT.ThenChange(
# TensorFlowLiteC.podspec.template,
# TensorFlowLiteSelectTfOps.podspec.template,
# ../objc/TensorFlowLiteObjC.podspec.template,
# ../swift/TensorFlowLiteSwift.podspec.template
# )
# Default tags for filtering iOS targets. Targets are restricted to Apple platforms.
TFL_DEFAULT_TAGS = [
"apple",
]
# Following sanitizer tests are not supported by iOS test targets.
TFL_DISABLED_SANITIZER_TAGS = [
"noasan",
"nomsan",
"notsan",
]
# iOS framework with symbol allowlist. Exported C++ symbols might cause symbol
# collision with other libraries. List of symbols to allowlist can be
# generated by running `nm -m -g FRAMEWORK_LIBRARY | grep _TfLite` for framework
# built with `ios_static_framework` rule.
def tflite_ios_framework(
name,
bundle_name,
allowlist_symbols_file,
exclude_resources = True,
**kwargs):
"""Apply symbol hiding to the output of ios_static_framework.
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.
allowlist_symbols_file: a file including a list of allowed 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,
allowlist_symbols_file,
]
clean_dep_extract_object_files_main = clean_dep("//tensorflow/lite/ios:extract_object_files_main")
clean_dep_hide_symbols_with_allowlist = clean_dep("//tensorflow/lite/ios:hide_symbols_with_allowlist")
cmd = ("INPUT_FRAMEWORK=\"$(location " + framework_target + ")\" " +
"BUNDLE_NAME=\"" + bundle_name + "\" " +
"ALLOWLIST_FILE_PATH=\"$(location " + allowlist_symbols_file + ")\" " +
"EXTRACT_SCRIPT_PATH=\"$(location " + clean_dep_extract_object_files_main + ")\" " +
"OUTPUT=\"$(OUTS)\" " +
"\"$(location " + clean_dep_hide_symbols_with_allowlist + ")\"")
native.genrule(
name = name,
srcs = srcs,
outs = [name + ".zip"],
cmd = cmd,
tools = [
clean_dep_extract_object_files_main,
clean_dep_hide_symbols_with_allowlist,
],
)
# iOS xcframework with symbol allowlist. Exported C++ symbols might cause symbol
# collision with other libraries. List of symbols to allowlist can be
# generated by running `nm -m -g FRAMEWORK_LIBRARY | grep _TfLite` for framework
# built with `apple_static_xcframework` rule.
def tflite_ios_xcframework(
name,
bundle_name,
allowlist_symbols_file,
**kwargs):
"""Apply symbol hiding to the output of apple_static_framework.
Args:
name: The name of the target.
bundle_name: The name to give to the xcframework bundle, without the
".xcframework" extension. If omitted, the target's name will be used.
allowlist_symbols_file: a file including a list of allowed symbols,
one symbol per line.
**kwargs: Pass-through arguments.
"""
preprocessed_name = "Preprocessed_" + name
apple_static_xcframework(
name = preprocessed_name,
bundle_name = bundle_name,
**kwargs
)
xcframework_target = ":{}.xcframework.zip".format(preprocessed_name)
srcs = [
xcframework_target,
allowlist_symbols_file,
]
clean_dep_extract_object_files_main = clean_dep("//tensorflow/lite/ios:extract_object_files_main")
clean_dep_hide_symbols_with_allowlist = clean_dep("//tensorflow/lite/ios:hide_xcframework_symbols_with_allowlist")
cmd = ("INPUT_FRAMEWORK=\"$(location " + xcframework_target + ")\" " +
"BUNDLE_NAME=\"" + bundle_name + "\" " +
"ALLOWLIST_FILE_PATH=\"$(location " + allowlist_symbols_file + ")\" " +
"EXTRACT_SCRIPT_PATH=\"$(location " + clean_dep_extract_object_files_main + ")\" " +
"OUTPUT=\"$(OUTS)\" " +
"\"$(location " + clean_dep_hide_symbols_with_allowlist + ")\"")
native.genrule(
name = name,
srcs = srcs,
outs = [name + ".zip"],
cmd = cmd,
tools = [
clean_dep_extract_object_files_main,
clean_dep_hide_symbols_with_allowlist,
],
)
# When the static framework is built with bazel, the all header files are moved
# to the "Headers" directory with no header path prefixes. This auxiliary rule
# is used for stripping the path prefix of header inclusions paths from the
# provided headers.
def strip_common_include_path_prefix(name, hdr_labels, prefix = ""):
"""Create modified header files with the inclusion path prefixes removed.
Args:
name: The name to be used as a prefix to the generated genrules.
hdr_labels: List of header labels to strip out the include path. Each
label must end with a colon followed by the header file name.
prefix: Optional prefix path to prepend to the final inclusion path.
"""
for hdr_label in hdr_labels:
hdr_filename = hdr_label.split(":")[-1]
hdr_basename = hdr_filename.split(".")[0]
native.genrule(
name = "{}_{}".format(name, hdr_basename),
srcs = [hdr_label],
outs = [hdr_filename],
cmd = """
sed -E 's|#include ".*/([^/]+\\.h)"|#include "{}\\1"|g'\
"$(location {})"\
> "$@"
""".format(prefix, hdr_label),
)
+1
View File
@@ -0,0 +1 @@
first foo.o
+1
View File
@@ -0,0 +1 @@
second foo.o
+1
View File
@@ -0,0 +1 @@
third foo.o
+6
View File
@@ -0,0 +1,6 @@
!<arch>
foo.o 1609941687 12549 24403 100644 11 `
first foo.o
foo.o 1609941704 12549 24403 100644 12 `
second foo.ofoo.o 1609941712 12549 24403 100644 11 `
third foo.o
Binary file not shown.
@@ -0,0 +1 @@
long file name
@@ -0,0 +1 @@
short file content
+1
View File
@@ -0,0 +1 @@
even bytes
+5
View File
@@ -0,0 +1,5 @@
!<arch>
odd.o 1609941182 12549 24403 100664 9 `
odd bytes
even.o 1609941194 12549 24403 100664 10 `
even bytes
+1
View File
@@ -0,0 +1 @@
odd bytes
+1
View File
@@ -0,0 +1 @@
bar file content
+1
View File
@@ -0,0 +1 @@
foo file content
+4
View File
@@ -0,0 +1,4 @@
!<arch>
foo.o 1609934189 12549 24403 100664 16 `
foo file contentbar.o 1609934193 12549 24403 100664 16 `
bar file content
+1
View File
@@ -0,0 +1 @@
foo file content
+4
View File
@@ -0,0 +1,4 @@
!<arch>
foo.o 1610108108 12549 24403 100644 16 `
foo file contentfoo.o 1610108119 12549 24403 100644 16 `
foo file content