我对NDK + Gradle + CMake集成很新,我试图理解为什么链接不能按预期导出符号。
我有一个CMakeLists.txt
构建的静态库,它不是主CMakeLists.txt
。
脚本的作用如下:
# main CMakeLists.txt
add_subdirectory(${LIBS}/foo libs}
add_library(native SHARED native.cpp)
# omitting standard android libraries
target_link_libraries(native foo ${android-lib} ${log-lib})
CMakeLists.txt
内的${libs}/foo
如下:
# misc configuration of ${SRC}
add_library(foo STATIC ${SRC})
该脚本运行正常,它可以链接libnative.so
,我可以找到生成的libfoo.a
。一切似乎都很好。
然后我尝试在foo库中包含的foo.cpp
中定义一个本机方法:
extern "C" JNIEXPORT void JNICALL Java_com_mypackage_Controls_onTap(JNIEnv*, jobject, int x, int y) {
// log something
}
但是我无法调用foo库中定义的本机方法。我在运行时得到UnsatisfiedLinkError
。相反,如果我将该方法(直接通过复制和粘贴)移动到native.cpp,那么一切都很顺利。
基本上是这样的:
UnsatisfiedLinkError
)我尝试使用nm
检查导出的函数,看起来foo.a
正确导出了本机函数,我可以看到
00011060 T Java_com_mypackage_Controls_onTap
但此条目从libnative.so
消失。相反,如果我直接在native.cpp中定义方法,那么我也可以在libnative.so
上使用nm正确地看到它。
另外,调用来自foo
的{{1}}库中的任何方法都可以正常工作,因此库可以有效地静态链接。
我无法理解这背后的原因,方法应该没问题,可见性应该是native.cpp
宏指定的正确,所以我真的在黑暗中摸索(而且Gradle没有提供任何编译阶段的输出,所以我无法理解发生了什么,但build.ninja文件似乎是正确的)
答案 0 :(得分:3)
这种行为,即使令人不愉快,也是正确的。链接器丢弃任何对象"文件" (在您的情况下, foo.o )来自使用过的静态库,除非它们是"固定"通过共享库中的一个对象(在您的情况下, native.o )。有三种方法可以解决这个问题:
编译 foo.cpp 作为 libnative.so 的一部分,而不是 static lib。
参考Java_com_mypackage_Controls_onTap
或其他任何内容
来自foo.cpp
native.cpp
的外部符号
使用SET(native -Wl,--whole-archive foo -Wl,--no-whole-archive)
(请参阅https://stackoverflow.com/a/17477559/192373)