在使用 C++ 和 Java 的 Android 应用程序中包含 TFLite C API 时的构建问题

Posted

技术标签:

【中文标题】在使用 C++ 和 Java 的 Android 应用程序中包含 TFLite C API 时的构建问题【英文标题】:Build issue when including TFLite C API in Android app that uses C++ and Java 【发布时间】:2020-08-21 19:57:15 【问题描述】:

我通过 C++ 使用 TFLite 使用 NDK 构建我的应用程序,希望能帮助我解决链接错误。我关注的指南是https://www.tensorflow.org/lite/guide/android#use_tflite_c_api

我已将 TFLite C API 头文件和动态共享库包含在我使用 CMake 构建的程序中。

我收到以下错误:

../../../../src/main/cpp/TFLiteExample.cpp:17: error: undefined reference to 'TfLiteModelCreateFromFile'

一些附加信息:我在app/src/main/includes 中包含了头文件,在app/src/main/jni 中包含了.so 动态库。 CMakeLists.txt 文件位于 app/src/main 中。下面是CMakeLists.txt的相关组件:

cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_VERBOSE_MAKEFILE ON)

###Internal Linking

#Add internal C++ libraries
add_library( native-lib SHARED src/main/cpp/native-lib.cpp )
add_library( TFLiteExample SHARED src/main/cpp/TFLiteExample.cpp)

add_library( tensorflowlite_jni SHARED IMPORTED )
set_property(TARGET tensorflowlite_jni
    PROPERTY IMPORTED_LOCATION $PROJECT_SOURCE_DIR/src/main/jni/libtensorflowlite_jni.so)

#Make directories visible to all C++ files
include_directories(src/main/includes)
include_directories(src/main/cpp)
include_directories(src/main/jni)

# Specify the libraries which our native library is dependent on, including Oboe
target_link_libraries (native-lib tensorflowlite_jni TFLiteExample)

target_link_libraries(TFLiteExample tensorflowlite_jni)

这里是TFLiteExample.h

#ifndef TEST2_TFLITEEXAMPLE_H
#define TEST2_TFLITEEXAMPLE_H

// TFLite include files

#include <builtin_ops.h>
#include <c_api.h>
#include <c_api_experimental.h>
#include <common.h>


class TFLiteExample 
    public:
    TFLiteExample();
    static void TFLitePredict();
;


#endif //TEST2_TFLITEEXAMPLE_H

这里是TFLiteExample.cpp

#include "TFLiteExample.h"

TFLiteExample::TFLiteExample()


void TFLiteExample::TFLitePredict() 
TfLiteModel* model = TfLiteModelCreateFromFile("/src/main/assets/_quant.tflite");

标题 common.hc_api.h 都是来自 Tensorflow 的代码。除了将#include "../../../../../../../../../../../Library/Android/sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/include/c++/v1/stdbool.h" 等相对包含路径替换为#include &lt;cstdbool&gt; 之外,我没有修改代码。

common 开头包含以下内容:

#ifndef TENSORFLOW_LITE_C_COMMON_H_
#define TENSORFLOW_LITE_C_COMMON_H_

#include <cstdbool>
#include <stddef>
#include <stdint>

#ifdef __cplusplus
extern "C" 
#endif  // __cplusplus
...

还有c_api 和:

#ifndef TENSORFLOW_LITE_C_C_API_H_
#define TENSORFLOW_LITE_C_C_API_H_

#include <stdarg>
#include <stdint>

#include "common.h"

#ifdef __cplusplus
extern "C" 
#endif  // __cplusplus
...

【问题讨论】:

“C 头文件包括使用相对路径的 C++ 标准头文件” - 几乎在任何情况下,这是克服约束的错误方式。如果标准头文件不能以“短”方式访问,则根本不应该使用它们。 @Tsyvarev 我将相对路径包含替换为短包含#include &lt;cstdint&gt;。现在,程序无法读取 TFLite C API:../../../../src/main/cpp/TFLiteExample.cpp:39: error: undefined reference to 'TfLiteModelDelete' “现在,程序无法读取 TFLite C API” - 不,程序已成功包含 headers。 “未定义的引用”是 linking 阶段的错误,发生在 compile 之后。请在问题帖子中实现代码和错误消息。 谢谢@Tsyvarev。我刚刚更新了帖子。 【参考方案1】:

更新:程序已按照以下说明成功构建: https://***.com/a/63372486/4008884.

我做了以下修改:

首先,我替换了文件结构

app/src/main/jni/libtensorflowlite_jni.so

app/src/main/jni/arm64-v8a/libtensorflowlite_jni.so
app/src/main/jni/armeabi-v7a/libtensorflowlite_jni.so
app/src/main/jni/x86_64/libtensorflowlite_jni.so
app/src/main/jni/x86/libtensorflowlite_jni.so

其次,我将 TFLite C API 标头移动到同一目录 app/src/main/jni/

第三,我在build.gradleandroid 部分包含以下内容:

ndk 
    abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

最后,我在 CMakeLists.txt 的链接中添加了$ANDROID_ABI

set(JNI_DIR $PROJECT_SOURCE_DIR/src/main/jni)
add_library( tensorflowlite_jni SHARED IMPORTED)

set_target_properties(tensorflowlite_jni
        PROPERTIES IMPORTED_LOCATION
        $JNI_DIR/$ANDROID_ABI/libtensorflowlite_jni.so)

include_directories( $JNI_DIR )

target_link_libraries(native-lib tensorflowlite_jni)

【讨论】:

【参考方案2】:

我的功能有问题 显示的错误是undefined reference to TfLiteModelCreateFromFile;我想在 C 语言的程序中使用 API C for TensorFlow。这是我的程序

int32_t main(int32_t argc, char *argv[])   
 
  TfLiteModel* model = TfLiteModelCreateFromFile("iris.tflite");
  TfLiteInterpreterOptions*options =TfLiteInterpreterOptionsCreate();

【讨论】:

以上是关于在使用 C++ 和 Java 的 Android 应用程序中包含 TFLite C API 时的构建问题的主要内容,如果未能解决你的问题,请参考以下文章

SWIG (Java):如何将带有回调函数的结构从 Android 应用程序传递给 C++?

#yyds干货盘点#Android C++系列:JNI引用管理

如何使用 Java Native Interface 在 C++ 中导入 python 库 - Android Studio

Android使用JNI,C++调用JAVA代码,能找到JAVA的函数无法调用?

是否可以在没有 Java 的情况下构建 Android 应用程序? [复制]

如何在 Android 上重新启动 Qt 或 c++ 中的程序?