Android NDK - How to build static libraries just once? - android

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

Related

Android NDK, headers from a prebuilt static library

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.

Linking issue when prebuilt static and shared libraries with the Android NDK

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.

Android NDK linking problems

I compiled Sox et al with NDK. So, I have all Android-friendly shared libs.
I made a simple test file which calls a sox function.
NDK build tells me:
undefined reference to `sox_open_read'
sox_open_read is defined in sox.h. I know it's finding sox.h because it gives me a warning about that file:
In file included from (...)/sox/sox.h:19
So maybe it wants to find sox_open_read in the actual libsox.so. Well, I've tried about a 100 different ways to tell it where the sox shared lib is e.g.
LOCAL_SHARED_LIBRARY := sox
LOCAL_LDLIBS := -L$(LOCAL_PATH_FULL)/jni/libs/libsox.so
However, It will work if I specify Sox as a static library:
#LOCAL_SHARED_LIBRARY := sox
LOCAL_STATIC_LIBRARIES := sox
LOCAL_LDLIBS := -L$(LOCAL_PATH_FULL)/jni/libs/libsox.so
It's my understanding that I don't want to staticly link to the sox lib - I want to dynamically link to it.
You should define libsox.so as a prebuilt library. Create a makefile as the following and put your prebuilt libsox.so in the same directory with this makefile. After that, you can use libsox same as you've rebuilt it. Don't forget to include this makefile into your build.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libsox
LOCAL_SRC_FILES := libsox.so
include $(PREBUILT_SHARED_LIBRARY)

Linking FFTW into an Android NDK application

I am currently writing a genre classification application as my final year project in Computer Engineering. I initially wrote the feature extraction code (implementing FFTW) in C and now I need to implement it on Android via the NDK.
This is my first NDK project so I'm still getting the hang of things but I have compiled the FFTW3 library for Android according to this guide. I didn't do the very last step because I didn't think it was right for what I need.
My question is how do I, after the compile step, use the library in the main NDK application that calls on it? Do I everything normally in Application.mk just with LOCAL_STATIC_LIBRARIES set to the libfftw3.a that I just compiled? And then I don't need to have any -lfftw3 linker flags like I normally would right?
You can use prebuit FFTW library (no matter how did you build it).
Or you can build FFTW in Android.mk makefile with the whole project.
Android.mk content will be:
# Prebuilt FFTW library
include $(CLEAR_VARS)
LOCAL_MODULE := fftw
include $(PREBUILT_STATIC_LIBRARY)
# or
# Build FFTW library
include $(CLEAR_VARS)
LOCAL_MODULE := fftw
# TODO put your static libs build flags
include path_to_fftw_sources/$(LOCAL_MODULE).mk
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := YourProject
# TODO put your shared lib build flags
include path_to_your_project/$(LOCAL_MODULE).mk
LOCAL_STATIC_LIBRARIES += fftw
include $(BUILD_SHARED_LIBRARY)
I have written path_to_fftw_sources/$(LOCAL_MODULE).mk for building fftw static library and path_to_your_project/$(LOCAL_MODULE).mk for building your shared library. It is often better to put LOCAL_SRC_FILES and LOCAL_C_INCLUDES to the separate .mk file.
You can read more about Android.mk file in docs/ANDROID-MK.html document in your NDK distribution.

How to compile a static library using the Android NDK?

I'm trying to compile a static library to use on Android but I can't figure out how to compile it. The library uses standard libraries (stdio.h etc...) and libxml2.
I am trying to compile using arm-eabi-gcc but I get the following error:
/cygdrive/c/android-ndk-r4/build/platforms/android-8/arch-x86/usr/include/asm/posix_types.h:15:28: error: posix_types_64.h: No such file or directory
How do I get this to work?
As I understand it, the correct method is to use ndk-build and not invoking the compiler directly.
In Android.mk you need to specify a module for each static library you want to compile, and then specify that your shared library should use it.
Example of a modified Android.mk file of the hello-jni sample project:
LOCAL_PATH := $(call my-dir)
# Define vars for library that will be build statically.
include $(CLEAR_VARS)
LOCAL_MODULE := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := <list_of_src_files>
# Optional compiler flags.
LOCAL_LDLIBS = -lz -lm
LOCAL_CFLAGS = -Wall -pedantic -std=c99 -g
include $(BUILD_STATIC_LIBRARY)
# First lib, which will be built statically.
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_STATIC_LIBRARIES := <module_name>
LOCAL_C_INCLUDES := <header_files_path>
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
If you want control over which modules to compile when you run ndk-build you can create create a Application.mk file (in the same directory as Android.mk) and list all the modules as in the following example:
APP_MODULES := <module_name_1> <module_name_2> ... <module_name_n>
In response to
Can you generate a static library (.a file) without a shared library
that uses it?
(which really should have been its own question), the answer is yes.
By default, the NDK will only build executables and shared libraries (with their dependencies of course). You can, however, force the NDK to build a standalone static library by explicitly referencing it in your Application.mk.
Assuming your static library module is LOCAL_MODULE := libXYZ, add the following line to Application.mk (creating the file in the same folder as your Android.mk if it doesn't exist):
APP_MODULES := XYZ
Note the the APP_MODULES value does not include the lib prefix included in your static library module name.
Alternatively, if you don't want to create an Application.mk, you can specify the value on the command line: ndk-build APP_MODULES=XYZ
A cool trick: if you have an Android.mk file, you can change the build type from:
include $(BUILD_SHARED_LIBRARY)
to
include $(BUILD_STATIC_LIBRARY)
and .a libraries will be output to the obj/ folder into their respective architectures when you ndk-build the library.

Categories

Resources