Android NDK CMake链接问题
我是NDK+Gradle+CMake集成的新手,我试图理解为什么链接不能按预期导出符号 我有一个由Android NDK CMake链接问题,android,c++,android-ndk,linker,cmake,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_libra
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库中定义的本机方法。我在运行时遇到了一个不满意的链接错误
。相反,如果我(直接通过复制和粘贴)将方法移动到native.cpp,那么一切都会正常进行
所以基本上:
- Java->native.cpp中的方法有效
- Java->native.cpp中的方法->在foo库中定义的方法
- foo库中的Java->method不起作用(
)unsatifiedlinkerror
nm
检查导出的函数,结果显示foo.a
正确地导出了本机函数,如我所见
00011060 T Java_com_mypackage_Controls_onTap
但是这个条目会从libnative.so
中消失。相反,如果我直接在native.cpp中定义方法,那么我也可以在libnative.so
上使用nm正确地看到它
此外,从native.cpp
调用foo
库中的任何方法都可以正常工作,因此库可以有效地静态链接
我无法理解这背后的原因,方法应该是好的,可见性应该是正确的,正如
JNIEXPORT
宏指定的那样,所以我真的在暗中摸索(Gradle没有提供编译阶段的任何输出,所以我无法理解发生了什么,但是build.ninja文件似乎是正确的)这种行为,即使令人不快,也是正确的。链接器从使用过的静态库中删除任何对象“文件”(在您的示例中为foo.o),除非它们被共享库中的一个对象“固定”(在您的示例中为native.o)。有三种方法可以解决这个问题:
Java\u com\u mypackage\u控件\u onTap
或任何其他
来自native.cpp
中foo.cpp
的外部符号SET(native-Wl,--whole-archive foo-Wl,--no-whole archive)
(请参阅)您是否尝试添加
集(CMAKE\u VERBOSE\u MAKEFILE on)
?从您的解释中很难看出哪里出了问题-要么是从libnative.so中删除了符号,要么是完全跳过了链接libfoo.a。@不跳过libfoo.a的AlexCohn链接,因为我能够从libnative调用libfoo的方法,并且它正确链接并工作。看起来符号被剥离了,或者没有从外部明显导出,但我试图强制-fvisibility=default,但没有成功。不幸的是,使用的生成器不是make,因此没有makefile。我可以看到调用命令,它似乎是正确的。so是通过喜欢native.o和libfoo.a生成的。我真的没有任何线索。谢谢,通过对相关发布的搜索(不包括Android NDK),我得出了相同的结论。虽然使用--whole archive
似乎是解决这个问题的灵丹妙药,但我想知道是否有一种方法可以将特定方法标记为“始终导出”,可能是通过\uuuuuu属性\uuuuuuuuuu
来保持事情的正常,而不仅仅是盲目导出任何对象文件的任何符号(因为最终可能只会使用1000个符号中的10个)?否,不存在链接器选项“保留符号a、b和q,即使没有人需要它们”。但是(见上文2)很容易模拟这样的选项。如果您从隐式JNI绑定切换到显式RegisterNatives(),您将自动得到它。