how to process android ndk project dependency - android

I have two android projects with native support, that's to say, they're both android project and c++ project. One is android library(app-lib), another(std-pos-app) is android app who depends app-lib.
The Android.mk file in app-lib like bellow:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := app-lib
LOCAL_SRC_FILES := ...
include $(BUILD_SHARED_LIBRARY)
When it's builded, it will produce libapp-lib.so in libs/armeabi fiolder.
std-pos-app want to call the native code in app-lib.so. So the Android.mk file in std-pos-app like bellow:
LOCAL_PATH := $(call my-dir)
#------------------
include $(CLEAR_VARS)
LOCAL_MODULE := app-lib1
LOCAL_SRC_FILES := path-to-libapp-lib/libapp-lib.so
include $(PREBUILT_SHARED_LIBRARY)
#------------------
include $(CLEAR_VARS)
LOCAL_MODULE := std-pos-app
LOCAL_SRC_FILES := ...
include $(BUILD_SHARED_LIBRARY)
Use PREBUILT_SHARED_LIBRARY to prebuild libapp-lib.so, when std-pos-app is builded, libapp-lib.so and libstd-pos-app.so will appear in libs/armeapi. But when I want to run the std-pos-app, the error occured:
Error generating final archive: Found duplicate file for APK: lib/armeabi/libapp-lib.so
I konw the reason why it happen, because the android project dependency. But how to solve it? Thx.

I've found an alike thread that describes the same question. And I've solved the problem with the solution in the thread. How to use a library project with both c and java apis on Android

Related

cannot find -libsubstrate-dvm -libsubstrate

I got a problem in android.mk.It always show me that cannot find -lsubstrate-dvm and -lsubstrate. I don't know what it is? Could someone tell me how to solve this problem ? Here is the logcat:
Android NDK:non-system libraries in linker flags: -libsubstrate-dvm -libsubstrate
Android NDK: This is likely to result in incorrect builds. Try using LOCAL_STATIC_LIBRARIES
Android NDK: or LOCAL_SHARED_LIBRARIES instead to list the library dependencies of the
Android NDK: current module
cannot find -libsubstrate-dvm
cannot find -libsubstrate
Here is the android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := substrate
LOCAL_SRC_FILES := libsubstrate.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := substrate-dvm
LOCAL_SRC_FILES := libsubstrate-dvm.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := cydiasubstrate.cy
LOCAL_SRC_FILES := cydiasubstrate.cy.cpp
LOCAL_LDLIBS := -llog -L$(LOCAL_PATH) -lsubstrate-dvm -lsubstrate -lz
LOCAL_ARM_MODE := arm
APP_ALLOW_MISSING_DEPS=true
include $(BUILD_SHARED_LIBRARY)
please help me to fix this issue.
substrate-dvm is the name of the module being built, it relies on a prebuild library, not on sources, so you should look for libsubstrate-dvm.so
You could follow the following link for further help:
https://blog.gdssecurity.com/labs/2014/12/16/hooking-non-public-methods-with-the-ndk-using-mobile-substra.html
to include the Substrate libraries. The easiest way to
do this is to navigate to the ‘/sdk/extras/saurikit/cydia_substrate/’
directory and copy ‘substrate.h’ and navigate to the
‘/sdk/extras/saurikit/cydia_substrate/lib//’ directory and copy
‘libsubstrate-dvm.so’ file into the jni folder of the project.

jar file built in Android has only META-INF

I'm build a custom framework for Android device. Here is the makefile:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src) src/com/my_company/my_api/IMyService.aidl
LOCAL_AIDL_INCLUDES := src/com/my_company/my_api/IMyService.aidl
LOCAL_MODULE := com.my_company.mymanager
include $(BUILD_JAVA_LIBRARY)
"com.my_company.mymanager.jar" is getting generated. But it has no classes.dex, and it only has "META_INF" directory.
Note: This works well with Android 7.1.1. The issue started to happen after building this with latest Android 7.1.1 changes. Please suggest the reason for this strange behaviour.

$(LOCAL_PATH) not returning the path to current directory correctly

