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/
Related
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.
We are trying to build capicxx-core-runtime for an ARM based platform running Android Pie. It's an open source IPC framework which is part of the GENIVI initiative by major automotive OEM's. Our AIM is to bring the IPC framework into our Android system.
The git repo is placed here https://github.com/GENIVI/capicxx-core-runtime.git
I am using the Android NDK version r17b and building using the following command to configure the cmake based build.
cmake -DCMAKE_TOOLCHAIN_FILE=/home/hp/downloads/android-ndk-r17b/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_NATIVE_API_LEVEL=27 ../
When I compile using 'make', I see the individual cpp files are compiled, but I am getting following errors during linking as shown in the link below.What is the configuration that I may be missing.
Linker error log
the capicxx-core-runtime is building a shared library, so you need to resolve all of it's internal symbols, including the c++ runtime.
To quickly test this: edit the capicxx-core-runtime CMakeLists.txt to link the c++_shared runtime, line 130:
target_link_libraries(CommonAPI PRIVATE ${DL_LIBRARY} ${DLT_LIBRARIES})
becomes
target_link_libraries(CommonAPI PRIVATE ${DL_LIBRARY} ${DLT_LIBRARIES} c++_shared)
and rerun your cmake command and make command.
It seems that capicxx-core-runtime can be buildable now for Android (both NDK and AOSP) out the box, please see corresponding pull requests: https://github.com/GENIVI/capicxx-core-runtime/pulls?q=author%3Ankh-lab+
Also here is simple example for AndroidStudio how it could be used with vSOME/IP transport: https://github.com/nkh-lab/ndk-capi-hello-world
i want to load shared library dynamically from external files directory.
I create library and test it on linux, it works.
Compile: gcc -fPIC -shared -static-libstdc++ -static-libgcc test_lib.cpp constructor.cpp -o test.so
But when i use this in android ndk, i get runtime error:
dlopen failed: library "libc.so.6" not found.
How i can solve it? I'm use emulator
You can't use libraries built for normal linux on android - it's still linking to the shared libc.so.6 which isn't available on Android. (You can't statically link a shared library, see e.g. https://stackoverflow.com/a/6637842/3115956.)
You need to build the library using the NDK compiler against the Android C runtime library.
If you're adventurous, you could try forcing it to link the C runtime statically into your library though, by making it link libc.a instead of libc.so, but I'm not sure if this causes other issues. (One can run executables built for normal linux on android, assuming they're built with -static, but I'm not sure how well that works for shared libraries.)
I am following the link here to build Android libraries for openssl:
http://wiki.openssl.org/index.php/Android
Here are my settings in Setenv-Android.sh:
_ANDROID_EABI="arm-linux-androideabi-4.6"
_ANDROID_ARCH=arch-arm
_ANDROID_API="android-16"
The next step is to run the following command:
$ . ./Setenv-Andrhoid.sh
Here is the error I am getting:
Error: FIPS_SIG does not specify incore module. Please edit this script.
There is no mention of how to configure FIPS_SIG in the wiki. Looks like the script is looking for a file or directory called "incore." I searched through my $ANDROID_NDK_ROOT. However, i don't have any "incore" file.
The next command I need to run is the following:
$ ./config shared -no-ssl2 -no-ssl3 -no-comp -no-hw -no-engine \
--openssldir=/usr/local/ssl/$ANDROID_API
Here, is openssldir pointing to absolute /usr/... directory? I am hoping the eventual header and lib files end up in $ANDROID_NDK_ROOT/platform/android-16/arch-arm directory.
Here is the error I am getting:
Error: FIPS_SIG does not specify incore module. Please edit this script.
Oh, you're right. That has been fixed on the wiki.
I thought there was a comment in the script about "it safe to ignore if...", but it appears there is no comment about it either. Sigh....
The same script is used to build both FIPS Capable and non-FIPS version of the OpenSSL library. Its safe to ignore the FIPS_SIG error if you are not building the FIPS Capable library.
Since your are using OpenSSL and Android, it is safe to ignore. If you were following FIPS Library and Android, then it could not be ignored.
Looks like the script is looking for a file or directory called "incore."
For completeness, incore is a script that embeds the HMAC's fingerprint into the program or shared object. The FIPS Object Module will use the embedded HMAC to integrity test itself at startup. Its pretty useless in practice since the key is well known ;)
incore is distributed with openssl-fips-2.0.7.tar.gz and friends. Once you put incore somewhere (the directory tree or, for example, /usr/local/ssl/android-18/bin), you set FIPS_SIG to the filename.
$ ./config shared -no-ssl2 -no-ssl3 -no-comp -no-hw -no-engine
--openssldir=/usr/local/ssl/$ANDROID_API
Here, is openssldir pointing to absolute /usr/... directory? I am hoping the eventual header and lib files end up in $ANDROID_NDK_ROOT/platform/android-16/arch-arm directory.
--openssldir is the install directory. You should set it to $ANDROID_NDK_ROOT/platform/android-16/arch-arm if that's where you want the library installed.
A little more info: by default, OpenSSL will install itself at /usr/local/ssl. When I build iOS, is use --openssldir=/usr/local/ssl/ios. When I build Android, --openssldir=/usr/local/ssl/android-18 (or android-14, etc).
For example, here's what mine looks like on a Mac Book:
$ ls /usr/local/ssl/
android-14 darwin macosx-x64
android-18 ios macosx-x86
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