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
Related
I'm trying to use Google's Protocol buffer on a C++ project. I can build it just fine for say... an iOS framework target. However, I can't seem to get the compiler to find any of the google/protobuf files. I already have the static library file (not sure if this one works on my architecture? i used: https://gist.github.com/BennettSmith/9487468ae3375d0db0cc)
in the output of the proto file, let's say blah.pb.h, i have a reference to protobuf:
#include <google/protobuf/stubs/common.h>
the compiler can't find that ^ reference.
I've tried to ndk-build with something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := libprotobuf
LOCAL_SRC_FILES := src/lib/libprotobuf.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_SRC_FILES:=$(shell find src/lib -name '*.cpp')
LOCAL_MODULE := mymodule
LOCAL_C_INCLUDES += ./src/lib
LOCAL_STATIC_LIBRARIES := libprotobuf
include $(BUILD_SHARED_LIBRARY)
but it doesn't seem to help at all. what's going on? how do i include lib protobuf when i have the .a file? do i have to compile it from source?
turns out i have to multiple things:
i have to duplicate the entire protobuf include folder (the one with all the headers) to my project. and then include them in my LOCAL_EXPORT_C_INCLUDES
also, the command that i was using to do ndk-build is also not fully correct. it was missing a ton of stl stuff, like missing "string" or vector or map. so i used this instead:
ndk-build V=1 NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_STL=stlport_static
NDK - Android Java with native (JNI) C++ code build issue
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.
I'm testing JNI on Android in Eclipse.
I have a simple Android project with one activity. In Eclipse's project explorer, I added:
jni/ folder
Android.mk in the jni/ folder
prng.c in the jni/ folder
The source file is named prng.c because it wraps Crypto++'s random number generator. Crypto++ is already cross-compiled for ARMv7, so I have libcryptopp.so standing by.
When I select Project → Build Project, the library is not built. I've confirmed its not built after cleaning the project, too.
Android-PRNG$ find . -iname *.so
Android-PRNG$
Question: Why is Eclipse not building the shared object? What else need to be done?
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := prng
LOCAL_SRC_FILES := prng.c
include $(BUILD_SHARED_LIBRARY)
prng.c
Its basically empty at the moment because I can't get javah to run on the Java class file that calls the native methods. I hope to fix that problem next.
#include <string.h>
#include <jni.h>
#include <cryptopp/osrandom.h>
static RandomNumberGenerator& GetPRNG()
{
static AutoSeededRandomPool prng;
return prng;
}
It's actually very easy with ADT for the last couple of years; it was much worse before. The plugin described in the linked post are coming preinstalled; you still need to
1 install NDK
2 set the path to it in Preferences/Android/NDK menu
3 right click on your Android project, Android Tools/Add Native Support
... and now you are all set.
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.