Compiling native_app_glue.c results in an invalid library file - android

I'm cross-compiling a C++ library to Android. I'm using CMake as my build generator and I'm using the toolchain file provided in the NDK (called android.toolchain.cmake). Note, I'm on Windows.
I'd like to compile the android_native_app_glue.c source - also provided by the NDK - to a static library so I can later link it to my final application. After having an error, that said I'm missing the symbol ANativeActivity_onCreate, I've started investigating. ANativeActivity_onCreate is a function defined in android_native_app_glue.c, so I've looked at the compiled library using nm -o libnative_glue.a and it was quite surprising to see this:
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 T ANativeActivity_onCreate
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_create
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_destroy
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_entry
libnative_glue.a:android_native_app_glue.c.o:0000000000000000 t android_app_free
...
Basically my functions are "there", but are zero-sized. I'm assuming they are thrown away at the next link, since they are not valid - looking at the next artifact with nm confirmed that.
The CMake snippet to compile the library is fairly trivial, but I'll provide it for completeness's sake:
add_library(native_glue STATIC "${CMAKE_ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c")
I have two pre-defined cache-entries for CMake, ANDROID_ABI=arm64-v8a and ANDROID_PLATFORM=24.
What could cause this invalid library compilation?

Building a NativeActivity is usually done via libnative_app_glue.a, see https://developer.android.com/ndk/samples/sample_na.
Unfortunately, the instructions there have never been updated for CMake, so it could be easier to add the android_native_app_glue.c file to your shared lib.

The linker attempts to prune any unused symbols that come from non-whole static libraries, and ANativeActivity is not used directory but rather is intended for re-export.
You can either link libnative_app_glue as a whole archive, or use -u to prevent the symbol from being dropped.
With -u:
target_link_libraries(mylib -u ANativeActivity_onCreate native_app_glue)
With whole archives:
target_link_libraries(mylib -Wl,--whole-archive native_app_glue -Wl,--no-whole-archive)
I haven't actually tested either of these with CMake. The ndk-build equivalents are known to work though.
You might also be able to use an object library, which is the CMake flavor of whole archives.

Related

CMake cannot find libraries and package when building using Android toolchain [duplicate]

I build a C++ project depending on the Boost library using CMake (3.4.1). Host platform is Linux, targets are that host and cross-build Android NDK.
I'm only using Boost header files and I just downloaded/extracted the boost folder (and I don't have a /usr/include/boost directory).
In my CMakeLists.txt file I declare the dependency to Boost like this:
find_package(Boost 1.57 REQUIRED)
And I configure my build like this:
BOOST_ROOT=/path/to/boost cmake ../src
Which actually works as expected for my native build.
When I now configure a build exactly the same way (only specifying some more environment variables and a CMAKE_TOOLCHAIN_FILE) CMake gives me:
BOOST_ROOT=/path/to/boost JAVA_HOME=/bla/bla/bla \
ANDROID_NDK=/bla/bla/bla \
ANDROID_SDK=/bla/bla/bla \
ANT=/usr/bin/ant \
cmake ../src -DCMAKE_TOOLCHAIN_FILE=/bla/bla/android.toolchain.cmake
CMake Error at /usr/share/cmake/Modules/FindBoost.cmake:1247 (message):
Unable to find the requested Boost libraries.
Unable to find the Boost header files. Please set BOOST_ROOT to the root
directory containing Boost or BOOST_INCLUDEDIR to the directory containing
Boost's headers.
Call Stack (most recent call first):
CMakeLists.txt:4 (find_package)
So I believe I did almost the same to build for the Android target but the very same method that finds Boost for the host-build doesn't work here.
I tried to set Boost_DIR, BOOSTROOT and BOOST_INCLUDEDIR all with the same effect. Also I've deleted all content in the build directory before trying anything new.
What can be possible reasons for this behavior? I've already tried to print BOOST_ROOT directly in the FindBoost.cmake script like this:
message("BOOST_ROOT: $ENV{BOOST_ROOT}")
With the expected behavior (writing BOOST_ROOT: /path/to/boost).
Of course I can cheat now and just link the boost folder into the include folder of the cross compiler but that's not nice of course and I want to find out what's going on.
When cross-compiling, the toolchain file normally sets the variable CMAKE_FIND_ROOT_PATH. Combined with the CMAKE_FIND_ROOT_PATH_MODE_LIBRARY variable set to ONLY, CMAKE_FIND_ROOT_PATH variable is used as effective chroot for find_library calls, so only libraries under the given prefix(es) are searched.
Analogue variables exist to adjust the behavior for find_path (used for searching include paths) and find_program.
THe toolchain file you use actually sets CMAKE_FIND_ROOT_PATH at line 1521:
set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin"
"${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}"
"${ANDROID_SYSROOT}"
"${CMAKE_INSTALL_PREFIX}"
"${CMAKE_INSTALL_PREFIX}/share" )
and below sets CMAKE_FIND_ROOT_PATH_MODE_* variables to ONLY. So you need to have Boost installed under one of these directories, and give hints (like BOOST_ROOT) relative to it.
Note, that Boost should be built for the target platform (Android NDK in you case), not for the platform where you cross-compile (Linux).

