Android - use generated C files with JNI - android

I am trying to create an application using C files.
In fact, the C files were generated from matlab (~20 files, with .c and .h), and I didn't modify those files.
To use those files with JNI, I create an other C file which is using JNI : native-lib.c.
So the C files generated by matlab are used through native-lib.c (I used a tuto found on the web to write this file).
I have this architecture for the c files :
src/
-- jni/
---- native-lib.c
---- include/
-------- All the c files generated from matlab
And this is native-lib.c (that I simplify here):
#include <jni.h>
#include "include/function1.h"
JNIEXPORT jint JNICALL
My_project_function1(JNIEnv* env, jobject obj, Function1_Args args) {
int x = function1(args);
return x;
}
etc...
To build the C library I use this file : CMakeList.txt :
cmake_minimum_required(VERSION 3.4.1)
add_library(native-lib SHARED src/jni/native-lib.c)
include_directories(src/jni/include)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
But this file CMakeList.txt doesn't work ! All the files in the folder include/ are not included in the project (only native-lib.c is recognize).
So I want to include the files of the include/ folder WITHOUT modify them (without adding JNIEXPORT, JNICALL, etc...).
I almost never use C, and I know nothing about the C generation. So I don't know how to do, and I don't understand most of the answers found on the web :(
Is someone understand why CMakeList.txt doesn't work? Do you have a solution to solve my problem ?
Thanks !

I am not familiar with CMake, however, You probably want to either add the src/jni/include folder as a second library source and static link to native-lib, or add the contents of src/jni/include directly to the arguments of add_library(native-lib SHARED ...). Please note that include_directories are for #include paths and not for src locations.

Finally I found a solution to my problem :
It is very simple in fact :
cmake_minimum_required(VERSION 3.4.1)
file(GLOB sources_c
"src/jni/include/*.h"
"src/jni/include/*.c"
"src/jni/native-lib.c"
)
add_library(native-lib SHARED ${sources_c})
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
I just put all the C files in the variable sources_c with file(GLOB sources_c ...).
And, in CMakeList.txt, it seems that there is any distinction between pure C files and JNI-C files (C files with, JNIEXPORT, ect ...).
I hope it will help !

Related

Android Studio: CMake is not finding Boost header files

I included a Boost-Header file to my test project using CMakeLists.txt. My some.cpp can include this header without any error, but i'm not able to run since the header file relies obviously on other Boost headers and its not finding the required files. The location of my files is in cpp folder and the boost files are in (C:\boost) a subdirectory:
..\src\main\cpp\boost\RequiredHeader.hpp.
For the include files in the "RequiredHeader" the compiler is looking at:
..\src\main\cpp\boost\boost\AnotherHeader.hpp.
CMakeLists.txt (Boost-part)
# ADD BOOST
message("Import Boost...\n")
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_INCLUDE_DIRS C:/boost_1_64_0/boost)
find_package(Boost 1.64.0)
if(Boost_FOUND)
message("Boost found! Link libraries...\n")
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(myDependantLib ${Boost_LIBRARIES})
endif()
Your help is highly appreciated!
Updated question:
How to tell CMake where my Boost header files are, since it still is not finding the right location, with BOOST_ROOT set?
Updated CMakeLists.txt
# ADD BOOST
message("Add boost...\n")
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(BOOST_ROOT C:/boost_1_64_0)
set(BOOST_INCLUDE_DIR C:/boost_1_64_0/boost)
FIND_PACKAGE(Boost 1.64.0 COMPONENTS foreach REQUIRED)
if(Boost_FOUND)
message("Boost found! Link libraries...\n")
target_link_libraries(calculator LINK_PUBLIC ${Boost_LIBRARIES})
endif()
This post here helped me in resolving this.
Include Boost-Header files and libs:
set(BOOST_ROOT C:/boost)
The path containing the include headers "boost/*.hpp" and libraries "stage/lib" or any other path where your compiled files have been output.
Then you need to specify the include header and libs paths. In the default case the headers are stored in the same directory as the root (since "boost" folder is searched automatically) and the libs as described in "stage/lib". Otherwise it should be "include" and "lib" of your output directory, while the boost version has to be corresponding to the one specified in version.hpp in the "boost" folder:
set( Boost_INCLUDE_DIR ${BOOST_ROOT}/include )
set( Boost_LIBRARY_DIR ${BOOST_ROOT}/lib )
set( Boost_Version 1_64 )
find_package( Boost ${Boost_Version} COMPONENTS system thread )
if( Boost_FOUND )
target_include_directories( <your_lib> PUBLIC/PRIVATE ${Boost_INCLUDE_DIR} )
# its possible to include boost to system path too:
# include_directories( SYSTEM ${Boost_INCLUDE_DIR} )
link_directories( ${Boost_LIBRARY_DIR} )
target_link_libraries( <your_lib> ${Boost_LIBRARIES} )
endif()
Then i was able to simply:
#include <boost/random.hpp>
#include <boost/whatever.hpp>
This worked for me on following environment:
Android Studio 2.3.1 and 3.0
NDK 14.1
Boost 1.56.0 and 1.64.0
Windows 10
If further explanation is needed, please comment your concerns!

