I am attempting to compile an Android NDK library to use android-ndk-profiler for profiling.
In Audio.h, I have:
extern "C" {
void monstartup(char const*);
void moncleanup();
}
In Audio.cpp, I have:
#include "Audio.h"
com_example_native_init(JNIEnv *env, jobject thiz) {
// Start profiling
monstartup("libDMAudiolib.so");
...
}
I am compiling with
ndk-build NDK_MODULE_PATH=/cygdrive/c/ndk_modules
And the exact compilation error I am getting is
Path/to/Audio.cpp:136: error: undefined reference to 'monstartup'
Are there any android ndk gurus out there who can tell me what's going on?
Sounds like monstartup isn't getting linked in (that looks like a linker error, not a compiler error).
Make sure your Android.mk has the additions shown on the Usage page, particularly the LOCAL_STATIC_LIBRARIES directive.
ndk-build does not work well with cygwin. Please use C:/ndk-modules and similar notation in your scripts.
LOCAL_STATIC_LIBRARIES := android-ndk-profiler
is correct, but it requires that your Andorid.mk includes something like
include $(CLEAR_VARS)
LOCAL_PATH := c:/ndk-modules/android-ndk-profiler
LOCAL_MODULE := android-ndk-profiler
LOCAL_SRC_FILES := libandprof.a
include $(PREBUILT_STATIC_LIBRARY)
(see http://android-ndk-profiler.googlecode.com/svn-history/r11/wiki/Usage.wiki)
This happened to me and it was due to LOCAL_STATIC_LIBRARIES being in the wrong place in the Android.mk file. In particular, it had to be before the line "include $(BUILD_SHARED_LIBRARY)".
Related
I am trying to implement ffmpeg into my Android app.
I already have the prebuilt .so files that I need.
I just can't figure out how to invoke one of the many functions in the library.
Here is what I have thus far:
I've placed each of the .so files under a jniLibs folder
Here is my gradle file
From there, I load the library like this:
static {
Log.e("jni", "starting");
System.loadLibrary("avdevice");
Log.e("jni", "finished");
}
It loads successfully. So far so good.
Next, I look at the .h file to find the methods that I can call. Please note, I am assuming that this .h file is bundled into the .so file. This might be where it all falls apart.
/**
* Return the LIBAVDEVICE_VERSION_INT constant.
*/
unsigned avdevice_version(void);
Since I now know the method name I need to call I place this in my code:
public native int avdeviceVersion();
When I try and call avdeviceVersion(); I get this error message back:
java.lang.UnsatisfiedLinkError: No implementation found for int com.my.app.ApplicationContext.avdeviceVersion() (tried Java_com_my_app_ApplicationContext_avdeviceVersion and Java_com_my_app_ApplicationContext_avdeviceVersion__)
Now, I realize that Java_com_my_app_ApplicationContext_avdeviceVersion doesn't match the method name in the .h file. But, I'm left clueless how to make it match and what to do next. If you know, please explain it as thoroughly as possible. Assume I know nothing :)
Update
I added the Android.mk file as well as the Application.mk, I also added a Jni bridge called video.c.
JNIEXPORT jint JNICALL Java_com_my_app_jni_VideoKit_version(JNIEnv *env, jobject instance, jobjectArray args) {
return (*env)->avdevice_version();}
My Android.mk is this:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := video.c
include $(BUILD_SHARED_LIBRARY)
With these changes the result is the same.
You should configure the environment for using c/c++ classes.
You need CMakeLists.txt or Android.mk / Application.mk.
Then, You should make a class for linking java class and native class.
This link could help you.
As the error messages says,
jint Java_{PACKAGE_NAME}_{CLASS_NAME}_{FUNCTION_NAME}(JNIEnv *env, jobject obj) is needed. And you could call avdevice_version() inside the function.
Update
In Android.mk, first you make prebuilt shared library, and then make linking shared library
include $(CLEAR_VARS)
LOCAL_MODULE := static_avdevice # you can change the name
LOCAL_SRC_FILES = avdevice.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include # header file directory
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include # header file directory
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := jniLinker
LOCAL_SRC_FILES := video.c
LOCAL_STATIC_LIBRARIES := static_avdevice
include $(BUILD_SHARED_LIBRARY)
Then, load library. System.loadLibrary("jniLinker");
And, there are a lot of samples in googlesamples github.
https://github.com/googlesamples/android-ndk/tree/master/hello-libs
This is the code sample for using 3rd-party library. (But it uses CMake.)
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.
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 trying to create a shared library that links to another shared library.
Here is my main module Android.mk:
TOP_LOCAL_PATH := $(call my-dir)
include $(call all-subdir-makefiles)
LOCAL_PATH := $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/ $(LOCAL_PATH)/lib/include
LOCAL_MODULE := SightCore-jni
LOCAL_SRC_FILES := SightDemo.cpp SightCore-jni.cpp
LOCAL_SHARED_LIBRARIES := SightAPI
LOCAL_LDLIBS = -llog
include $(BUILD_SHARED_LIBRARY)
I also have the prebuilt shared library in ./lib directory with its own Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := SightAPI
LOCAL_SRC_FILES := libSightAPI.so
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
The SightCore-jni.cpp source file is the jni interface to the shared library and is loaded using the command
System.loadLibrary("SightCore-jni");
During the ndk-build process I get no compilation or linkage errors.
When I try to run the application and access one of the native methods I get the UnsatsfiedLinkError.
I noticed that if disable the references to the SightAPI in my jni code and put a typo to the LOCAL_STATIC_LIBRARIES := SightAPI line, The build is successful and there is no UnsatisfiedLinkError.
This mean that the jni code I have is good (I'm actually sure it is ok...)
So the observation is as follows:
If I compile the shared library with the prebuilt shared library I get a corrupted .so file.
If I compile the same ndk project without linking to the prebuilt shared library there is no problem loading the shared library from the java side.
Please help me out if you can.
Thanks in advance,
Ita
Found the issue.
Apparently the ndk build system doesn't automatically load referenced shared libraries, even if they are declared in your Android.mk.
I had to call on System.loadLibrary(SightAPI) & System.loadLibrary("SightCore-jni") in order to solve this issue. I would have expected that the only library to load would have been the main library SightCore-jni.
Well..I guess the moral is If you want something done, do it yourself :)
+1 to Roy Samuel for his effort and correct instincts.
I hope this helps anyone.
Cheers
Have you made sure that the cpp function name, that you'd like to use over JNI, is corresponding to the package name of the Java wrapper class where System.loadLibrary("SightCore-jni"); is present?
e.g. If you would like to use the C function, myFunction in the java layer, and suppose your JNI wrapper class is in the package com.my.package.sightcore,
then your C code function name should be like this :
JNIEXPORT JNICALL Java_com_my_package_sightcore_myFunction(JNIEnv * env, jobject thiz, ...)
If you are running your app on your device,
See if the API levels, and hence, the sdk release matches to your device's android version (API level).
Hope this helps. Let me know if you need more clarifications...
This happened to me, and the solution for me was to make sure I was including the proper file libgnustl_shared.so and not libc++_shared.so after I switched compilers. So, just making sure either one of these files is the correct one for your build, and making sure it's been updated with the latest, you shouldn't get this issue any longer.
I can't seem to get the following trivial code to compile/link and the problem seems specific to std::wstring and the gnustl_static C++ library. Any help would be appreciated.
main.cpp file:
#include <string>
int main(void)
{
std::wstring wtest(L"Test");
return 0;
}
Application.mk file:
APP_CFLAGS += -fexceptions
APP_STL := gnustl_static
Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TestWCharApp
LOCAL_CFLAGS := -D_GLIBCXX_USE_WCHAR_T
LOCAL_SRC_FILES := main.cpp
include $(BUILD_EXECUTABLE)
When attempting to link the above application using gnustl_static I get the following error message:
undefined reference to `std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(wchar_t const*, std::allocator<wchar_t> const&)'
If I change APP_STL to stlport_static and define _STLP_HAS_WCHAR_T everything seems to compile/link/run fine. I verify it works by uploading the exe to the emulator and running it via the shell.
I'm going to need to use the gnustl implementation for c++ exception support otherwise I'd go with stlport_shared. Any clues as to why the above sample works for stlport_static but not gnustl_static?
It's a problem with the file $NDK/sources/cxx-stl/gnu-libstdc++/Android.mk
Add the following line to that file:
LOCAL_MODULE_FILENAME := libstdc++
What's your target OS? According to this thread, gnustl_static doesn't support wchar_t prior to 2.3.
From the platforms\android-*\arch-arm\usr\include\wchar.h header file:
/* IMPORTANT: Any code that relies on wide character support is essentially
* non-portable and/or broken. the only reason this header exist
* is because I'm really a nice guy. However, I'm not nice enough
* to provide you with a real implementation. instead wchar_t == char
* and all wc functions are stubs to their "normal" equivalent...
*/
Funny though that running the following simple program in an android emulator show that wchar_t is 4 bytes.
#include <stdio.h>
int main(void)
{
printf("Size of wchar is %d\n", sizeof(wchar_t));
return 0;
}
Another thing to consider. The JNI bridge provides two useful ways to marshal string data. GetStringUTFChars (returns const char ) and GetStringChars (returns jchar). How many bytes do you think a jchar is defined as ... 2.
Make sure you run "ndk-build clean" and manually delete your libs/ and obj/
directories.
(Reference)