Compiling GRPC's CSharp extensions with NDK for Android

I am attempting to use GRPC with Unity. I'm stuck compiling a libgrpc_csharp_ext.so file which will successfully work with the arm-v7a Android archetecture. I expected the following command to work from the GRPC repository root:
arm-linux-androideabi-gcc -I. -I./include -fPIC -o libgrpc_csharp_ext.o -c src/csharp/ext/grpc_csharp_ext.c
arm-linux-androideabi-gcc -I. -I./include -shared libgrpc_csharp_ext.o -o libgrpc_csharp_ext.so
I cobbled this together from this question. It compiles successfully and Unity recognizes the file when placed in /Plugins/Android as a arvm7 library:
but when GRPC attempts to DllImport("grpc_csharp_ext") on an actual Android device, I get an error:
Unable to load library
'/data/app/PACKAGE/lib/arm/libgrpc_csharp_ext.so',
native render plugin support disabled: java.lang.UnsatisfiedLinkError:
dlopen failed: cannot locate symbol "grpc_slice_from_copied_buffer"
referenced by
"/data/app/PACKAGE/lib/arm/libgrpc_csharp_ext.so"...
Followed by:
Unable to find grpc_csharp_ext
I know this is possible because this open-source project has successfully cross-compiled the necessary files. When I download the .so file from their project and drop it into mine it successfully loads, except it was compiled with a very old version of GRPC and I therefore do not wish to use it. Furthermore, I've already successfully created an .a file for iOS which works well with a similar strategy. When I check my file with file libgrpc_csharp_ext.so I see that it is ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, with debug_info, not stripped. This matches the type of the file obtained from the open-source repository.
It seems like the appropriate symbols are not included in the resulting .so, based upon the error message above and also that the .so is ~36kb, but the "correct" .so from the open-source project is >5mb. I guess I'm compiling a dynamic library that doesn't include all the necessary symbols, but I'm not enough of a compiler guru to find the correct options.
Thanks to the help of the GRPC team, I have a working solution; see my comment in the issue here: https://github.com/grpc/grpc/issues/14402#issuecomment-369942250
I'm working with them to hopefully get this integrated into master. In the mean time, I will try to keep this blog post up to date with the instructions for each platform (not just Android): http://examinedself.com/cross-compile-grpc-unity/

Building PCL for Android