Android NDK CMake linking issues

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)

Android NDK cmake JNI static library

Because of security concerns I would like to link all libraries statically including my native library containing JNI_OnLoad function. I've read that it's possible to link JNI library statically (http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#library_version) but I fail to do it with Android Studio. Is it possible?
Here's what I have currently.
In Java code:
System.loadLibrary("testlibrary");
In cmake makefile:
add_library( testlibrary
STATIC
${mysources} )
target_link_libraries(testlibrary)
In C++ file:
extern "C" {
EXPORT
JNIEXPORT jint JNICALL JNI_OnLoad_testlibrary(JavaVM *vm, void *reserved) {
...
return JNI_VERSION_1_8;
}
When built with Android Studio application fails because it tries to find *.so library file:
java.lang.UnsatisfiedLinkError:
dalvik.system.PathClassLoader[DexPathList[[zip file
"/data/app/xxx-1/base.apk"],nativeLibraryDirectories=[/vendor/lib,
/system/lib]]] couldn't find "libtestlibrary.so"
System.loadLibrary("testlibrary");
This line tries to load libtestlibrary.so, and obviously it wasn't built and packed into APK, since library with this name is static one:
add_library( testlibrary
STATIC
${mysources} )
Here you've described target libtestlibrary.a, that is not loadable, and can only be linked against loadable .so. So to achieve desired result you should declare testlibrary as shared one, and then link it against another static libraries. As result you'll get one, monolitic shared library, that can be loaded into program address space. E.g
add_library(testlibrary SHARED ${mysources})
add_library(lib1 STATIC ${lib1_src})
add_library(lib2 STATIC ${lib2_src})
...
target_link_libraries(testlibrary lib1 lib2 ...)

How to link crypto shared library in Android JNI

I am writing a wrapper to use some functions of crypto.
I build crypto lib from openssl-android with Android-NDK. Now i have the libcrypto.so that i need, but i donĀ“t know how to link it with my wrapper.
My project tree is like this
(proj root)
|
|->(src)
|->(src)-> com.package
|->(src)-> com.package->NativeCipher.java
|
|->(jni)
|->(jni)->Android.mk
|->(jni)->NativeCipher.c
NativeCipher.java
public class NativeCipher {
static {
System.loadLibrary("crypto");
System.loadLibrary("NativeCipher");
}
public static native byte[] AESEncrypt(byte[] in, byte[] key);
}
NativeCipher.c
#include <string.h>
#include <jni.h>
#include <aes.h>
jbyteArray Java_com_package_NativeCipher_AESEncrypt(JNIEnv* env, jobject this, jbyteArray in, jbyteArray key)
{
// All my code here
}
I need to use the functions of #include that crypto provides.
However, i don't know what to do with the .so files that NDK generates and how to make the Android.mk file to build.
Thanks in advance, i tried to be as specific as posible.
Native libraries go to the libs/armeabi or libs/armeabi-v7a of your Android project. You might want to rename the OpenSSL library though, because the system already has a libcrypto.so. As for your own JNI wrapper, just take the shared library sample from the NDK and modify to use your own files.

how to use libssl.so in an android project?

I did build the libssl.so from openssl project with Android NDK under the mac os x shell and now I would like someone to tell me how i can use it in Eclispe and in my android project ?
Is it ok if I drag and drop the file in the project root directory ??
How can I access the library function from the code ??
I saw this example :
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndkfoo");
}
// declare the native code function - must match ndkfoo.c
private native String invokeNativeFunction();
...
file ndkfoo.c :
jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
But the libssl.so has it own functions list and they not named with my java class name i guess...
Any idea ?
to link .so file to yr project, u need to right click project->properties->Java Build Path->Library->Android 2.* -> Native Library location ->Edit -> browse to .so file folder path

Categories

Resources