Reputation: 508
I've seen questions similar to this one, but the scenarios are not exactly the same, nor can I get an answer that works on my problem.
I have the source code for a C++ library. We need to use this library as part of an android application but it also needs to be available for third party to use as a C++ library.
I have a makefile that generates the .a file out of the library's source code, using ndk's compiler. That's the pure C++ part.
On the Java part, I have a simple demo project with a simple activity containing a button. When the button is pressed a call to native code is made.
Everything works fine as long as I don't try to call a function from the library from the JNI function.
Here are the sources for the library:
SimpleMath.h
int Add(int aNumber1, int aNumberB);
SimpleMath.cpp
#include "SimpleMath.h"
int Add(int aNumberA, int aNumberB)
{
return aNumberA + aNumberB;
}
The makefile
APP = simple_app
LIBRARY = simple_library.a
OBJECTS = SimpleMath.o
CFLAGS = -Wall -pedantic
NDK_PATH = /home/jug/perforce/jug_navui_personal_main/Env/Linux/Android/ndk/r7c
CXX = $(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-g++
AR = $(NDK_PATH)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar
SYSTEM_LIBS = -lstdc++ -lm
INCLUDE_PATH += ${NDK_PATH}/platforms/android-9/arch-arm/usr/include
all: $(LIBRARY)
$(LIBRARY):
$(CXX) -c SimpleMath.c
$(AR) rcs simple_library.a SimpleMath.o
clean:
rm *.o *.a
On the java side, these are the files:
hello-jni.c
#include <string.h>
#include <jni.h>
#include "../../../native/simple_library/SimpleMath.h"
jstring Java_com_amstapps_samples_draft08jni_MainActivity_helloJni(JNIEnv* env, jobject obj)
{
// Uncommenting the line below results in undefined-symbol compile error
//int d = Add(1, 2);
return (*env)->NewStringUTF(env, "Hello from JNI!");
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_simple_library
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := ../../../native/simple_library/simple_library.a
include $(PREBUILT_STATIC_LIBRARY)
#include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := eng
LOCAL_ARM_MODE := arm
#LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_C_INCLUDES := ../../../android/native/simple_library
LOCAL_STATIC_LIBRARIES := my_simple_library
#LOCAL_WHOLE_STATIC_LIBRARIES := my_simple_library
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_MODULES := my_simple_library hello-jni
As I said, the problem comes when I to actually make use of the functionality in the library from the jni native code in java application.
Now, I'm not longer sure whether my problem is in the static-library's makefile or on the Android.mk. I first thought it must have to do with the generation of the library itself, but at this point, after seeing there are so many options I didn't know about in Android.mk, I have to admit I have no clue.
What else..?
Oh, yes, I also noticed my pure C++ library is using cpp extension whereas the jni code in java project is using c extension. I tried to have the latter using cpp as well, but compiler complains. Could this be part of the problem?
The error code that I get when trying to compile the Android.mk file is "undefined symbol", so, is the list of functions in simple_library.a (there's actually 1 function) not visible to hello-jni.c because of it being C++ and not plain C?
Another thing you might notice is I'm trying to build the static library on its own makefile as opposed to generating it with Android.mk; there's a reason for that, but at this point I would also be happy if I had to have it in generated by Android.mk if that's what it takes.
I don't see any way to add an attachment in here so that to share a zip with the project. Let me know if there's something I'm missing.. Otherwise the code is in a depot in bitbucket, so I can easily share it with anyone having an account there too.
Thanks for you answers.
Upvotes: 2
Views: 9592
Reputation: 14467
You write a lot of correct things, but you're missing just one.
The function's name gets mangled in C++. And in the .so file you do not get "Add" symbol, but something like "Add@8i". To avoid mangling just use the
extern "C" int Add(int x, int y)
declaration in the .cpp file and in the .h.
Usually one also adds the
/// Some .h file
#ifdef __cplusplus
extern "C" {
#endif
/// Your usual C-like declarations go here
#ifdef __cplusplus
} // extern "C"
#endif
And the
extern "C"
for each of the exported functions in the .cpp file.
Upvotes: 7