Does anyone have instructions for building the Point Cloud Library (PCL) for Android? I found a few superbuilds of PCL that claim to be able to build PCL and its dependencies. I tried the superbuild from http://www.hirotakaster.com/weblog/how-to-build-pcl-for-android-memo/. I'm using Ubuntu 14.10, Android 19, NDK r10d, and PCL 1.6.0, but I'm willing to use any versions. I'm also using the terminal for compiling. For Android hardware, I'm using a Project Tango.
I tried using android-cmake (http://code.google.com/p/android-cmake/), but I'm not sure how to build the proper toolchain. I continually receive the error "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." I get this error with plain cmake and ccmake, too.
Does anyone have any detailed instructions for building PCL for Android (e.g., a bash script or terminal instructions)? Or, does anyone have a link to pre-built libraries?
(Caveat Emptor: This is not a long term solution)
I was able to get past the CMAKE error by editing the cmake file
pcl-superbuild/toolchains/toolchain-android.cmake
These two changes should get past the errors mentioned above:
set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86" ) # Line 468
Should be
set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" )
This will generate another error, unless you change the following line (Line 1023)
if( ANDROID_NDK_RELEASE STRGREATER "r8" ) # r8b
Should be
if( ANDROID_NDK_RELEASE STRGREATER "r10" ) # r8b
The first change adds _64 to x86_64. The second adds compatibility for r10d.
This doesn't fix all of the errors though, because BOOST threads don't place nicely with GCC 4.6+. Implement the patch shown at this link (https://svn.boost.org/trac/boost/ticket/6165).
Again, that still doesn't fix all of the errors. (I haven't figured out why this is needed yet, math.h shouldn't need std::). In the file,
pcl-superbuild/CMakeExternals/Source/pcl/common/include/pcl/pcl_macros.h
Edit lines 99-102:
# define pcl_isnan(x) isnan(x)
# define pcl_isfinite(x) isfinite(x)
# define pcl_isinf(x) isinf(x)
They should be:
# define pcl_isnan(x) std::isnan(x)
# define pcl_isfinite(x) std::isfinite(x)
# define pcl_isinf(x) std::isinf(x)
PCL still generates many warnings, but at least it compiles (so far)
**EDIT: **
This doesn't get you all the way (unfortunately) because the boost libraries don't play well with C++11.
To fix this, download boost 1.55 from http://sourceforge.net/projects/boost/files/boost/1.55.0/, and overwrite the boost directory
pcl-superbuild/CMakeExternals/Source/boost/boost_1_45_0
(This directory gets created when you run make for the first time).
Next, modify
pcl-superbuild/CMakeExternals/Source/boost/CMakeLists.txt
and find the line:
file(GLOB lib_srcs ${boost_root}/libs/filesystem/v2/src/*.cpp)
replace it with
file(GLOB lib_srcs ${boost_root}/libs/filesystem/src/*.cpp)
That's as far as I've gotten
this link helps a lot, you can take a look. I also left some comments there..
http://www.hirotakaster.com/weblog/how-to-build-pcl-for-android-memo/
for compile pcl 1.6 with ndk r10d, you need to replace toolchain-android.cmake with the toolchain from opencv library
I built PCL and its dependencies using Ubuntu 14.10, 32-bit. I also had to use NDK r8c, 32-bit. The key to building Hirotakaster's superbuild was using a 32-bit os.
I managed to compile your super build with Ubuntu 15.10 64-bit and NDK r10e. I changed the toolchain-android.cmake with the one from OpenCV. Then in common.hpp(found in /Source/pcl/common/include/pcl/common/impl) I had to add the following lines:
# include < math.h >
# define pcl_isnan(x) std::isnan(x)
# define pcl_isfinite(x) std::isfinite(x)
# define pcl_isinf(x) std::isinf(x)

NDK: Compile c++ files with .mm extension

I have some C++ source files (with .mm extension) in an XCode project.
I'm trying to compile only those that are pure C++ (no objc syntax or cocoa runtime used) and compile them in an Android NDK build (NDK r8d).
The problem seems to be that g++ will not even consider .mm files as C++ and will fail with:
arm-linux-androideabi-g++: error: Objective-C++ compiler not installed on this system
I tried:
1. LOCAL_CPP_EXTENSION := .mm (in Android.mk) - doesn't help.
2. Search g++ documentation on how to accept custom file extensions - couldn't find any.
I'd really like to find a way to force NDK/g++ to accept .mm files, but open to other ideas like:
copy & rename .mm to .cpp for the Android project - I don't like this since it complicates the build and version control, but it seems like the most basic thing that could work.
build this as a static lib (using xcode) - I tried going there, but I wasn't sure which architecture to build for, or if it even makes sense.
Others?
Does anyone have some experience or ideas on this? Thanks.
Solution (see accepted answer)
LOCAL_CFLAGS += -x c++
Add the "-x c++" option to $CFLAGS variable in .mk file. This should force GCC to use the C++ compiler.
EDIT: sorry for the typo, "-x" option, not "-c" and "c++", not "cpp"
Despite the accepted answer, I'd still say that renaming the files to .CPP would be the right thing to do. What's so controversial about making the extension match the content? Xcode would be fine with compiling C++ files, and as a bonus, it'll protect you from accidentally polluting it with Objective C++ on the iOS side.

Setting up an Android build environment for JNI applications

I've got a hold of a proprietary JNI application which I need to build for a MIPS device. I've read "Initializing a Build Environment", parts of the NDK docs, some Google Groups threads and numerous StackOverflow questions, but I'm still short of my answer.
So far, I've checked out the Android source using Google's repo script and have it under ~/AndroidSource. I've also separately downloaded the SDK under ~/AndroidSDK and the NDK under ~/AndroidNDK. The code I'm trying to build is in a separate location. The SDK and NDK binaries are in my path. For building, I tried to use two different versions of the NDK as well as the one under the Android source tree, and experienced different sets of problems. My current setup uses NDK r8b, downloaded separately from the Android source.
The application has its Android.mk and jni/Android.mk. However, several directives in the latter point to paths such as
frameworks/base/include
system/core/include
with no prefixes. I thought these were meant to point to the respective directories in the Android source, so I symlinked them to the current directory. After some more symlinking and makefile and source hacking, I got the application to compile, but am currently stuck on the linking phase with lots of references to missing method bodies. During the whole time I knew I was doing something wrong.
I'm on a Linux x86_64 host, if it is of any concern.
So my question is:
What is the proper method to set up a build environment for JNI applications? What environment variables, symlinks and/or path expansions should I set up? Do I need to call any scripts once or before each ndk-build invocation?
Also, I'd be happy if you corrected me on any concepts or terminology I've gotten wrong.
Your approach wiyh symlinking the AOSP tree for system headers is correct. What you need now are the system libraries compiled for MIPS. The easiest way to get them is to adb pull them from a target device (or emulator image). But you can also build these libraries yourself, as part of the AOSP build (see build instructions for the source tree you downloaded).
If you still have any problems remaining, run your ndk-build with parameter V=1 and publish the link command and its results.
I use the following in my build (YMMV).
Explicitly invoke arm-linux-androideabi-gcc as your compiler or linker (should be in PATH).
NDK_PLATFORM=/path/to/android-ndk-r*/platforms/android-14
Pass -I"$(NDK_PLATFORM)/arch-arm/usr/include" to the compiler
Pass -nostdlib -L"$(NDK_PLATFORM)/arch-arm/usr/lib/" -lgcc -lc -lm to the linker

Categories

Resources