Android NDK CMake linking issues - android

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:
Java -> method in native.cpp works
Java -> method in native.cpp -> method defined in foo library works
Java -> method in foo library doesn't work (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)

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)

Related

Disable compiler optimization for a variable in JNI C code

I have a variable definition in an Android JNI C function that does nothing but define itself as a string. I want this string to appear in the binary, but when I build the project, the .so file does not contain the string.
Here's what I've tried in the C code.
#pragma GCC push_options
#pragma GCC optimize ("O0")
const char volatile myString[32] = "Some string that must be there";
#pragma GCC pop_options
How can I get disable the compiler from optimizing away this unused variable definition?
I suspect that your problem is not with the compilation, but with the linking. Linkers often leave out data that is not used, to reduce the size of the binary. To check this, use the strings command or equivalent on the .o file generated from your C file: if the string is in that, but not in your .so your problem is the linking.
Unfortunately, I don't know how to work around this problem with the linker command(s), because all of my Android C programming has been done with a standalone tool-chain and a custom build system.
Your easiest solution is simply to make a copy of the string at run-time. You need to do this in your C code, so that the linker knows the string gets used.

Building an Android executable gRPC server that uses protocol buffers (without APK)

I compiled the gRPC Android example from here.
I want to run the program as executable from adb shell.
Added these lines to grpc-helloworld.cc:
#include <iostream>
int main() {
std::cout << "qwerty" << std::endl;
return 0;
}
And these lines to its CMakeLists.txt:
add_executable(avocado
src/main/cpp/grpc-helloworld.cc)
target_include_directories(avocado
PRIVATE ${HELLOWORLD_PROTO_HEADERS})
target_link_libraries(avocado
helloworld_proto_lib
android
${log-lib})
Then I pushed the generated executable and libs file and tried to run it:
LD_LIBRARY_PATH=. ./avocado
I got the following error:
[libprotobuf FATAL
/home/buga/grpc/third_party/protobuf/src/google/protobuf/stubs/common.cc:79]
This program was compiled against version 3.0.0 of the Protocol Buffer
runtime library, which is not compatible with the installed version
(3.5.1). Contact the program author for an update. If you compiled
the program yourself, make sure that your headers are from the same
version of Protocol Buffers as your link-time library. (Version
verification failed in
"out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android_arm64_armv8-a_kryo300_shared_core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_metrics.pb.cc".)terminating
with uncaught exception of type google::protobuf::FatalException: This
program was compiled against version 3.0.0 of the Protocol Buffer
runtime library, which is not compatible with the installed version
(3.5.1). Contact the program author for an update. If you compiled
the program yourself, make sure that your headers are from the same
version of Protocol Buffers as your link-time library. (Version
verification failed in
"out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android_arm64_armv8-a_kryo300_shared_core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_metrics.pb.cc".)
Aborted
What am I doing wrong?
We realized that there is a version of the protobuf library called libprotobuf-cpp-full.so and libprotobuf-cpp-lite.so, and it seems that their version is 3.0.0. This is conflicting with our version (3.5.1) which is compiled into either a static lib, or as a shared lib.
I'm not quite sure why this happens. Something about once the linker loads helloworld_proto_lib, it overrides all loaded protobuf symbols, and for some reason another library that you had nothing to do with crashes your program. But that's not telling you anything new.
Here's one way to solve this problem:
1. Changes to grpc-helloworld.cc
Make the main extern "C", and change its name maybe. For example:
extern "C" int my_main() {
std::cout << "qwerty" << std::endl;
return 0;
}
2. Add file grpc-avocado.cc
This will contain the actual main of the executable, which will dynamically load the libraries helloworld_proto_lib and grpc-helloworld. Here's how to do it:
#include <iostream>
#include <android/dlext.h>
#include <dlfcn.h>
int main() {
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
void* proto_lib = android_dlopen_ext("/path/to/libhelloworld_proto_lib.so", RTLD_LAZY, &extinfo);
void* helloworld = dlopen("/path/to/libgrpc-helloworld.so", RTLD_LAZY);
int (*my_main)() = (int (*)())dlsym(helloworld, "my_main");
return my_main();
}
The function android_dlopen_ext from #include <android/dlext.h>, and its flag argument, are described here: https://developer.android.com/ndk/reference/group/libdl . In the above code we pass the flag ANDROID_DLEXT_FORCE_LOAD, which is documented as:
When set, do not use stat(2) to check if the library has already been loaded.
This flag allows forced loading of the library in the case when for some reason multiple ELF files share the same filename (because the already-loaded library has been removed and overwritten, for example).
Note that if the library has the same DT_SONAME as an old one and some other library has the soname in its DT_NEEDED list, the first one will be used to resolve any dependencies.
I think the text in bold is what explains why this solution works.
3. Change CMakeLists.txt
Since you'll be loading helloworld_proto_lib dynamically, you can now remove it from the executable definition, and there's no need for any proto headers:
add_executable(avocado
src/main/cpp/grpc-avocado.cc)
target_link_libraries(avocado
android
${log-lib})
Build, push, and run
You can now build, push the executable avocado and the two libraries libgrpc-helloworld.so, libhelloworld_proto_lib.so, and run. You don't need LD_LIBRARY_PATH. Good luck with the rest of your project!

