如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它? [英] How to build TensorFlow Lite as a static library and link to it from a separate (CMake) project?
问题描述
通过将我的源代码添加到tensorflow/lite/examples
,类似于官方C ++ TF指南建议的完整TF.现在,我想将其构建为一个单独的项目(共享库),以静态方式链接到TF Lite,并使用CMake作为构建系统.
I've successfully built a simple C++ app running TF Lite model by adding my sources to tensorflow/lite/examples
, similarly to what the official C++ TF guide suggests for full TF. Now I want to build it as a separate project (shared library) linking to TF Lite statically and using CMake as a build system.
我试图向我的CMakeLists.txt
添加自定义目标,这将使用Bazel构建TF Lite:
I tried to add a custom target to my CMakeLists.txt
, which would build TF Lite with Bazel:
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编写的代码.不确定是否足够.
I chose those Bazel targets because the BUILD
file from tensorflow/lite/examples/minimal
has them as dependencies, and they work for me when I build
my code with Bazel within TF repo. Not sure if that's enough.
然后我手动收集包括dirs(具有丑陋的临时硬编码路径)和libs:
Then I manually collect include dirs (with that ugly temporarily hardcoded path) and libs:
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})
通过这种配置,我在链接期间获得了许多未定义的对TFLite内容的引用.我检查了nm
并发现libframework.pic.a
中确实缺少那些符号,我在Bazel输出的各种.o
文件中找到了其中的一些符号.手动选择所有这些.o
文件似乎是错误的.
And with this configuration, I get many undefined references to TFLite stuff during linkage. I checked with nm
and those symbols are indeed missing in libframework.pic.a
, I found some of them in various .o
files in Bazel output. Manually picking all those .o
files seems wrong.
那么,是否有可能像我想的那样从CMake很好地链接到TF Lite?也许有一些神奇的bazel query include_dirs(//tensorflow/lite:framework)
命令可以为我提供所有必要的包含目录的路径,以及一个类似的库链接命令,以便我可以将此信息传递给CMake?
So, is it possible to link nicely to TF Lite from CMake like I'm trying to? Maybe is there some magical bazel query include_dirs(//tensorflow/lite:framework)
command which would give me paths to all the necessary include dirs, and a similar command for libraries to link against so that I could pass this info to CMake?
推荐答案
我最终为CMake的target_link_libraries
(在TFLite_LIBS
中)手动列出了所有必需的TFLite对象文件,并且可以正常工作.
I ended up listing all necessary TFLite object files manually for CMake's target_link_libraries
(in the TFLite_LIBS
) and it works.
我使用了一个简单的shell脚本来获取必要的目标文件列表. 首先,我将构建日志中所有未定义的引用收集到bash数组中,如下所示:
I used a simple shell script to get the list of necessary object files. First I collected all undefined references from build log into a bash-array as following:
SYMBOLS=(\
'tflite::CombineHashes('\
'tflite::IsFlexOp('\
'tflite::ConvertArrayToTfLiteIntArray('\
'tflite::EqualArrayAndTfLiteIntArray('\
...
'tflite::ConvertVectorToTfLiteIntArray(')
然后对于该数组中的每个符号,我遍历了bazel build输出中的每个*.o
文件:
Then for every symbol in that array, I went through every *.o
file in bazel build output:
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
中(当然具有正确的路径前缀).之后,我得到了未定义引用的新部分,但是经过几次迭代,它解决了所有问题.
and added the output to TFLite_LIBS
in CMake (with correct path prefix, of course). After that, I got a new portion of undefined references, but after a few iterations, it resolved everything.
也许我也可以从我最初的树内构建中的*-params
文件中获取依赖项的完整列表,但是快速检查表明它具有一些冗余项,并且脚本仅收集了必要的项.
Probably I could also obtain the full list of dependencies from *-params
file from my initial in-tree build, but a quick check showed that it had some redundant items, and the script collected only the necessary ones.
对于包含位置,我用${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/
替换了硬编码到bazel缓存中平面缓冲区的路径.感谢 jdehesa 的提示.
For include locations, I replaced that hardcoded path to flatbuffers in bazel cache with ${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/
. Thanks jdehesa for the hint.
更新:
全包式TF Lite静态库的本机构建可以非常类似于 RPi , iOS 或
UPDATE:
The native build of all-inclusive TF Lite static library can be done very similar to official build instructions for RPi, iOS or ARM64 using plain old 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
.外部依赖项及其标头将进入<tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads
(例如flatbuffers
标头位于<tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include
中).
The output library will be stored as <tensorflow-root>/tensorflow/lite/tools/make/gen/<platform>/lib/libtensorflow-lite.a
. And the external dependencies with their headers would go into <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads
(for example flatbuffers
headers are in <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include
).
指南没有提到可以直接调用make.有针对不同交叉编译目标的包装器脚本,它们仅设置适当的变量并运行make.但是默认情况下,make只会执行本机构建.可以在CMakeLists.txt
中将此定制发票添加为自定义命令.
Guide doesn't mention that make could be called directly. There are wrapper-scripts for different cross-compilation targets, which just set appropriate variables and run make. But by default make would just do native build. This make invokation can be added as a custom command in CMakeLists.txt
.
这篇关于如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!