如何将 TensorFlow Lite 构建为静态库并从单独的 (CMake) 项目向其 link?
How to build TensorFlow Lite as a static library and link to it from a separate (CMake) project?
我已经成功构建了一个简单的 C++ 应用程序 运行 TF Lite model by adding my sources to tensorflow/lite/examples
, similarly to what the official C++ TF guide 建议使用完整的 TF。现在我想将它构建为一个单独的项目(共享库)link静态地连接到 TF Lite 并使用 CMake 作为构建系统。
我尝试将自定义目标添加到我的 CMakeLists.txt
,这将使用 Bazel 构建 TF Lite:
set(TENSORFLOW_DIR ${CMAKE_SOURCE_DIR}/thirdparty/tensorflow)
add_custom_target(TFLite
COMMAND bazel build //tensorflow/lite:framework
COMMAND bazel build //tensorflow/lite/kernels:builtin_ops
WORKING_DIRECTORY ${TENSORFLOW_DIR})
我选择那些 Bazel 目标是因为来自 tensorflow/lite/examples/minimal
的 BUILD
文件将它们作为依赖项,并且它们在我构建时为我工作
我在 TF 仓库中使用 Bazel 的代码。不确定是否足够。
然后我手动收集包含目录(带有丑陋的临时硬编码路径)和库:
set(TFLite_INCLUDES
${TENSORFLOW_DIR}
~/.cache/bazel/_bazel_azymohliad/ec8567b83922796adb8477fcbb00a36a/external/flatbuffers/include)
set(TFLite_LIBS
${TENSORFLOW_DIR}/bazel-bin/tensorflow/lite/libframework.pic.a)
target_include_directories(MyLib ... PRIVATE ... ${TFLite_INCLUDES})
target_link_libraries(MyLib ... ${TFLite_LIBS})
使用此配置,我在 linkage 期间获得了很多对 TFLite 内容的未定义引用。我检查了 nm
,libframework.pic.a
中确实缺少这些符号,我在 Bazel 输出的各种 .o
文件中找到了其中一些。手动选择所有这些 .o
文件似乎是错误的。
那么,是否可以像我尝试的那样从 CMake 很好地 link 到 TF Lite?也许有一些神奇的 bazel query include_dirs(//tensorflow/lite:framework)
命令可以给我所有必要的包含目录的路径,以及一个类似的库命令 link 反对以便我可以将此信息传递给 CMake?
我最终为 CMake 的 target_link_libraries
(在 TFLite_LIBS
)手动列出了所有必要的 TFLite object 文件并且它有效。
我使用了一个简单的 shell 脚本来获取必要的 object 文件列表。
首先,我将构建日志中所有未定义的引用收集到 bash-array 中,如下所示:
SYMBOLS=(\
'tflite::CombineHashes('\
'tflite::IsFlexOp('\
'tflite::ConvertArrayToTfLiteIntArray('\
'tflite::EqualArrayAndTfLiteIntArray('\
...
'tflite::ConvertVectorToTfLiteIntArray(')
然后对于该数组中的每个符号,我遍历了 bazel 构建输出中的每个 *.o
文件:
for SYMBOL in $SYMBOLS[@]; do
for OBJ in $(find -L /path/to/tensorflow/bazel-bin/ -name '*.o'); do
nm -C $OBJ | grep "T $SYMBOL" > /dev/null && echo $OBJ
done
done | sort | uniq
并将输出添加到 CMake 中的 TFLite_LIBS
(当然,路径前缀正确)。之后,我得到了一个新的未定义引用部分,但经过几次迭代后,它解决了所有问题。
可能我还可以从我最初的 in-tree 构建的 *-params
文件中获取完整的依赖项列表,但快速检查显示它有一些冗余项,并且脚本只收集了必要的。
对于包含位置,我用 ${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/
替换了 bazel 缓存中平面缓冲区的硬编码路径。感谢 jdehesa 的提示。
更新:
all-inclusive TF Lite 静态库的本地构建可以非常类似于 RPi, iOS or ARM64 的官方构建说明,使用普通的旧 make:
1. ./tensorflow/lite/tools/make/download_dependencies.sh
2. make -f tensorflow/lite/tools/make/Makefile
输出库将存储为<tensorflow-root>/tensorflow/lite/tools/make/gen/<platform>/lib/libtensorflow-lite.a
。并且带有 headers 的外部依赖项将进入 <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads
(例如 flatbuffers
headers 在 <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include
中)。
指南没有提到可以直接调用make。有wrapper-scripts针对不同的cross-compilation目标,这只是设置适当的变量和运行 make。但默认情况下 make 只会进行原生构建。此 make 调用可以作为自定义命令添加到 CMakeLists.txt
.
我已经成功构建了一个简单的 C++ 应用程序 运行 TF Lite model by adding my sources to tensorflow/lite/examples
, similarly to what the official C++ TF guide 建议使用完整的 TF。现在我想将它构建为一个单独的项目(共享库)link静态地连接到 TF Lite 并使用 CMake 作为构建系统。
我尝试将自定义目标添加到我的 CMakeLists.txt
,这将使用 Bazel 构建 TF Lite:
set(TENSORFLOW_DIR ${CMAKE_SOURCE_DIR}/thirdparty/tensorflow)
add_custom_target(TFLite
COMMAND bazel build //tensorflow/lite:framework
COMMAND bazel build //tensorflow/lite/kernels:builtin_ops
WORKING_DIRECTORY ${TENSORFLOW_DIR})
我选择那些 Bazel 目标是因为来自 tensorflow/lite/examples/minimal
的 BUILD
文件将它们作为依赖项,并且它们在我构建时为我工作
我在 TF 仓库中使用 Bazel 的代码。不确定是否足够。
然后我手动收集包含目录(带有丑陋的临时硬编码路径)和库:
set(TFLite_INCLUDES
${TENSORFLOW_DIR}
~/.cache/bazel/_bazel_azymohliad/ec8567b83922796adb8477fcbb00a36a/external/flatbuffers/include)
set(TFLite_LIBS
${TENSORFLOW_DIR}/bazel-bin/tensorflow/lite/libframework.pic.a)
target_include_directories(MyLib ... PRIVATE ... ${TFLite_INCLUDES})
target_link_libraries(MyLib ... ${TFLite_LIBS})
使用此配置,我在 linkage 期间获得了很多对 TFLite 内容的未定义引用。我检查了 nm
,libframework.pic.a
中确实缺少这些符号,我在 Bazel 输出的各种 .o
文件中找到了其中一些。手动选择所有这些 .o
文件似乎是错误的。
那么,是否可以像我尝试的那样从 CMake 很好地 link 到 TF Lite?也许有一些神奇的 bazel query include_dirs(//tensorflow/lite:framework)
命令可以给我所有必要的包含目录的路径,以及一个类似的库命令 link 反对以便我可以将此信息传递给 CMake?
我最终为 CMake 的 target_link_libraries
(在 TFLite_LIBS
)手动列出了所有必要的 TFLite object 文件并且它有效。
我使用了一个简单的 shell 脚本来获取必要的 object 文件列表。 首先,我将构建日志中所有未定义的引用收集到 bash-array 中,如下所示:
SYMBOLS=(\
'tflite::CombineHashes('\
'tflite::IsFlexOp('\
'tflite::ConvertArrayToTfLiteIntArray('\
'tflite::EqualArrayAndTfLiteIntArray('\
...
'tflite::ConvertVectorToTfLiteIntArray(')
然后对于该数组中的每个符号,我遍历了 bazel 构建输出中的每个 *.o
文件:
for SYMBOL in $SYMBOLS[@]; do
for OBJ in $(find -L /path/to/tensorflow/bazel-bin/ -name '*.o'); do
nm -C $OBJ | grep "T $SYMBOL" > /dev/null && echo $OBJ
done
done | sort | uniq
并将输出添加到 CMake 中的 TFLite_LIBS
(当然,路径前缀正确)。之后,我得到了一个新的未定义引用部分,但经过几次迭代后,它解决了所有问题。
可能我还可以从我最初的 in-tree 构建的 *-params
文件中获取完整的依赖项列表,但快速检查显示它有一些冗余项,并且脚本只收集了必要的。
对于包含位置,我用 ${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/
替换了 bazel 缓存中平面缓冲区的硬编码路径。感谢 jdehesa 的提示。
更新:
all-inclusive TF Lite 静态库的本地构建可以非常类似于 RPi, iOS or ARM64 的官方构建说明,使用普通的旧 make:
1. ./tensorflow/lite/tools/make/download_dependencies.sh
2. make -f tensorflow/lite/tools/make/Makefile
输出库将存储为<tensorflow-root>/tensorflow/lite/tools/make/gen/<platform>/lib/libtensorflow-lite.a
。并且带有 headers 的外部依赖项将进入 <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads
(例如 flatbuffers
headers 在 <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include
中)。
指南没有提到可以直接调用make。有wrapper-scripts针对不同的cross-compilation目标,这只是设置适当的变量和运行 make。但默认情况下 make 只会进行原生构建。此 make 调用可以作为自定义命令添加到 CMakeLists.txt
.