Flutter FFI调用C++库遇ld未定义符号错误,CMake配置排查
我下载了一个外部C++库,计划通过Flutter FFI在Flutter程序中使用。已正确配置FFI,但调用该库函数时出错:initAoo函数调用aoo_initialize(0),编译运行到Android设备时,出现ld: error: undefined symbol: aoo_initialize错误,编译任务:app:externalNativeBuildDebug执行失败。我认为问题出在CMakeLists.txt配置上,当前配置如下,请问配置存在什么问题?是否正确包含了编译所需文件?
调用代码
#include <iostream> #include "aoo/include/aoo/aoo.h" #include "aoo/include/aoo/aoo_server.h" #include "aoo/include/aoo/aoo_net.h" extern "C" void initAoo(){ aoo_initialize(0); std::cout << "Called from init AOO!" << std::endl; }
错误日志
* What went wrong: Execution failed for task ':app:externalNativeBuildDebug'. > Build command failed. Error while executing process /Users/zacharyhaslam/Library/Android/sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /Users/zacharyhaslam/FlutterApplications/state_management_example/android/app/.cxx/cmake/debug/armeabi-v7a add} ninja: Entering directory `/Users/zacharyhaslam/FlutterApplications/state_management_example/android/app/.cxx/cmake/debug/armeabi-v7a' [1/2] Building CXX object CMakeFiles/add.dir/cpp/add.cpp.o [2/2] Linking CXX shared library /Users/zacharyhaslam/FlutterApplications/state_management_example/build/app/intermediates/cmake/debug/obj/armeabi-v7a/libadd.so FAILED: /Users/zacharyhaslam/FlutterApplications/state_management_example/build/app/intermediates/cmake/debug/obj/armeabi-v7a/libadd.so : && /Users/zacharyhaslam/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv7-none-linux-androideabi19 --sysroot=/Users/zacharyhaslam/Library/Android/sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/darwin-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -fno-limit-debug-info -static-libstdc++ -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Wl,--gc-sections -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libadd.so -o /Users/zacharyhaslam/FlutterApplications/state_management_example/build/app/intermediates/cmake/debug/obj/armeabi-v7a/libadd.so CMakeFiles/add.dir/cpp/add.cpp.o -latomic -lm && : ld: error: undefined symbol: aoo_initialize >>> referenced by add.cpp:11 (../../../../../cpp/add.cpp:11) >>> CMakeFiles/add.dir/cpp/add.cpp.o:(initAoo) clang++: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed
当前CMakeLists.txt配置
cmake_minimum_required(VERSION 3.10.2) add_library( add SHARED cpp/add.cpp ) include_directories(cpp/aoo/include/aoo/aoo.h) add_library(aoo cpp/aoo/include/aoo/aoo.h) set_target_properties(aoo PROPERTIES LINKER_LANGUAGE CXX)
当前CMake配置存在三个核心问题:
include_directories参数错误
include_directories需要传入头文件所在的目录,而非单个头文件路径。你现在指定的是cpp/aoo/include/aoo/aoo.h,编译器无法正确识别所有相关头文件的位置。aoo库未正确引入
add_library(aoo cpp/aoo/include/aoo/aoo.h)仅添加了头文件,没有包含库的实现文件(.cpp/.c源文件)或预编译库文件(.so/.a)。链接器找不到aoo_initialize的具体实现,因此报出未定义符号错误。未将aoo库链接到目标库add
即使正确引入了aoo库,也需要显式将其链接到你自己的add库,否则编译时无法关联两者的符号。
分场景修正CMakeLists.txt
场景1:aoo库是源码形式(有.cpp/.c文件)
假设aoo的源码放在cpp/aoo/src目录下,修正后的配置如下:
cmake_minimum_required(VERSION 3.10.2) # 添加自己的add库 add_library( add SHARED cpp/add.cpp ) # 指定aoo库的头文件目录(让编译器找到.h文件) include_directories(cpp/aoo/include) # 添加aoo库的源码文件 add_library(aoo STATIC # 或SHARED,根据库类型选择 cpp/aoo/src/aoo.cpp cpp/aoo/src/aoo_server.cpp cpp/aoo/src/aoo_net.cpp # 其他aoo相关源文件 ) # 将aoo库链接到add库 target_link_libraries(add PRIVATE aoo)
场景2:aoo库是预编译的.so/.a库
假设预编译库放在cpp/aoo/libs/${ANDROID_ABI}目录下,修正后的配置如下:
cmake_minimum_required(VERSION 3.10.2) # 添加自己的add库 add_library( add SHARED cpp/add.cpp ) # 指定aoo库的头文件目录 include_directories(cpp/aoo/include) # 引入预编译的aoo库 add_library(aoo SHARED # 或STATIC,对应库的类型 IMPORTED ) # 设置预编译库的路径 set_target_properties(aoo PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/cpp/aoo/libs/${ANDROID_ABI}/libaoo.so" # 如果是静态库,后缀改为.a ) # 将aoo库链接到add库 target_link_libraries(add PRIVATE aoo)
关键修改说明
include_directories(cpp/aoo/include):让编译器能找到aoo.h等头文件,你代码中的#include "aoo/aoo.h"会自动从这个目录下查找。- 正确添加aoo库的实现:无论是源码还是预编译库,都要让CMake识别到库的二进制实现,否则链接器找不到符号。
target_link_libraries(add PRIVATE aoo):将aoo库的符号关联到add库,确保编译时能找到aoo_initialize的实现。
内容的提问来源于stack exchange,提问作者zh24