I am using Android NDK to compile a shared library. I am using the latest build of Android Studio (Android Studio 15- #AI-141.2422023 ). In my cpp code, I am using a thirdparty shared library. When writing the Android.mk file, I have first created a PREBUILT_SHARED_LIBRARY with the following code.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := essentia
LOCAL_SRC_FILES := $(LOCAL_PATH)/../../../essentia-shared/lib/libessentia.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../../essentia-shared/include/essentia
include $(PREBUILT_SHARED_LIBRARY)
The problem I am facing is that $(LOCAL_PATH) is behaving a bit weirdly. The path it is returning is
jni/jni/../../../essentia-shared/lib/libessentia.so
I have the following questions:
I am not sure, why there are two jni's appended at the front of the path. Also when I tried to print the value of LOCAL_PATH by using $(warning $(LOCAL_PATH)), it prints jni.
Shouldn't $(LOCAL_PATH) return the absolute path? This is even more confusing because at times I got the absolute path using $(LOCAL_PATH).
PS: I am using the terminal internal to Android Studio to run ndk-build
Edit 1: I run the ndk-build from src/main
$(call my-dir) from src/main for src/main/jni/Android.mk results in "jni". On the other hand, LOCAL_SRC_FILES are always treated relative to the LOCAL_PATH, which is "jni". That's how jni/jni appears for your .so.
On the other hand, all …_INCLUDES are treated relative to working directory, which in your case is src/main from where you launched ndk-build. Due to the delicate nature of current directory, it is a good practice to use absolute paths for all include paths.
So, this is the suggested rewrite of this part of your Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := app-lib
LOCAL_SRC_FILES := a.cpp b.cpp
LOCAL_SHARED_LIBRARIES := essentia
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH += /../../../essentia-shared
include $(CLEAR_VARS)
LOCAL_MODULE := essentia
LOCAL_SRC_FILES := lib/libessentia.so
LOCAL_EXPORT_C_INCLUDES := $(abspath $(LOCAL_PATH)/include/essentia)
include $(PREBUILT_SHARED_LIBRARY)

Android NDK/JNI: Building a shared library that depends on other shared libraries

I am writing an android app that wants to make JNI calls into a shared library built in using the NDK. The trick is this shared library calls functions provided by OTHER shared libraries. The other shared libraries are C libraries that have been compiled elsewhere.
Here's what I've tried:
My Environment:
I'm working in Eclipse. I've added native support and have a jni library. In that library I have my code and a \lib directory where I have copied my other .so files.
Attempt #1 Android.mk: Just telling it where the libs are
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
This builds just fine, but when I try to run I get errors indicating that dlopen(libnative_lib) failed because it couldn't load libsupport_lib1.
Coming here I found this:
Can shared library call another shared library?
which said that I needed to call load library on all necessary libraries. Great!
Attempt #2 Opening each library first
static {
System.loadLibrary("support_lib1");
System.loadLibrary("support_lib2");
System.loadLibrary("native_lib");
}
Again, this builds just fine, however when I run I get a new error:
couldn't load libsupport_lib1. findLibrary returned null.
Now we're getting somewhere. It must not be loading the libraries over to the target.
Attempt #3 Copying .so files into project/libs/armeabi
Didn't work. When Eclipse builds it deleted the files I dropped in there.
Attempt #4 Creating a new module for each library
So then I found this:
Android NDK: Link using a pre-compiled static library
It's about static libraries, but maybe I am having a similar problem. The gist is that I need to declare a module for each library. So my new Android.mk looks like this:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(BUILD_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(BUILD_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
This builds! Even better, armeabi has the sos now! Even BETTER I get the following messages when I try to run it (telling me that support_lib1 and 2 were opened by LoadLibrary:
Trying to load lib /data/app-lib/com.example.tst/libsupport_lib1.so
added shared lib /data/app-lib/com.example.tst/libsupport_lib1.so
no JNI_OnLoad found in /data/app-lib/com.example.tst/libsupport_lib1.so, skipping init
but then...
dlopen failed: Could not locate symbol func_that_exists_in_libsupport_lib.so referenced by libnative_lib.so
Edit: Attempt 5: Use PREBUILT_SHARED_LIBRARY
So I found this:
How can i Link prebuilt shared Library to Android NDK project?
which seems to be exactly what I'm asking. Their answer seems to be 'don't use 'build_shared_library' but instead 'use PREBUILT_SHARED_LIBRARY
Okay, let's try.
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
Build... fails! The build complains about missing symbols now.
Edit: Attempt 6: Flatten everything
So I went back to the prebuilts documentation in the NDK. It says:
Each prebuilt library must be declared as a single independent module to the build system. Here is a trivial example where we assume that the file "libfoo.so" is located in the same directory than the Android.mk below:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
Notice that, to declare such a module, you really only need the following:
Give the module a name (here 'foo-prebuilt'). This does not need to correspond to the name of the prebuilt library itself.
Assign to LOCAL_SRC_FILES the path to the prebuilt library you are providing. As usual, the path is relative to your LOCAL_PATH.
Include PREBUILT_SHARED_LIBRARY, instead of BUILD_SHARED_LIBRARY, if you are providing a shared, library. For static ones, use PREBUILT_STATIC_LIBRARY.
A prebuilt module does not build anything. However, a copy of your prebuilt shared library will be copied into $PROJECT/obj/local, and another will be copied and stripped into $PROJECT/libs/.
So let's try flattening everything out to match the trivial example. I copied my libraries out of their cozy /lib folder and put them in the jni root. I then did this:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
and... same error. Moreover I'm most definitely NOT seeing library files getting copied to $PROJECT/obj/local.
sooooo.... now what?
Your problem is with the naming convention. NDK and Android insist on the shared library names to always begin with lib. Otherwise, the libraries will not be linked properly, and not copied to the libs/armeabi folder properly, and not installed on the device (copied to /data/data/package/lib directory properly.
If you rename support_lib1.so to libsupport_1.so and support_lib2.so to libsupport_2.so, and put these two files in jni/lib directory, then your Attempt #5 will work with minor change:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := lib/libsupport_1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := lib/libsupport_2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
BTW, I don't think you need this -L$(SYSROOT)/../usr/lib.
PS Don't forget to update the Java side, too:
static {
System.loadLibrary("support_lib1");
System.loadLibrary("support_lib2");
System.loadLibrary("native_lib");
}
Not sure if this is exactly where you are at, but here's what I know about these sorts of things.
Make each prebuilt libary its own separate Makefile. Multiple targets in Android.mk tends to get wonky. Sad.
Include each make file using $(call import-add-path) and $(call import-module)
Export as much as you can from the prebuilt's make files, using the LOCAL_EXPORT_ family of variables.
Prebuilt Shared Library Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_module_name
MY_LIBRARY_NAME := shared_library_name
### export include path
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
### path to library
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/lib$(MY_LIBRARY_NAME).so
### export dependency on the library
LOCAL_EXPORT_LDLIBS := -L$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/
LOCAL_EXPORT_LDLIBS += -l$(MY_LIBRARY_NAME)
include $(PREBUILT_SHARED_LIBRARY)
This is assuming that the prebuilt libaries live in a dir structure like this
+ SharedProjectFolderName
+--- Android.mk
+--- include/
+-+- libs/$(TARGET_ARCH_ABI)/
|- libshared_library_name.so
If you are not building for multiple ABI, I guess you can leave that bit out
The Project's Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := my_jni_module
## source files here, etc...
### define dependency on the other library
LOCAL_SHARED_LIBRARIES := my_module_name
include $(BUILD_SHARED_LIBRARY)
$(call import-add-path,$(LOCAL_PATH)/path/to/myLibraries/)
$(call import-module,SharedProjectFolderName)
$(call import-module,AnotherSharedProject)
I recommend you put all shared libraries in one folder. When you say $(call import-module,SharedProjectFolderName) it looks for a folder containing an Android.mk along the search path you told it (import-add-path)
By the way, you probably shouldn't specify LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib. It should be finding the proper libs from NDK by itself. Adding more linker paths will probably confuse it. The proper way is to export the linker paths as flags from the sub-modules.
ALSO, you can use ndk-build V=1 to get a ton of info on why it can't find paths, etc
The -L option gives the linker a directory path in which to look for libraries. The -l option gives the linker a library file name to link in. Library file names must begin with "lib". Your libraries should be named libsupport_lib1.so and libsupport_lib2.so. If you do that, then this is probably what you should do (replacing attempt #1):
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog -lsupport_lib1 -lsupport_lib2
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib
The linker will prefix the library name you specify using -l with "lib" and suffix it with ".so". (Why do you have -L$(SYSROOT)/../usr/lib?)
I believe that attempts #1 and #2 failed because you did not link your libraries into your executable - they are not mentioned in a -l option. By the way, you can verify this yourself. Unzip the .apk file and look in the lib directory and subdirectories. Are your .so files in there?
Looking at the error:
but then... dlopen failed: Could not locate symbol func_that_exists_in_libsupport_lib.so referenced by libnative_lib.so
Can you supply the entire message? dlopen() loads and links libraries into the running process.

Linking dependent .so files with ndk-build for Android

I have created a .so file that exposes a native C call to Java via JNI. This works well and I can deploy the app onto my Android system if I just use system libraries in my C code. However, if I want to make calls to functions in other .so files, I cannot get my project to link correctly.
For example, say I have the "libotherso.so" file which contains APIs defined in C that I can call from the "MyJNILibrary.c" code I'm using to generate "libMyJNILibrary.so".
I tried to change my Android.mk file as follows:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyJNILibrary
LOCAL_SRC_FILES := MyJNILibrary.c
LOCAL_LDLIBS += -lotherso
include $(BUILD_SHARED_LIBRARY)
But when I call ndk-build on this, I get errors finding -lotherso. Where do I put the "libotherso.so" file so that ndk-build can pick it up?
Thanks for any help you can provide.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := otherso
LOCAL_SRC_FILES := ../lib/libotherso.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := MyJNILibrary
LOCAL_SRC_FILES := MyJNILibrary.c
LOCAL_SHARED_LIBRARIES := otherso
include $(BUILD_SHARED_LIBRARY)
Note that LOCAL_SRC_FILES is relative to your LOCAL_PATH.
Don't forget to load your dependency before your own JNI library:
static {
System.loadLibrary("otherso");
System.loadLibrary("MyJNILibrary");
}

Categories

Resources