Reputation: 133619
I'm quite new with NDK + Gradle + CMake integration and I'm trying to understand why linking doesn't export symbols as intended.
I have a static library built by a CMakeLists.txt
which is not the main CMakeLists.txt
.
The scripts does something like:
# 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})
while CMakeLists.txt
inside ${libs}/foo
is the following:
# misc configuration of ${SRC}
add_library(foo STATIC ${SRC})
The script works fine, it's able to link libnative.so
and I'm able to find the generated libfoo.a
. Everything seems fine.
I then try to define a native method in foo.cpp
contained in foo library:
extern "C" JNIEXPORT void JNICALL Java_com_mypackage_Controls_onTap(JNIEnv*, jobject, int x, int y) {
// log something
}
But I'm not able to call the native method defined in foo library. I get an UnsatisfiedLinkError
at runtime. If, instead, I move (directly by copying and pasting) the method to native.cpp then everything goes fine.
So basically:
UnsatisfiedLinkError
)I tried to inspect the exported functions with nm
and it looks like that foo.a
correctly exports the native function as I can see
00011060 T Java_com_mypackage_Controls_onTap
But this entry disappears from libnative.so
. If, instead, I define the method directly in native.cpp then I can see it correctly with nm also on libnative.so
.
In addition calling any method in foo
library from native.cpp
works as intended so the library is effectively statically linked.
I am not able to understand the reason behind this, the approach should be fine, visibility should be correct as specified by JNIEXPORT
macro so I'm really groping in the dark (and Gradle doesn't provide any output of compilation phase so I can't understand what's happening, but the build.ninja file seems correct)
Upvotes: 2
Views: 2218
Reputation: 57203
This behavior, even if unpleasant, is correct. The linker drops any object "files" (in your case, foo.o) from used static libraries, unless they are "pinned" by one of the objects in the shared lib (in your case, native.o). There are three ways to solve the problem:
compile foo.cpp as part of libnative.so instead of a static lib.
reference Java_com_mypackage_Controls_onTap
or any other
external symbol from foo.cpp
in native.cpp
use SET(native -Wl,--whole-archive foo -Wl,--no-whole-archive)
(see https://stackoverflow.com/a/17477559/192373)
Upvotes: 4