How to resolve the java.lang.UnsatisfiedLinkError in NDK in Android? - android-ndk

I am new in ndk development in android.I have gone through the file system of ndk android.
Here, explaining what i have done.
1) i have created a folder named "jni" then create 2 file named Android.mk and ndkfoo.c.
In Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and source file(s)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.c
include $(BUILD_SHARED_LIBRARY)
and in ndkfoo.c
#include <string.h>
#include <jni.h>
jstring Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
then i have created NdkFooActivity class, in which i have written
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndkfoo");
}
But now when i build from cygwin in xp it creates .so file successfully then i run as android application. It gives me java.lang.UnsatisfiedLinkError in LOGCAT.
So, Please let me know where i am wrong.
Thanks in Advance,

I think you forgot to change the package name.
Java_com_mindtherobot_samples_ndkfoo
It should be your package what you have specified creating project.

Also(just ran into this issue), please note that System.loadLibrary() will always throw an exception if you are testing on the Intel Atom x86 emulator. It works just fine on regular Android emulators and debugging on a physical device.

Although this has not been the OP's problem, I had the same java.lang.UnsatisfiedLinkError because of missing
static {
System.loadLibrary("mylibraryname");
}

There's a good chance the signature is wrong, as others have mentioned.
If you run the javah utility, you can find the exact signature. From the bin folder in your project, where the .apk is and the root of the Java class hierarchy is generated, run:
javah -o jni_sig.h com.mindtherobot.whatever.your.package.is.NdkFooActivity
...and, if you got the package name and class name correct, it will write out a header (called jni_sig.h) with the correct function signature(s) for any native functions. Copy that to your header and .c file, adding parameters as needed, and it should work correctly.

Maybe not relevant anymore but as far as I know you also need to add the "lib" prefix to your native library name. In your case you need to change the Android.mk to
"LOCAL_MODULE := libndkfoo" and keep "System.loadLibrary("ndkfoo");" as it is. Check the ndk sample code.

I'm pretty sure that should be:
JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
Which SDK are you targeting and which version of the NDK do you have? Does the error you're getting say that it couldn't load the library at all or that there was an unimplemented method? Either way make sure you don't have android:hasCode="false" set on the application tag in your manifest.
You can also open up the APK file after a build using winrar or something similar to make sure that the libndkfoo.so file is actually being included with the package.
Either way if you aren't declaring the native function in NdkFooActivity you will get that error, i.e.
public static native String invokeNativeFunction();

JNIEXPORT jstring JNICALL Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction(JNIEnv* env, jobject javaThis) {
return (*env)->NewStringUTF(env, "Hello from native code!");
}
the problem is that you compile for a target processor and execute in other. if you compile in ARM(armeabi) then execute in armeabi based emulator.
create a file called application.mk in same folder as Android.mk and put inside it one of this:
APP_ABI := x86
APP_ABI := armeabi
APP_ABI := mips
APP_ABI := armeabi x86 mips //to compile in all target and you will get 3 *.so files
then compile->run.
it should work.

Create a file Application.mk in jni folder.Copy following line and paste it to Application.mk and save.Now build the project with your cgywin and run again
APP_ABI := armeabi armeabi-v7a

The method name Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction
may be not same as that of your package name or class name.
To make this naming of method exactly same you must use javah.
This will make a header file which will be having the same method name that is required.To make this header file go to the classes folder in the bin of your project(make sure you have created the java file with static method and build it properly) by this command in your terminal
~/workspace/Android_Example2/bin/classes$
In this directory write the following command
sudo javah -jni com.NDK.android_example2.MainActivity
Change the package name and class name according to your project.This will create a com_NDK_android_example2_MainActivity.h in your classes folder.
Simply move this file into your jni folder. In this file, there will be static methods that you have created in the MainActivity.java file but they are just declared not implemented that you will implement in your C file.
NOTE: While Coping the method check that the method parameters are need to be declared, so make them declare in your C file.
Hope this help.

Replace this
Java_com_mindtherobot_samples_ndkfoo_NdkFooActivity_invokeNativeFunction
With
Java_your_packege_name_your_Activity_Name_invokeNativeFunction
Example if your package is com.pack and Activity Name name is MainActivity then
Java_com_pack1_MainActivity_invokeNativeFunction
Don't forget to add reference in Activity.
// load the library - name matches jni/Android.mk
static {
System.loadLibrary("ndkfoo");
}
public native String invokeNativeFunction();
Repeat all these step it should work :)

