I found similar questions on SO but none of them were with the same workflow.
I have a .so library (libcurl) in my project. The project builds but I need to get a hold of curl.h in my c code inside JNI.
Here's my Android.mk file:
LOCAL_PATH:= $(call my-dir)
LIBS_PATH := libs/$(TARGET_ARCH_ABI)
include $(CLEAR_VARS)
LOCAL_MODULE := libcurl
LOCAL_SRC_FILES := $(LIBS_PATH)/libcurl.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := testLib
LOCAL_SRC_FILES := lib.c
LOCAL_SHARED_LIBRARIES += libcurl
include $(BUILD_SHARED_LIBRARY)
Here's my c class:
#include "curl/curl.h"
#include "lib.h"
JNIEXPORT jint JNICALL Java_com_example_test_1libcurlandroidlib_Lib_getTestNumber
(JNIEnv *env , jclass clazz)
{
return 99;
}
The issue is with the "curl/curl.h" include command. I have also tried as but it does not find it either:
jni/lib.c:2:23: fatal error: curl/curl.h: No such file or directory
#include "curl/curl.h"
I have my libcurl.so file inside a lib folder inside the JNI folder, which at build time generates the same (I think) file into the libs folder at the root of the app:
Does anyone have any idea why I am not able to get a referece to curl.h, or what I have to do to get a hold of this library?
Thank you!
jni/lib.c:2:23: fatal error: curl/curl.h: No such file or directory
include "curl/curl.h"
To make use of this library, you need not only the compiled .so file, but also a set of function prototypes (and perhaps data type definitions) customarily provided by a header file.
With a well-defined library installation, these would be provided in a path adjacent to the binary - ie, you would have some "curlibrary/lib/libcurl.so" and next to it a "curlibrary/include/curl/curl.h"
To make that work, you would add the path of curl's include directory to your compiler command line, presumably by adding it to your Android.mk
LOCAL_C_INCLUDES := curlibrary/include
Or wherever you are keeping it.
To make use of the include path, your references to the library in code need to be enclosed in angle brackets, not double quotes, ie
#include <curl/curl.h> //this searches the include path
instead of
#include "curl/curl.h" //while this specifies a location relative to this source file
In a more fly-by-night context you may not really have a well-defined installation, but simply a .so file (hopefully compatible with your Android ABI) that you want to use, and a header file that you have either extracted or even re-created. In that case, you might more haphazardly toss "curl.h" somewhere in your project source, and include it via a specific quoted path as you were trying to do. Provided that path is correct, it will work - but it breaks the clean hierarchy of design, and could cause confusion if the api of curl ever changes in the future.
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 out NDK for the first time, and I'm stuck with building this project. I'm attempting to use the libraries used in Android's screencap recording program to read data from my screen. I understand that I need to use LibGUI, which I've pulled from my phone. Whenever I compile, however, I get this as an error message:
C:/Users/Kevin/Desktop/ScreenCapture//jni/main.cpp:2:34: fatal error: gui/ISurfaceComposer.h: No such file or directory
Which is odd, considering that I have libgui.so included.
What my main file looks like:
#include <stdio.h>
#include <gui/ISurfaceComposer.h>
int main() {
printf("Started!");
return 0;
}
What my Android.mk looks like:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgui-prebuilt
LOCAL_SRC_FILES := libgui.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := screencapture
LOCAL_SRC_FILES := main.cpp
LOCAL_SHARED_LIBRARIES := libgui-prebuilt
include $(BUILD_EXECUTABLE)
And I have both the main file and libgui.so in the same folder.
main.cpp:2:34: fatal error: gui/ISurfaceComposer.h: No such file or directory
Your error message indicates that the compiler is unable to find a header file, but your attempted solution is to provide a shared object (.so) library from the phone.
Libraries might help at link time, but before you can link you must successfully compile, and to do that you are going to have to obtain the missing header (perhaps from AOSP sources, as source code it will not be found on the phone) or else recreate it by deducing its contents from clues you collect. Unfortunately, it often isn't possible to take just one internal header out of AOSP, as it will likely depend on many others.
Linking against private system internals also introduces a risk of your program breaking if the private interface between internal components changes between Android versions.
(Normally I would also mention that you are unlikely to be able to record a screen with the NDK in it's normal usage of making a shared library to link into an application process, however your Android.mk seems to indicate you are building an executable - that might work if you can succesfully build it and you run it as a user with sufficient permission such as adb's shell userid or using a root hack)
Add one line for module screencapture:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/
If you haven't folder gui, you need to copy&paste includes headers *.h into folder jni/gui. Always such a requirement about using like that for ndk...
Or second case - using other location of this source for ldlibs:
LOCAL_LDLIBS := -L/full_path_to_source_gui/gui/
Many related questions have been asked regarding NDK linker errors, but I couldnt clearly found a solution to my situation.
I am trying to extend a sample NDK applicaiton, by adding 4 more local files of my own.
I am including them in the Android.mk file, and including the .h files appropriately.
Here is my Android.mk file.
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libgl2jni
LOCAL_CFLAGS := -Werror
LOCAL_SRC_FILES := gl_code.cpp \
sglBandwidthBench.c \
sglBandwidth.c \
common.c \
timer.c
LOCAL_LDLIBS := -llog -lGLESv3 -lEGL
include $(BUILD_SHARED_LIBRARY)
and the .h files inclusion has been proper. but the compilation gives me undefined reference to function x.
I added the files sglBandwidthBench.c sglBandwidth.c common.c timer.c, none of them contain a main function, and the only link is through referecing one of those functions in gl_code.cpp.
how can I link these files together successfully? I couldnt think of any way of specifying it. Any help would be much appreciated.
As you may know, link errors on undefined references are due to one or more method's implemetation not being found by the build system inside the prebuit libraries you provided. So, bottom line, you are probably missing the shared library which contains the implementation for function x.
My advice would be to double-check if you actually have libGLESv3.so under any of your <ndk>\platforms\<android-api-level>\arch-arm\usr\lib directory. Alternatively, check <ndk>\docs\STABLE-APIS.html to see if all the libraries you're using are listed there. If one of them is not, you will either need to upgrade your NDK version or to manually add the missing library to your source code (for that, read section PREBUILT_SHARED_LIBRARY from <ndk>\docs\ANDROID-MK.html).
Hope that this helps!
EDIT: Hi Sai, from what I just learned from your comments, you are trying to call a method implemented in a .c file from inside a .cpp one. So you need to enclose the contents of your gl_code.cpp with the following piece of code:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
I am using C++ to code in Android (I am using cocos2d-x, specifically).
Now, say, I have a class, MyClass, with .h and .cpp files. I would like to create a .so out of these files. Then, I would like to include that .so in my project and access it via #include "MyClass.h". Is it possible? If so, how? Thanks!
To build your static library for ARM you can use the NDK standalone toolchain.
Once you've compiled your .so, you can include the library in your project using the Android NDK make file (Android.mk) which will look like the following:
LOCAL_PATH := $(call my-dir)
LOCAL_SRC_FILES := my_module.so
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
You'll want to make sure you include the headers (/include) in the right path.
Not sure if your intent is to ge back into Android-land with your code, but if you're looking to create a bridge between your .so/C/C++ code and Java, you'll need to describe the appropriate JNI methods in C, build out the necessary Java classes with the static System.loadLibrary('my_module') imports and native method declarations mapped to your JNI methods.
I construct a simple android application which uses ndk with JNI.
The application has onw .cpp(debugTest.cpp) file that is used to link java and c++ with jni and another .c(javaEssentials.c) file with it's header(javaEssentials.h).
When I include in the .cpp file the .c file(#include "javaEssentials.c") no error is reported when compiling.
When I include in the .cpp file the header the compiler reports error of undefined reference of the functions the .c file has.It is real strange problem and I can't understand why is this happening.
As usual I have an include declaration of the header file in the .c file.
My android.mk is:
# build file written to describe the C and C++ source files to the Android NDK
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := debugTest
LOCAL_SRC_FILES := debugTest.cpp
include $(BUILD_SHARED_LIBRARY)
Any ideas why this is happening ?
You should only include headers (or alternatively use prototypes) to allow your C files to compile.
After compilation you would still have an error complaining about "undefined reference to `methodName'".
This is because C++ compilers encode the namespace of methods inside a cpp file. It doesn't do this for methods (or importantly, for method calls) inside of c files. This means that compiled c files cannot naturally access methods in compiled c++ code, even if the source code would suggest just that.
You can however tell the compiler that the method is going to be called by the "C" language therefore it will not encode the method namespace. You can instruct the compiler to do this by modifying the method in your cpp to look like this:
extern "C" int methodName()
{
return 1;
}
methodName() will now be accessible from your compiled C file.
You should to #include the .h files, not .c or .cpp.
Add to your Android.mk file:
LOCAL_C_INCLUDES := $(LOCAL_PATH)include_dir1 \
$(LOCAL_PATH)include_dir2 \
...
For every directory where there are .h files