I have a program I am porting that links together multiple libraries when creating the executable. I have built all those libraries using the stand alone toolchain and using the standalone toolchain I am able to create an executable that works on an android device. So, it seems like the libraries I have built are functional. Now I am trying to incorporate those libraries with an app. So, in my android.mk I have something like this:
LOCAL_PATH := $(call my-dir)
ROOT_PATH := $(LOCAL_PATH)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
LOCAL_PATH = $(ROOT_PATH)
LOCAL_MODULE := test-libs
LOCAL_STATIC_LIBRARIES := staticA
LOCAL_SHARED_LIBRARIES := sharedA sharedB sharedC sharedD
LOCAL_SRC_FILES := test-libs.c
include $(BUILD_SHARED_LIBRARY)
For each of the libraries, I have a Android.mk like this
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := sharedA
LOCAL_SRC_FILES := libsharedA.so
include $(PREBUILT_SHARED_LIBRARY)
The static library and one of the shared libraries have no dependencies on anything and if I only include them all is cool. One shared prebuilt library is dependent on the static prebuilt library only and the others are dependent on the prebuilt static library and other prebuilt shared libraries.
The problem is if I load any that are dependent on the static library via System.loadLibrary() I get the useful message:
Unable to dlopen(libsharedA.so) Cannot load library: link_image
Digging through this and following the suggestions here about how to use strace:
http://mpigulski.blogspot.com/2010/09/debugging-dlopen-unsatisfiedlinkerror.html
I found that when the shared libraries are loaded, they cannot locate a function that is in my static library.
So, how do I correctly use a prebuilt shared library whose use is dependent on a prebuilt static library and not have this issue?
Shared libraries should not depend on static libraries.
Static libraries are for linking (at compile-time) into an executable, not for adding at runtime.
If your shared library A uses a static library B, then either build a shared version of B or include B when you link A together.
Related
I've been trying to perform some native library builds for my Android App. More specifically performing ndk-build, with the help of some prebuilt shared libraries. One of the modules (let's call it pyjni) depends on those prebuilt shared libraries. Therefore my Android.mk consists of two modules for the prebuilt and to-be-built libraries respectively, as recommended for android ndk development.
This is my Android.mk file for the App:
LOCAL_PATH := $(call my-dir)
TARGET_ARCH_ABI := armeabi-v7a
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(LOCAL_DIR)/libs/$(TARGET_ARCH_ABI)/libprebuilt.so
LOCAL_MODULE := prebuilt
include $(PREBUILT_SHARED_LIBRARY)
# Build libpyjni.so
include $(CLEAR_VARS)
LOCAL_MODULE := pyjni
LOCAL_SRC_FILES := pyjni.c
LOCAL_C_INCLUDES:= $(LOCAL_DIR)/include/$(TARGET_ARCH_ABI)/
LOCAL_SHARED_LIBRARIES := prebuilt
LOCAL_LDLIBS += -llog
include $(BUILD_SHARED_LIBRARY)
Build turns out fine. In fact, when examining the .APK both the pre-built and built shared libraries are packaged inside # lib/armeabi-v7a. So far so good.
However, when trying to load the built shared library as System.loadLibrary("pyjni") during the App execution, it crashes notifying the following error:
java.lang.UnsatisfiedLinkError: dlopen failed: library ".../app/build/intermediates/ndkBuild/debug/obj/local/armeabi-v7a/libprebuilt.so" not found.
I can succesfully load the prebuilt library using System.loadLibrary("prebuilt"). So at this point I suspect it is an issue on how the prebuilt shared library is being packaged or rather how LOCAL_SHARED_LIBRARIES is working. In the app's build.gradle file the sourceSets.main.jniLibs.srcDirs points to the directory where libprebuilt.so is placed. To avoid packaging issues with multiple instances of the prebuilt library file, the gradle file specifies
packagingOptions{
pickFirst 'lib/armeabi-v7a/libprebuilt.so'
}
At this point I'm confused with how the link created by LOCAL_SHARED_LIBRARIES is working on execution.
In my Android application, I have quite a few open-source C++ projects that are built as static libraries. Essentially, Android.mk builds all the libraries as static and links them all to create my final core.so library.
Our nightly build checks out all the files from the source control in a clean directory and builds everything that is needed.
I am looking at how I can optimize our nightly build. As the third-party code does not change (may be once every six months), I would like to build them just once and check in the generated libs. I am guessing these libs would have a ".a" extension. The nighly build will simply check out these libs and link them to create my final core.so.
Basically, I am hoping I can break my existing Android.mk into two different ones - one for building static libraries and one for building the final shared library that the Android code can use.
I am wondering if this is possible. Regards.
You're looking for prebuilt library support.
Assuming your static library declaration looks something like this:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
you can make it use a prebuilt instead:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := libs/foo.a
include $(PREBUILT_STATIC_LIBRARY)
and include in your core lib just the same:
include $(CLEAR_VARS)
LOCAL_MODULE := myCore
LOCAL_SRC_FILES := core/core.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
So you could have a seperate Android.mk, or just use a conditional variable.
ifeq ($(USE_PREBUILT_LIBS),)
# declare with BUILD_STATIC_LIBRARY
else
# declare with PREBUILT_STATIC_LIBRARY
endif
I am having a problem when using a pre-built static library when the compiler is looking for headers.
I have a .cpp that needs to use a header file from a static library. My Android.mk is as followed :
include $(CLEAR_VARS)
LOCAL_MODULE := LibA
LOCAL_SRC_FILES := libs/libA.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := hello
LOCAL_SRC_FILES := hello.cpp
LOCAL_STATIC_LIBRARIES := LibA
include $(BUILD_SHARED_LIBRARY)
hello.cpp requires a header that can be found in the static library but the compiler says it can't find it. Do I have to have headers seperated from that static library ?
Headers are not included in static libraries. Even if they were, the compiler has no way to read a .a file, only the linker will do that.
I'm not a prof, but I've learned that you allways need a corresponding .h-file
included! In those .h-files the compiler gets the info "how to use" the libraries
as they defines the functions that are inside the libs.
Good luck
Martin
try "LOCAL_LDLIBS" in 2nd step.
We are trying to use a third party .a static library in our Android app. The .a lib is built for x86 and we used it with a PC linux box without problem.
Then we try to use it on Android with this Android.mk:
LOCAL_PATH:= $(call my-dir)
# first lib, which will be built statically
#
include $(CLEAR_VARS)
LOCAL_MODULE := libtwolib-first
LOCAL_SRC_FILES := rwl.a
LOCAL_MODULE_SUFFIX := .a
include $(PREBUILT_STATIC_LIBRARY)
# second lib, which will depend on and include the first one
#
include $(CLEAR_VARS)
LOCAL_MODULE := libtwolib-second
LOCAL_SRC_FILES := second.c
LOCAL_STATIC_LIBRARIES := libtwolib-first
include $(BUILD_SHARED_LIBRARY)
We get this error:
could not read symbols: File in wrong format
Is it because the .a file is compiled with x86 and we are building for arm?
The .a file is a legacy and most likely can't be recompiled from source. If this is the issue, is there any other solution?
Thanks.
You need to obtain the source for the third-party lib and cross-compile it to native Android's NDK such that its binary compatible.
Simply dropping an x86 static lib into Android's NDK build will just not work.
I have a program I am porting that links together multiple libraries when creating the executable. I have built all those libraries using the stand alone toolchain and using the standalone toolchain I am able to create an executable that works on an android device. So, it seems like the libraries I have built are functional. Now I am trying to incorporate those libraries with an app. So, in my android.mk I have something like this:
LOCAL_PATH := $(call my-dir)
ROOT_PATH := $(LOCAL_PATH)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
LOCAL_PATH = $(ROOT_PATH)
LOCAL_MODULE := test-libs
LOCAL_STATIC_LIBRARIES := staticA
LOCAL_SHARED_LIBRARIES := sharedA sharedB sharedC sharedD
LOCAL_SRC_FILES := test-libs.c
include $(BUILD_SHARED_LIBRARY)
For each of the libraries, I have a Android.mk like this
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := sharedA
LOCAL_SRC_FILES := sharedA.so
include $(PREBUILT_SHARED_LIBRARY)
When I then build my project (in eclipse), I get this:
C:/ndk/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/../lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a(unwind-arm.o): In function `__gnu_unwind_pr_common':
/cygdrive/c/ndk/android-ndk-r7b/build/core/build-binary.mk:314: recipe for target `obj/local/armeabi/libtest-libs.so' failed
/tmp/ndk-digit/src/build/../gcc/gcc-4.4.3/libgcc/../gcc/config/arm/unwind-arm.c:1237: undefined reference to `__cxa_call_unexpected'
Any thoughts on what is going wrong?
Also, the static library and one of the shared libraries have no dependencies on anything and if I only include them all is cool. One of my shared libraries only had a dependency on the static library. If I only include those, but when I include the others, which have dependencies on other shared libraries, this problem occurs.
Update 1: Ok it appears to be because the APP_STL setting in my Application.mk was being ignored. All I have in my Application.mk is:
APP_STL := gnustl_shared
If I copy over the libgnustl_shared.so and treat it like another prebuilt shared lib, my problem is gone. Any idea why the APP_STL is not working properly. Note, I could have screwed something up. I just upgraded to using 7b. Using gnustl_shared used to work for me with other apps. Rolling back to 7 doesn't fix it. I think I have messed something up in Eclipse. I use Eclipse (windows) with sequoyah.
It looks like the linker is giving you an error. What you should do is the following:
Add a LOCAL_LDLIBS under your LOCAL_MODULE := test-libs. Here you need to include all the libraries you link against when you compile your pre-compiled libraries. So for example:
LOCAL_LDLIBS := -lgnustl_shared -lgcc -llog -landroid -lstdc++
Basically you need to identify what library contains the function __cxa_call_unexpected. A quick google shows that it's probably in libstdc++. Make sure that you also link with this library when creating your pre-compiled libraries.
I'm thinking it might have something to do with exceptions support.
Are you using exceptions in your code and if so are you compiling with a runtime library that supports exceptions? (and compiling with exceptions on)?.
There is more on this in the CPLUSPLUS-SUPPORT and STANDALONE-TOOLCHAIN files in the ndk docs.
I've observed a similar problem when one of my projects which contains only C source files (*.c) references another project that contains a c++ file(*.cpp). Application.mk files for both projects had APP_STL := gnustl_shared in them. The ndk version is ndk7e.
The solution was adding an empty C++ file (dummy.cpp) to the project that contained only .c files. Supposedly ndk understood that this project should be linked against the gnustl_shared and the build succeeded.