Linker can't find function

Im trying to build an Ubuntu Touch tree, based on an Aosp tree I already correctly built.
It fails with this error
CAPEWrapper.cpp:16: error: undefined reference to '__xlog_buf_printf'
this is the header that file includes
#include "CAPEWrapper.h"
which on cascade includes
#include <cutils/xlog.h>
which in turn defines
#if defined(__cplusplus)
extern "C" {
#endif
int __xlog_buf_printf(int bufid, const struct xlog_record *rec, ...);
#if defined(__cplusplus)
}
#endif
I suspect that my g++ doesn't set __cplusplus macro. Could it be a realistic scenario with this kind of error? If this could be the problem, should I need to specify a standard implementation with "stdc=something" to solve it?
Any other idea is welcome.
Make sure that your project is linking libcutils, and that it's linking it in the correct order (i.e. that -lcutils appears in the linker command line after any module that depends on it).
In the end, I found that the modules was listed inside a macro called LOCAL_WHOLE_STATIC_LIBRARIES, that in Android environment passes its content to the --whole-archive flag of GCC linker.

Function 'glDrawTexfOES' could not be resolved

I'm creating a native android project using eclipse. I'm using opengl es 1.1.
I get this error when using a function from the glext.h file
Function 'glDrawTexfOES' could not be resolved
I'm using a function from gl.h right before i call the glDrawTexfOES. I'm able to use macros defined in the glext.h such as GL_TEXTURE_CROP_RECT_OES, so i know the file is included all right.
looking at the glext.h file, i found the function declaration i want, which is in an #ifdef block (#ifdef GL_GLEXT_PROTOTYPES). I defined GL_GLEXT_PROTOTYPES immediately before including glext.h, and i still have the same problem. I went into glext.h and edited it, first by commenting the ifdef and endif lines surrounding the functions i want. i still got the same error as above. then i copied the function declaration and pasted it at the top of the glext.h file, and my project still says it can't resolve that function.
I know glext.h is deprecated, but i should still be able to use it
I had this same issue, but then put this in my Android.mk file:
LOCAL_CFLAGS += -D GL_GLEXT_PROTOTYPES
http://grokbase.com/t/gg/android-ndk/11cxrckjmp/ndkr7-cant-see-gldrawtexioes

How to use CallStack (in CallStack.tpp) in a executable on android platform?