I also had a java.lang.UnsatisfiedLinkError error. I verified everything mention in above answers but was still getting the error. I eventually discovered that the JNI method names cannot have underscores.
Example:
Java_com_example_app_NativeLib_print_out_stuff <- generates java.lang.UnsatisfiedLinkError: print_out_stuff
Rename the print_out_stuff function to something without underscores:
Java_com_example_app_NativeLib_printOutStuff <- works

here's a tutorial how to use native code: here
make sure you dont have any spaces in your project path.
also you cant use an underscore in your package or project name.

Related

CMake Precompiled Headers not including correctly for Visual Studio

So I've recently started using the "new" target_precompile_headers command for CMake to generate and include my precompiled headers.
But for some reason it doesn't seem to work at all the way I want it.
I do understand that the usage of this command is to provide the list of headers to include in your pch and that CMake itself generates the actual pch. This seem to work just fine as I can see the pchs generated for each config & project in my solution.
However looking at the project properties, and more specifically looking at the .cpp properties the /FI command is always empty, which means no files are force included.
This also means that none of my cpp catches that I am using pch at all and my compile fails.
Does anyone have any suggestions on what could be wrong?
// Example of a CMakeLists.txt which defines a static lib using PCH
file(GLOB ALL_SOURCE_FILES "*.cpp" "*.h")
add_library(MyLib STATIC ${ALL_SOURCE_FILES})
target_precompile_headers(MyLib PRIVATE MyHeader.h)
Below you see my own lib created with the snippet above. As you can see, no Forced Include file is added, thus no cpp files gets the PCH included.
I found this workaround: Adding the compiler option manually...
if(MSVC)
target_compile_options(YourProject PRIVATE "/FI${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/$<CONFIG>/cmake_pch.hxx")
endif()
(Currently using Cmake 3.24.1 with cmake_minimum_required(VERSION 3.18) in the file)

Android NDK, CMake with other libraries

So I am trying to build and test out a CMake with the Android NDK on Android Studio. I can get my library to compile, but it doesn't seem to want to pull any third-party dependencies over. I've been reading through the toolchain and looking for better documentations, with no luck. Can someone tell me if I am missing?
cmake_minimum_required(VERSION 3.4.1)
set(SFML_PATH ${ANDROID_NDK}/sources/sfml)
set(SFML_LIB_PATH ${SFML_PATH}/lib/${ANDROID_NDK_ABI_NAME})
set(SFML_LIB_SYSTEM ${SFML_LIB_PATH}/libsfml-system.so)
set(SFML_LIB_AUDIO ${SFML_LIB_PATH}/libsfml-audio.so)
set(SFML_LIB_GRAPHICS ${SFML_LIB_PATH}/libsfml-graphics.so)
set(SFML_LIB_NETWORK ${SFML_LIB_PATH}/libsfml-network.so)
set(SFML_LIB_WINDOW ${SFML_LIB_PATH}/libsfml-window.so)
set(SFML_LIB_ACTIVITY ${SFML_LIB_PATH}/libsfml-activity.so)
set(SFML_LIB_MAIN ${SFML_LIB_PATH}/libsfml-main.a)
set(SFML_LIBS ${SFML_LIB_SYSTEM} ${SFML_LIB_GRAPHICS} ${SFML_LIB_AUDIO} ${SFML_LIB_WINDOW} ${SFML_LIB_ACTIVITY})
include_directories(${SFML_PATH}/include)
link_directories(${SFML_LIB_PATH})
add_library(native-lib SHARED
src/main/cpp/native-lib.cpp)
target_link_libraries(native-lib log ${SFML_LIBS})
#file(COPY ${SFML_LIBS} DESTINATION ${__android_install_path})
FOREACH(SFML_LIB ${SFML_LIB})
execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SFML_LIB}" "${LIBRARY_OUTPUT_PATH}/${SFML_LIB}" RESULT_VARIABLE __fileCopyProcess )
MESSAGE("Lib: ${SFML_LIB}")
ENDFOREACH(SFML_LIB)
Above is my CMakeLists.txt. I have done a little hacking to get it to compile with SFML with the paths, as I have not found good documentation with CMake and Android yet.
May you add more info for:
"but it doesn't seem to want to pull any third-party dependencies over."?
this one:
https://github.com/googlesamples/android-ndk/tree/master/hello-libs
has static and shared 3rd party libs, you may try it.
For the shared dependent lib, you will need to pack them into APK, that is done inside gradle, cmake will not do it.
The above example shows that, basically they need to be copied into your app/src/main/jniLibs too so they will be packed into apk, and pushed to your android phone/tablet. At runtime they could be loaded.
I have tried to put a group of libraries into one directory, and use
link_directories(...)
then just put the lib names directly into
target_link_libraries(...)
also works. Make sure you have the right libs for the ABIs you intend to support for your app [looks like you are just building for one ABI].
The process could be little long it will depend on your android skills.
An example could be similar to this process:
Crosscompile sfml.
Create your jni bridge
Generate with cmake the project and compile
Copy your files to android studio. create java loading library code.
I guess that you have crosscompiled sfml and you know how works crosscompiling process, if I am wrong check these link below:
Tutorial:
https://github.com/SFML/SFML/wiki/Tutorial:-Building-SFML-for-Android
Source code:
https://github.com/SFML/SFML
Toolchain:
https://github.com/SFML/SFML/blob/master/cmake/toolchains/android.toolchain.cmake
Changes on your cmake:
add this file
FIND_PACKAGE(SFML required)
In cmake put your SFML build directory and cmake will fills your VARIABLES
automatically for instance this variables:
set(SFML_PATH ${ANDROID_NDK}/sources/sfml)
set(SFML_LIB_PATH ${SFML_PATH}/lib/${ANDROID_NDK_ABI_NAME})
set(SFML_LIB_SYSTEM ${SFML_LIB_PATH}/libsfml-system.so)
set(SFML_LIB_AUDIO ${SFML_LIB_PATH}/libsfml-audio.so)
set(SFML_LIB_GRAPHICS ${SFML_LIB_PATH}/libsfml-graphics.so)
set(SFML_LIB_NETWORK ${SFML_LIB_PATH}/libsfml-network.so)
set(SFML_LIB_WINDOW ${SFML_LIB_PATH}/libsfml-window.so)
set(SFML_LIB_ACTIVITY ${SFML_LIB_PATH}/libsfml-activity.so)
set(SFML_LIB_MAIN ${SFML_LIB_PATH}/libsfml-main.a)
There are two ways to make android studio native apps:
Easy way:
Create JNI bridge:
Crosscompile your cmake script and copy your lib to app/src/main/jniLibs
add library in execution time
code:
try
{
Log.v(LOG_TAG, "adding your library");
System.loadLibrary(your_library);
}
catch(UnsatisfiedLinkError e)
{
Log.e(LOG_TAG,e.getMessage());
}
More complete way (it allows to debug library)
Create your ndk module in gradle
example
android.ndk {
moduleName = "your_library"
cppFlags.add("-fexceptions")
//cppFlags.add("-std=c++11")
//cFlags.add("-fopenmp")
cppFlags.add("-I" + file("src/main/jni").absolutePath)
stl = "gnustl_shared" // Which STL library to use: gnustl or stlport
ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log", "z"])
String libsDir = curDir.absolutePath + "/src/main/jniLibs/armeabi/"
ldLibs.add(libsDir + "your_native_lib.so")
}

$(build_executable) producing shared object

I'm trying to create an native executable for android and it keeps crashing. testing the file with readelf and objdump revivals that the file is considered to be an shared object file.
I'm using the r8e and compiling with ndk-build
test.c:
int main(){
return 0;
}
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC FILES := test.c
LOCAL_MODULE := test
include(BUILD_EXECUTABLE)
--
Setting the app_platform to android-9 results in the creation of an executable file ( and no crashes).
Have you tried specifying arguments int args and char *argv[] for your main() method? Also, where are you trying to run it?
I confirm this bug... I had a project that compiled perfectly with ndk-r8, but when I switched to ndk-8e my executable did not build properly anymore.
I reported it here: https://code.google.com/p/android/issues/detail?id=55769
Here is the answer I got from google:
This is normal.
By default, when targetting API level 17 or higher, "Position Independent Executables" (a.k.a. PIE) are generated by the BUILD_EXECUTABLE rule.
These are executable binaries, but they are only supported on Android 4.1 or higher. See [1] for more details.
If you really don't want these (e.g. because you want your program to run on previous releases of the platform), you have two choices:
Target a lower API level.
Use 'APP_PIE := false' in your Application.mk

NDK - Android Java with native (JNI) C++ code build issue

I am using a mix of Java and native JNI C++ code for an android project, using NDK r8b, in Eclipse in OSX. I want to be able to use the regular C++ classes (map, string) in std namespace.
In the Android.mk file the following were added:
APP_STL := stlport_shared
Here I also tried static library. Refer to http://docs.huihoo.com/android/ndk/r5/CPLUSPLUS-SUPPORT.html
STLPORT_FORCE_REBUILD := true
Also tried removing the forced build.
In the C/C++ path and variables:
${NDKROOT}/sources/cxx-stl/stlport/stlport
"map" and "string" headers were included in the .cpp file. I am able to use std::string and std::map. The assistant picks up on them. When searching for the definition (F3 in eclipse) the header file is shown, i.e. resolved. Also, the outline shows the "string" and "map" header files and when double clicking them it also brings the headers to the forefront.
However, the build doesn't pick them up. I get the following:
> ndk-build
> Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
> Gdbsetup : libs/armeabi/gdb.setup
> Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver
> Gdbsetup : libs/armeabi-v7a/gdb.setup
> Compile++ arm : ImageTargets <= ImageTargets.cpp
> xxx/Project/Code/MyImageTarget/jni/ImageTargets.cpp:20:18: fatal error: string: No such file > or directory
> compilation terminated.
> make: *** [xxx/Project/Code/MyImageTarget/obj/local/armeabi/objs-> debug/ImageTargets/ImageTargets.o] Error 1
Has anyone any idea what else is there to try.
Use V=1 parameter on ndk-build command line. This will echo all executed commands, including compilation and link, with all their parameters that NDK build assigns.
In your case, the answer can be found without detailed build log:
In the Android.mk file the following were added:
APP_STL := stlport_shared
This is your mistake. The document you cited explains that this setting should go into Application.mk. This file is usually considered optional. Yes it is. Instead of creating this file, you can specify APP_STL on the command line:
ndk-build V=1 APP_STL=stlport_static
I don't know why and how Eclipse resolves #include <string> or map.

Android NDK - problem linking an external library (can't found it)

I am working with Android NDK r6b under cygwin (the system is updated correctly). I am modifying the hello-jni sample in order to learn working with NDK. Since i have a library written in C++ that i wish to use in the hello-jni (actually, i have created a prj called helloworld with a single .cpp file called ndkfoo.cpp) sample, i created a new Android project in Eclipse (updated for Android), added a jni directory, added a Android.mk and Application.mk files, edited them in order to compile the .cpp. At the end of the compilation, i obtain a .so file.
Now, in the helloworld Android.mk, i need to make some edits in order to tell the linker to include that library. Suppose the library file is libmylib.so, i have the following android.mk script:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/mylib
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../../mylib/libs/armeabi/ -lmylib
include $(BUILD_SHARED_LIBRARY)
My directories are organized in the following way:
d:/android/android-ndk-r6b => android ndk root
d:/android/workspace/helloworld => helloworld project
d:/android/workspace/mylib => mylib project library
(therefore, the path to libmylib.so is: d:/android/workspace/mylib/libs/armeabi).
Unfortunately, this doesn't seems to work. If i remove every reference to mylib from ndkfoo.cpp, it compiles and run even on my phone. If i do not remove references to mylib, it compiles but doens't link: i obtain the following result:
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo
ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/
bin/ld.exe: cannot find -lmylib
Ps.
I forgot to mention that i run ndk-buld under the jni directory of the helloworld project.
Pss.
I have found a lot of similar questions over the internet. I have always worked with Visual C/C++ IDE, so i am really new to GCC, makefiles and so on...
The message
D:/android/android-ndk-r6b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windo ws/bin/../lib/gcc/arm-linux-androideabi/4.4.3/../../../../arm-linux-androideabi/ bin/ld.exe: cannot find -lmylib
is indicating you that the linker is not finding your library, this should come from a problem in the LD_LIBS' path.
I think that my-dir macro does not include devices' unit identifier so, your LOCAL_PATH variable should miss the D: and, I think, won't work with cygwin. I'm a Linux user and I'm not 100% sure but, if you replace
LOCAL_PATH := $(call my-dir)
by
LOCAL_PATH := D:$(call my-dir)
it should work. On the other hand you can always set the relative path by setting:
LOCAL_LDLIBS += -L$../../mylib/libs/armeabi/ -lmylib

Resources