Android NDK CMake链接问题

时间:2016-10-15 18:47:54

标签: android c++ android-ndk linker cmake

我对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,那么一切都很顺利。

基本上是这样的:

  • Java - > native.cpp中的方法有效
  • Java - > native.cpp中的方法 - > foo库中定义的方法工作
  • Java - > foo库中的方法不起作用(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文件似乎是正确的)

1 个答案:

答案 0 :(得分:3)

这种行为,即使令人不愉快,也是正确的。链接器丢弃任何对象"文件" (在您的情况下, foo.o )来自使用过的静态库,除非它们是"固定"通过共享库中的一个对象(在您的情况下, native.o )。有三种方法可以解决这个问题:

  1. 编译 foo.cpp 作为 libnative.so 的一部分,而不是 static lib。

  2. 参考Java_com_mypackage_Controls_onTap或其他任何内容 来自foo.cpp

  3. native.cpp的外部符号
  4. 使用SET(native -Wl,--whole-archive foo -Wl,--no-whole-archive)(请参阅https://stackoverflow.com/a/17477559/192373