A question from https://stackoverflow.com/a/11467040/1442443
my final target is to dump user space stack.
I try to build a cpp file as below to a executable on android platform. Therefore, by calling tryToGetStack(), I can get call stack of my executable in run time.
#include <utils/CallStack.h>
namespace android
{
extern "C" void tryToGetStack()
{
CallStack stack;
stack.update();
stack.dump("");
}
}
and add lib setting to to Android.mak since CallStack.tpp is in libutils
LOCAL_SHARED_LIBRARIES += libutils
but I always get error with message:
error: undefined reference to 'android::CallStack::CallStack()'
error: undefined reference to 'android::CallStack::update(int, int)'
...
It seems the executable resolve the symbols at link time rather than load the .so file in runtime?
Do I missing something or there is some limit in Android build system?
I know it is a simple question, but I really need help...
update1
I try to add the code to another executable. The result is same... Does anyone knows the rule of android build system?
update2
There are some key words in my console "target StaticExecutable: ...", I think is is the answer.
http://en.wikipedia.org/wiki/Static_executable
my final target is to dump user space stack.
after google so many information from internet, I found there are 4 ways:
ptraceļ¼š http://en.wikipedia.org/wiki/Ptrace
It is really hard to use ptrace, and we need to stop the thread before using ptrace to attach
_unwind_backtrace: the way used by CallStack (CallStack class in CallStack.cpp)
example: http://git.stlinux.com/?p=stm/uclibc.git;a=blob;f=libubacktrace/sysdeps/sh/backtrace.c;h=18b91b1bb3fa26344a521927c631553a410fcf56;hb=d6a3d9ece5922a337800a8e2ed4db7e226f9ccb3
It is work with a drawback: if you use it as the thread is processing signal, it would dump signal stack rather than dump thread stack
The same problen: How to get fullstacktrace using _Unwind_Backtrace on SIGSEGV
backtrace: http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
a GNU extension function, not be implemented in Bionic libc used by Android
reference: https://stackoverflow.com/a/8295238/1442443
reference: http://lists.puredata.info/pipermail/pd-list/2012-02/094258.html
a patch to dump user space thread stack: http://www.gossamer-threads.com/lists/linux/kernel/1525096
but only be implemented in X86 architecture... orz
I try to port it to android, no it only shows the first frame of stack since arm does not use frame pointer.
So... 2 is the answer.
However, I wonder if someone can resolve the problem : How to get fullstacktrace using _Unwind_Backtrace on SIGSEGV
update:
if you can use cross compiler to use glic to compile your code, maybe you can use 3. backtrace !
http://communities.mentor.com/community/cs/archives/arm-gnu/msg02514.html
update2
a good article
http://codingrelic.geekhold.com/2009/05/pre-mortem-backtracing.html
Since this is such an important question here is my answer that worked for me. My code is in C so it has to call a C++ function that can access android::CallStack.
stackdump.cpp:
#include < utils/CallStack.h >
extern "C" void dumpCallStack( char *label)
{
android::CallStack cs;
cs.update();
cs.dump(label);
}
my main code (foo.c):
void dumpCallStack(char *label);
...
dumpCallStack(\__FUNCTION__);
I have had the same problem once. And it is hard to interpret.
The syntax is of course correct and reasonable!
I have tried many methods but it did not work.
Finally, I got an idea that, the lib reference "LOCAL_SHARED_LIBRARIES += libutils" should be put into a makefile generating a dynamic library rather than into a makefile generating a static library. This is the final reason.
Reference:
http://yongbingchen.github.io/blog/2013/05/09/dump-stack-in-android-native-c-code/
I also received this error, but I added:
LOCAL_STATIC_LIBRARIES += libutils
before line of LOCAL_MODULE := xxx in vm/Android.m of three targets and added
LOCAL_SHARED_LIBRARIES += libcorkscrew
in vm/Android.mk
and libdex/Android.mk, and same for the dexlist/Android.mk, dexdump/Android.mk
After all these done, it works for me.

Categories

Resources