问题
I have asked this question in google android-ndk group but not get any answer.
I am trying to build a common module in a independent project by click the "Is Library" is eclipse. This project provides both c apis and java apis. While some of these apis are related. ( it means it's not a good idea to separate them into 2 projects) Let's name it common and libcommon.so.
When I am using this library in another project ( suppose testcommon), I add the common project as a library in eclipse at project explorer--> properties --> Android --> Library --> Add. But this only make me possible to use java apis in the library.
Also I add libcommon.so as a PREBUILT_SHARED_LIBRARY in android.mk in testcommon project so that I could access c apis. ( as below )
include $(CLEAR_VARS)
LOCAL_MODULE := common-prebuilt
LOCAL_SRC_FILES := ../../common/libs/$(TARGET_ARCH_ABI)/libcommon.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := testCommon
LOCAL_SRC_FILES := testCommon.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../common/jni/include/
LOCAL_SHARED_LIBRARIES := common-prebuilt
include $(BUILD_SHARED_LIBRARY)
In this way, ndk-build is success but when I am running it, I get below errors:
[2012-02-29 15:28:20 - testCommon] Error generating final archive:
Found duplicate file for APK: lib/armeabi/libcommon.so
Origin 1: E:\Code\EclipseWorkspace\testCommon\libs\armeabi\libcommon.so
Origin 2: E:\Code\EclipseWorkspace\Common\libs\armeabi\libcommon.so
I think that because both reference to library and prebuild shared library add libcommon.so to testcommon project. In fact, I have tested to only reference the library or add a prebuild shared library, they both copied libcommon.so to testcommon.
The question is, what should I do if I need a library with both c and java apis.( not only code )
Thanks
After I read Can shared library call another shared library?, I found a way to solve this but still not very sure.
Use below line in Android.mk instead of PREBUILT_SHARED_LIBRARY also make native part works and libraries will not be copied in this way. So that duplicate copy could be fixed.
LOCAL_LDFLAGS := -L$(LOCAL_PATH)/../../Common/libs/$(TARGET_ARCH_ABI)/ -lcommon
The reason why this could not work in my before test is that even is this way, both libraries should be load in java, but not only libtestCommon.
System.loadLibrary("common"); // I lost this in my before test
System.loadLibrary("testCommon");
I think it's clear for me now.
Both LOCAL_SHARED_LIBRARIES and -L plus -l should work fine in NDK.
The problem is that when I call
System.loadLibrary("testCommon")
it will try to find so files at /data/data/$(app path)/lib (System.java::loadLibrary --> Runtime.java::loadLibrary --> DexPathList.java::findLibrary ) but when libtestCommon try to find its dependency libCommon.so, it will only find it at /vendor/lib and /system/lib since
LD_LIBRARY_PATH=/vendor/lib:/system/lib.
If I call System.loadLibrary("common") first, dlopen will load it into cache (Linker.c::alloc_info). This make libtestCommon.so loads libCommon.so success I guess. So everything works.
I also noticed these words at the end of SYSTEM-ISSUES.html in ndk-r7:
- A bug prevents one application shared library from depending on another one. For example, if you build both libfoo.so and libbar.so for your application, and list libfoo.so as a dependency for libbar.so in bar/Android.mk (with LOCAL_SHARED_LIBRARIES := foo), then loading libbar.so will always fail, even if you have already loaded libfoo.so in your process.
There is a little different. If I have already loaded libfoo.so in my process, libbar.so will success.
So, answer at last is:
- Use LOCAL_LDFLAGS := -Lxx -lxx if you need any shared libraries in android library project.
- You must call System.loadLibrary for every shared libraries needed. That's also the way to use another shared library in one library.
- The path of libraries at /libs/ is placed at /data/data//lib/.
回答1:
As an option you can use
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
in one of Android.mk and exclude the duplicate lib.
回答2:
I have been wrestling with a similar problem. I want to build an Android library project with both Java and C. I want dependent projects' Java to be able to reference the library's Java and dependent projects' C code in JNI to be able to reference the C in the library's jni. I required two kludges. One is almost identical to your solution:
LOCAL_LDFLAGS := -L$(LOCAL_PATH)/../../Common/libs/$(TARGET_ARCH_ABI)/ -lcommon
I created a dependency on the library project's actual location in the file system. Your dependency assumes the Common library project is a sibling directory of your dependent TestCommon project.
I also created a build.xml Ant file that copies the C header files from the library project to a jni/include directory in the dependent jni folder.
With these two kludges, I am able to get everything working. I would really like to eliminate both kludges, but could not find a way.
来源:https://stackoverflow.com/questions/9510162/how-to-use-a-library-project-with-both-c-and-java-apis-on-android