I'm trying to link a Shared Library that I generated with the NDK-Standalone toolchain on a different build machine. Then using that specific .so I put it on Android Studio. From there I created a jni.h file using javah which then helped me write the .c JNI for the function calls.
Followed this example How do I compile any native (C, C++) library using NDK in the form of shared libraries .
ndk-build does compile and seems to work correctly but when trying to run the application on the phone I get a error at
static {
System.loadLibrary("testLib")
}
Saying that could not find testLib.so even though it is generated and in the libs/armeabi-v7a/testLib.so directory
CURRENT ERROR:
01-31 14:41:53.779 19024-19024/com.jolopy.testing_02 E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.jolopy.testing_02, PID: 19024
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.jolopy.testing_02-2/base.apk"],nativeLibraryDirectories=[/data/app/com.jolopy.testing_02-2/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "testLib.so"
at java.lang.Runtime.loadLibrary(Runtime.java:367)
at java.lang.System.loadLibrary(System.java:1076)
at com.jolopy.testing_02.TestLib.<clinit>(TestLib.java:6)
at com.jolopy.testing_02.MainActivity.onCreate(MainActivity.java:18)
How I built the .so file:
arm-linux-androideabi-gcc -c -fPIC testLib.c -o test.o
arm-linux-androideabi-gcc test.o -o testing.so
From there I wrote a JNI wrapper class using javah which generated the testing_Android.h file. Which from there generated the testing_Android.c JNI wrapper that I'm using to call functions from my testLib.c library:
#include "testLib.h"
//Including Machine Generated Header
#include "testing_Android.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Initialize
(JNIEnv *env, jobject obj){
(void)env;
(void)obj;
testing_Initialize();
}
JNIEXPORT jint JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Get_1Count
(JNIEnv *env, jobject obj){
(void)env;
(void)obj;
return(testing_Get_Count());
}
JNIEXPORT jint JNICALL Java_com_jolopy_testing_102_TestLib_testinglib_1Get_1CurrentName
(JNIEnv *env, jobject obj, jlong ptr, jint x){
(void)env;
(void)obj;
return (testing_Get_CurrentName((char *)ptr , (int)x));
}
From there I have 5 files in the jni folder in Android which is where I run the ndk-build command from:
testing.so | testing_Android.h | testing_Android.c | Application.mk | Android.mk
Android.mk:
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testLib
LOCAL_SRC_FILES := testing.so
LOCAL_EXPORT_C_INCLUDES := testing_Android.c
include $(PREBUILT_SHARED_LIBRARY)
Application.mk:
APP_PLATFORM := android-19
APP_ABI := armeabi-v7a
Any suggestions or faults in my progress that you might see that I don't would be greatly appreciated.
-Cheers!
Change below
APP_ABI := armeabi-v7a
to
APP_ABI := arm64-v8a
Because from your error logs, your device is arm64 ABI.
If you are starting a new Android NDK project, I would like to suggest you start from Android Studio + CMake tool chains, see here for my personal JniExample project based on Android Studio and CMake:
https://github.com/russell-shizhen/JniExample
https://stackoverflow.com/a/52951886/8034839
Instead of using the ndk standalone toolchain, I used the ndk-build on my build machine which then generated the libs file I needed. From there I added the libs file with the contents of:
arm64-v8a
armeabi-v7a
x86
x86_64
Into my Android directory under src>main>jniLibs which then stored all the files and just added the command to my app build.gradle:
sourceSets.main{
jniLibs.srcDir 'src/main/jniLibs'
}
For ndk-build to work properly I had to include the jniWrapper.c file.
Android.mk:
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testing
LOCAL_SRC_FILES := jniWrapper.c \
testLib.c
include $(BUILD_SHARED_LIBRARY)
Application.mk (I was testing with "all" but its unneeded):
APP_PLATFORM := android-23
APP_ABI := all
I know this is a work around solution but for some reason I could not figure out the toolchain to work correctly.
Related
I'm trying to add firebase c++ sdk to my cocos2d-x 3.14 game. So far I've create Android.mk in firebase_cpp_sdk directory:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := firebase-prebuilt
LOCAL_SRC_FILES := libs/android/$(TARGET_ARCH_ABI)/c++/libapp.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := firebase-analytics
LOCAL_SRC_FILES := libs/android/$(TARGET_ARCH_ABI)/c++/libanalytics.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_STATIC_LIBRARY)
Then in my project in Android.mk I've added:
LOCAL_C_INCLUDES += /Users/piotr/Documents/pierdoly/firebase_cpp_sdk/include
LOCAL_STATIC_LIBRARIES += firebase-prebuilt firebase-analytics
$(call import-add-path, /Users/piotr/Documents/pierdoly/firebase_cpp_sdk)
I can sync gradle and build project.
I also can
#include <firebase/app.h>
in AppDelegate.cpp (or h) and it works fine. Even Android studio can see all firebase headers and I can inspect them.
Now, in applicationDidFinishLaunching I've added this:
#if (CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID)
::firebase::App* app = ::firebase::App::Create(::firebase::AppOptions());
#else
::firebase::App* firebaseApp = ::firebase::App::Create(::firebase::AppOptions(), cocos2d::JniHelper::getEnv(), cocos2d::JniHelper::getActivity());
#endif
There's also alternative version via JNICALL from AppActivity.java (to pass correct activity as some say solution above doesn't work):
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_initFirebase(JNIEnv* env, jobject thiz)
{
::firebase::App* app = ::firebase::App::Create(::firebase::AppOptions(), env, thiz);
}
#endif
Yet my problem is: it won't even compile. There's linker error:
Error:(141) undefined reference to 'firebase::App::Create(firebase::AppOptions const&, _JNIEnv*, _jobject*)'
I can clearly "go" into this function in Android Studio and I've rechecked twice parameters I'm giving. They're fine. Yet linker yells at me.
How can I fix linker? What am I missing here?
I had the same problem but found the answer:
It's about the order of the libraries being linked.
You just have to rearrange it like this:
LOCAL_STATIC_LIBRARIES += firebase-analytics firebase-prebuilt
And it should work.
Say thanks to the guys in this github issue
Cocos uses different utils for native libraries build, it can be cmake or ndk util, so check in your frameworks/runtime-src/proj.android/gradle.properties option PROP_BUILD_TYPE and change if it needs from cmake to ndk-build
then look on build.gradle at frameworks/runtime-src/proj.android/app/build.gradle it must use ndk-build correctly.
I'm trying to modify this tutorial to include a prebuilt C library in my Android Studio project (ie. not using the experimental Gradle plugin) http://kvurd.com/blog/compiling-a-cpp-library-for-android-with-android-studio/
The library itself is coming from a client who won't reveal the source code, therefore I have no control over that part of the build process, however they are already following the same tutorial.
The project builds, load-library works and the NDK link (/jni/my-wrapper.c) works fine, until I try to call the actual library function defined in my prebuild header. The error I'm receiving is:
$ ndk-build
[arm64-v8a] Compile : my-wrapper <= my-wrapper.c
[arm64-v8a] SharedLibrary : libmy-wrapper.so
/Users/me/AndroidStudioProjects/MyProject/app/obj/local/arm64-v8a/objs/my-wrapper/my-wrapper.o: In function `Java_com_my_project_SignInActivity_CallFunction':
/Users/me/AndroidStudioProjects/MyProject/app/jni/my-wrapper.c:44: undefined reference to `MyFunction'
collect2: error: ld returned 1 exit status
make: *** [/Users/me/AndroidStudioProjects/MyProject/app/obj/local/arm64-v8a/libmy-wrapper.so] Error 1
Here's my Android.mk:
LOCAL_PATH := $(call my-dir)
# static library info
include $(CLEAR_VARS)
LOCAL_MODULE := libMyLib
LOCAL_MODULE_FILENAME := libMyLib
LOCAL_SRC_FILES := ../prebuild/libMyLib.a
LOCAL_EXPORT_C_INCLUDES := ../prebuild/include
include $(PREBUILT_STATIC_LIBRARY)
# wrapper info
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += ../prebuild/include
LOCAL_MODULE := my-wrapper
LOCAL_SRC_FILES := my-wrapper.c
LOCAL_STATIC_LIBRARIES := libMyLib
include $(BUILD_SHARED_LIBRARY)
And MyLib.h (note that foobar() works fine as it's in the header but as long as I'm calling MyFunction from within my-wrapper.c the ndk-build fails):
#include <math.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int MyFunction(some stuff);
int foobar(){return 1;};
Finally, my-wrapper.c:
#include <MyLib.h>
jbyte Java_com_my_project_SignInActivity_MyFunction(JNIEnv *env, jobject thiz, some other stuff){
// return MyFunction(some other stuff which I cast to C types); //linker fails if uncommented
return foobar(); //works fine
}
That's a C++ mangled name. You can only use it from C++, not from C.
If you really need to call it from C, you might be able to do it like so:
extern int _Z12MyFunctionP9my_structPhS1_S1_(/* whatever the function args are */);
jbyte Java_com_my_project_SignInActivity_MyFunction(
JNIEnv *env, jobject thiz, some other stuff) {
return _Z12MyFunctionP9my_structPhS1_S1_(args);
}
That depends on the code you're calling being compatible as such (if that's the case, you should ask the client to build their APIs as extern "C").
I'd really recommend just moving your code to C++ though.
I use PTAM code taken from here. I try to make an android application with this code.
The PTAM code uses libcvd, TooN, gvars3 library. I generate a .so file from my c++ test file using ndk-build.
Firstly, I try to run below code on android phone :
#include <string.h>
#include <jni.h>
extern "C" {
int returnInt()
{
int returnVal = 4;
return returnVal;
}
}
It can generate .so file without any errors. If I add #include < TooN/TooN.h > , `ndk-build says that
fatal error: TooN/TooN.h: No such file or directory
#include <TooN/TooN.h>
^
compilation terminated.
Android.mk is :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test-jni
LOCAL_SRC_FILES := test-jni.cpp
include $(BUILD_SHARED_LIBRARY)
How can I solve this error message?
fatal error: TooN/TooN.h: No such file or directory
#include <TooN/TooN.h>
When you use <> with #include, the compiler will search for the file in your include path (and possibly other predefined directories).
To add a directory to your include path when building a module in Android.mk you would add it to LOCAL__INCLUDES. For example, if the full path to TooN.h is /home/foobar/TooN/TooN.h you should do this:
LOCAL_C_INCLUDES += /home/foobar
I get fatal error: iostream: No such file or directory.There is no folder named iostream under usr/include or usr/local/include.
The iostream class is part of the STL, so you need to specify an STL implementation to build against. This can be done using the APP_STL variable in Application.mk. For example:
APP_STL := gnustl_shared
See this page for a list of STL implementations available with the NDK.
So I'm attempting to use libopus on my native code for an Android application.
My Android.mk file looks like this:
PLATFORM_PREFIX := /opt/android-ext/
LOCAL_PATH := $(PLATFORM_PREFIX)/lib
include $(CLEAR_VARS)
LOCAL_MODULE := libopus
LOCAL_SRC_FILES := libopus.a
include $(PREBUILT_STATIC_LIBRARY)
# I have to redeclare LOCAL_PATH because the library is in /opt/android-ext/
# and my project is somewhere else. Not very elegant.
LOCAL_PATH := /home/sergio/workspace/Project/jni
include $(CLEAR_VARS)
LOCAL_MODULE := opusUtilsNative
LOCAL_SRC_FILES := opusUtilsNative.c
LOCAL_C_INCLUDES += $(PLATFORM_PREFIX)/include
LOCAL_STATIC_LIBRARIES := android_native_app_glue libopus
include $(BUILD_SHARED_LIBRARY)
And my code in opusUtilsNative.c looks like this:
#include "opusUtilsNative.h"
#include <opus/opus.h>
#include <opus/opus_types.h>
JNIEXPORT jbyteArray JNICALL Java_Project_OpusUtils_encode
(JNIEnv * je, jclass jc, jbyteArray data){
int rc;
opus_int16 * testOutBuffer;
unsigned char* opusBuffer;
OpusDecoder *dec;
dec = opus_decoder_create(48000, 2, &rc);
return data;
}
And when I try to build it, it works fine only if I remove the line that uses the "opus_decoder_create" function. Else I will get this:
error: undefined reference to 'opus_decoder_create'
I can see that opus_decoder_create is clearly defined on opus.h, which is clearly being included since if I exclude that line, I'll get an error regarding the opus_int16 and OpusDecoder declarations. How come some definitions are being included and some aren't?
Any help will be greatly appreciated.
This was tricky. After digging around for a bit, I realized I hadn't cross-compiled the opus library correctly, and I didn't have an ARM binary after all.
A good way to verify if your library was cross-compiled correctly:
cd /opt/android-ext/lib #Or wherever the .a file is
ar x libopus.a
file tables_LTP.o #Or any of the .o files generated by ar x
The output should look like this:
tables_LTP.o: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
Otherwise, you might want to double-check your cross-compilation process.
It's error from linker, not from compiler. You forgot to add reference to correspondent libraries to your Android.mk file, do smth like this:
LOCAL_LDLIBS += -lopus
I forgot to integrate one key library
LOCAL_LDLIBS := -lGLESv2
This fixed my problem.
I'm doing the following tutorial http://mobile.tutsplus.com/tutorials/android/ndk-tutorial/.
And I can't seem to compile properly. I get the following error:
dyld: unknown required load command 0x80000022
dyld: unknown required load command 0x80000022
Compile thumb : ndk1 <= native.c
dyld: unknown required load command 0x80000022
make: *** [obj/local/armeabi/objs/ndk1/native.o] Trace/BPT trap
I'm running Mac OS X 10.5.8. I'm using Gnu Make 3.81. I'm using the awk that ships with mac os x. And I'm using android ndk r7b.
The dyld error seems to pop up with a lot of code compiled for 10.6 and then tried on a 10.5.8 machine.
Android.mk make file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := ndk1
LOCAL_SRC_FILES := native.c
include $(BUILD_SHARED_LIBRARY)
native.c file:
#include <jni.h>
#include <string.h>
#include <android/log.h>
#define DEBUG_TAG "NDK_NDKtestActivity"
void Java_my_mumbo_jumbo_NDKtestActivity_helloLog(JNIEnv * env, jobject this, j\
string logThis)
{
jboolean isCopy;
const char * szLogThis = (*env)->GetStringUTFChars(env, logThis, &isCopy);
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", szLogThis);
(*env)->ReleaseStringUTFChars(env, logThis, szLogThis);
}
Am I not including an android library in my path possibly? I've only added the android r7b folder to my path so i could find ndk-build?
Thanks,
Thomas
Please look at this links.it may be helpfull..
http://psrdotcom.blogspot.in/2011/12/android-ndk-jni-windows-xp7-with-3264.html#!http://psrdotcom.blogspot.com/2011/12/android-ndk-jni-windows-xp7-with-3264.html
http://marakana.com/forums/android/examples/49.html
http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/
You need to downgrade to NDK 6b as shown here:
https://ar.qualcomm.at/arforums/showthread.php?t=1590
Vaclav