简体   繁体   中英

Android: How to use an existing C++ static library from your JNI code?

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM