Case:
I am building an app which uses libcrypto and libssl. I am trying to use prebuilt libcrypto.so and libssl.so and compile my application.
But I keep getting undefined reference errors.
My App/Android.mk
LOCAL_PATH := $(call my-dir)
my_LOCAL_PATH := $(LOCAL_PATH)
include $(call all-subdir-makefiles)
LOCAL_PATH := $(my_LOCAL_PATH)
common_SRC_FILES := \
src/foo.c
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(common_SRC_FILES)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../openssl/include
LOCAL_SHARED_LIBRARIES += mylibssl mylibcrypto
include $(BUILD_STATIC_LIBRARY)
My App/mylibssl/Android.mk
Building mylibssl [from a prebuilt libssl.so]
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylibssl
LOCAL_SRC_FILES := libssl.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../openssl/include
include $(BUILD_PREBUILT)
My App/mylibcrypto/Android.mk
Building mylibcrypto [from a prebuilt libcrypto.so]
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylibcrypto
LOCAL_SRC_FILES := libcrypto.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := .so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../openssl/include
include $(BUILD_PREBUILT)
I keep getting
error: undefined reference to 'BIO_new_mem_buf'
error: undefined reference to 'PEM_read_bio_X509_AUX'
error: undefined reference to 'BIO_free'
...
I have spent several hours trying to figure out and am totally stuck. Please help!
I am building an app which uses libcrypto and libssl... But I keep getting undefined reference errors.
error: undefined reference to 'BIO_new_mem_buf'
error: undefined reference to 'PEM_read_bio_X509_AUX'
error: undefined reference to 'BIO_free'
These are linker errors, and mean you are not linking against the OpenSSL library. Its probably a path problem, assuming you have an Android version of the OpenSSL library available.
If you need an an Android version of the OpenSSL library, then you can build it yourself or find it on Github. To build it yourself, see FIPS Library and Android (just ignore the FIPS stuff). The steps required are (and note the leading dot "." when running the script):
cd openssl-1.0.1f/
wget http://wiki.openssl.org/images/7/70/Setenv-android.sh
chmod a+x *.sh
. ./setenv-android.sh
./config shared no-ssl2 no-hw no-engine --openssldir=/usr/local/ssl/android-18/ <other options>
make depend
make all
For option two, you can search Github with https://www.google.com/q=openssl+android+site:github.com.
Building mylibcrypto [from a prebuilt libcrypto.so]
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mylibcrypto
LOCAL_SRC_FILES := libcrypto.so
This is not going to produce expected results, and will likely result in a crash if you get it to work. The problem is Android uses 0.9.8, and you are probably building against 1.0.1.
What happens is Zygote loads OpenSSL 0.9.8 at startup (its the parent of all Android Java programs). When your app is launched, Zygote is forked so OpenSSL is already mapped into the address space. That means the version of OpenSSL you are carrying around is not loaded. Later, you crash because 0.9.8 and 1.0.1 are not binary compatible (i.e., they are ABI incompatible).
You are correct in building a wrapper shared object (mylibcrypto.so). However, mylibcrypto.so will need to statically link against OpenSSL to avoid the above problem. That is, mylibcrypto.so will need to link against libcrypto.a and libssl.a.
Related
I have to use some c++ code in my android application. This code was used successfully in an iOS project.
The code depends on 2 external libraries: zero-mq and protocol buffers.
I compiled the zmq library as an static library like explained here. I added the static (.a) library and the .jar to my project.
I created the protobuf library with the following configurations:
./configure --host=arm-eabi --with-sysroot=x/android-ndk-r10d/platforms/android-21/arch-arm CC="x/android-ndk-r10d/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot x/android-ndk-r10d/platforms/android-21/arch-arm" --enable-cross-compile --with-protoc=protoc LIBS=-lc
make
I changed the real directories to x to make them shorter.
In my Android Project(IDE: Android Studio) I prepared everything which is necessary. I created a JNI Folder and deactivated the auto-creation of the makefiles.
Application.mk:
APP_MODULE := proxy
APP_STL := gnustl_shared
APP_CPPFLAGS := -frtti -fexceptions --std=c++11
APP_ABI := armeabi-v7a ##all later
NDK_TOOLCHAIN_VERSION := 4.9
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := zmq_static
LOCAL_SRC_FILES := zmq/libzmq.a
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static1
LOCAL_SRC_FILES := protobuf/libprotobuf.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static2
LOCAL_SRC_FILES := protobuf/libprotobuf-lite.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
LOCAL_MODULE := protobuf_static3
LOCAL_SRC_FILES := protobuf/libprotoc.a
LOCAL_EXPORT_C_INCLUDES := google/protobuf protobuf/
include $(PREBUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := proxy
LOCAL_CFLAGS := -I/include -pthread -lpthread -D__GXX_EXPERIMENTAL_CXX0X__ - frtti
LOCAL_CPPFLAGS := -I/include -pthread -lpthread -D__GXX_EXPERIMENTAL_CXX0X__ -frtti
LOCAL_CPP_FEATURES += exceptions
LOCAL_LDLIBS := -llog
LOCAL_SRC_FILES := \
usersession.cpp\
## LOCAL_ALLOW_UNDEFINED_SYMBOLS := true will compile the code but shutdown on runtime
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\main\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\arm\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\debug\jni
LOCAL_C_INCLUDES += C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\armDebug\jni
LOCAL_C_INCLUDES += \zmq
LOCAL_C_INCLUDES += \protobuf
LOCAL_STATIC_LIBRARIES := zmq_static protobuf_static1 protobuf_static2 protobuf_static3
LOCAL_WHOLE_STATIC_LIBRARIES := zmq_static protobuf_static1 protobuf_static2 protobuf_static3
include $(BUILD_SHARED_LIBRARY)
The zmq library is in the subdirectory zmq and the protobuf library is in the subfolder protobuf.
Now the linking of the Objects still does not work. The Error Output when I execute ndk-build:
C:\Users\M\Dropbox\Workspace\ndk_swig_test\app\src\main\jni>ndk-build
[armeabi-v7a] SharedLibrary : libproxy.so
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/ext/new_allocator.h:127: error: undefined reference to 'ControlledInstance::ControlledInstan (std::shared_ptr<protogen::Application>, std:
:shared_ptr<protogen::Role>, std::shared_ptr<protogen::User>)'
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/bits/shared_ptr_base.h:511: error: undefined reference to 'protogen::User::User()'
C:/Users/M/Documents/ndk/sources/cxx-stl/gnu- libstdc++/4.9/include/bits/shared_ptr_base.h:914: error: undefined reference to 'google::protobuf::internal::empty tring_'
C:/Users/M/Dropbox/Workspace/ndk_swig_test/app/src/main//jni/controlledinstance.h :23: error: undefined reference to 'protogen::MetaGraph::~MetaGraph()'
collect2.exe: error: ld returned 1 exit status
make.exe: *** [C:/Users/M/Dropbox/Workspace/ndk_swig_test/app/src/main//obj/local/armeabi- v7a/libproxy.so] Error 1
I tried many versions of the Android.mk and recreated the library more than once with different options which I found all over the internet.
I also looked at dozens of threads on stackoverflow which did not help me.(I'm not allowed to link them because of low reputation)
Additionally i read most of the doc files from the ndk e.g. PREBUILTS.
I added some other directories to my JNI directory e.g. the directory with the original files and directories (compiler, io, stubs...). I think this directory should offer the export of the necessary methods if the prebuild library was successfully linked to my shared library - which is not the case.
I tried far more than I can explain in few minutes and I think it would be overkill if i added everything I've tried because nothing helped.
Because this is my first question I dont have the reputation to include more than 2 links. Sorry for that.
There may probably be other issues as well, but you at least have got a typo - it should be include $(PREBUILT_STATIC_LIBRARY), as in, BUILT, not BUILD.
I was given a shared library built on Linux x86, let's call it libA.so, and I want to use the function calls provided by this library SDK.
I am having issues building and have a few questions:
1) I will be able to build for x86, but will I be able to build for arm? I believe the answer is no, meaning I cannot run on a Nexus 5 for example.
2) The ndk-build complains of the #include that should be resolved by my LOCAL_SHARED_LIBRARIES. I am not sure why that is. My Android.mk is as follow:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := B
LOCAL_SRC_FILES := B.cpp
LOCAL_SHARED_LIBRARIES := A
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Can someone please help me resolve my Android.mk? I don't understand why it is complaining about my include statement in B.cpp. Please let me know if I can run B in an arm environment, although the SDK I am relying on was built on x86.
If your shared library libA.so has been compiled for linux-x86, it will certainly not run on android x86 targets (mainly because it needs to be linked to Bionic C library instead of glibc), and absolutely not on android arm devices.
Then, to solve your second issue, if you can get properly compiled android shared libraries for your android targets, you would include your library this way:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := A
LOCAL_SRC_FILES := ../libA/prebuilts/$(TARGET_ARCH_ABI)/libA.so # path to libA .so file, depending on the target ABI.
LOCAL_EXPORT_C_INCLUDES := ../libA/includes # path to libA headers.
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := B
LOCAL_SRC_FILES := B.cpp
LOCAL_SHARED_LIBRARIES := A
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
I'm beginer to Android NDK. I want to build a RSA example base on openssl libary.
First, I built libssl.so and libcrypto.so librairies with ndk-build in the guardianproject.
Next, I create a new sample project to integrate libary (libss.so & lybcryto.so). I follow the same in this post
My App directory
TrialApp
|
|-->Activity.java (includes System.LoadLibrary calls)
|
|-->jni
|-->TestJNI2.cpp
|
|-->Android.mk
|
|-->includes
| |
| |-->openssl (dir containing *.h files)
|
|-->precompiled
|-->libssl.so
|-->libcrypto.so
My android.mk:
LOCAL_PATH := $(call my-dir)
# Prebuilt libssl
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := precompiled/libssl.so
include $(PREBUILT_SHARED_LIBRARY)
# Prebuilt libcrypto
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := precompiled/libcrypto.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
c_includes := $(LOCAL_PATH)
cf_includes := includes/openssl
cf_includes := $(addprefix -Ijni/,$(cf_includes))
export_c_includes := $(c_includes)
LOCAL_MODULE := security
LOCAL_SRC_FILES := TestJNI2.cpp
LOCAL_CFLAGS += $(cf_includes)
LOCAL_EXPORT_C_INCLUDES := $(export_c_includes)
LOCAL_LDLIBS := -llog
LOCAL_LDLIBS += $(LOCAL_PATH)/precompiled/libssl.so
LOCAL_LDLIBS += $(LOCAL_PATH)/precompiled/libcrypto.so
include $(BUILD_SHARED_LIBRARY)
TestJNI2.cpp
/* OpenSSL headers */
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
/* Initializing OpenSSL */
void init_openssl(void){
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
}
Then when i build with ndk-build always have problems like this
/data/workspace/TestJNI2/jni/TestJNI2.cpp:3:25: error: openssl/bio.h: No such file or directory
/data/workspace/TestJNI2/jni/TestJNI2.cpp:4:25: error: openssl/ssl.h: No such file or directory
/data/workspace/TestJNI2/jni/TestJNI2.cpp:5:25: error: openssl/err.h: No such file or directory
/data/workspace/TestJNI2/jni/TestJNI2.cpp: In function 'void init_openssl()':
/data/workspace/TestJNI2/jni/TestJNI2.cpp:10: error: 'SSL_load_error_strings' was not declared in this scope
/data/workspace/TestJNI2/jni/TestJNI2.cpp:11: error: 'ERR_load_BIO_strings' was not declared in this scope
/data/workspace/TestJNI2/jni/TestJNI2.cpp:12: error: 'OpenSSL_add_all_algorithms' was not declared in this scope
make: *** [/data/workspace/TestJNI2/obj/local/armeabi/objs/security/TestJNI2.o] Error 1
Can anyone help me? Or how to build an example RSA algorthim base on openssl lib?
You should build static libraries for libssl and libcrypto in your script. If you can't, rename these libraries (you can do this after build, while copying to your precompiled directory). The reason is that the system comes with its own (probably different) version of these shared libraries, and the loader will use /system/lib/libssl.so and /system/lib/libcrypto.so instead of your private copies.
Regarding the Android.mk file, I slightly cleaned it up for you (note that I did not change the names of prebuilt LOCAL_MODULEs, but changed the name of LOCAL_MODULE you finally build, because security is, well, too generic and could also happen to match a system library on some device):
LOCAL_PATH := $(call my-dir)
# Prebuilt libssl
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := precompiled/libPrivateSsl.so
include $(PREBUILT_SHARED_LIBRARY)
# Prebuilt libcrypto
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := precompiled/libPrivateCrypto.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := PrivateSecurity
LOCAL_C_INCLUDES := includes
LOCAL_SRC_FILES := TestJNI2.cpp
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := ssl crypto
include $(BUILD_SHARED_LIBRARY)
Don't forget that your Java should load the dependencies first:
{
System.loadLibrary("PrivateSsl");
System.loadLibrary("PrivateCrypto");
System.loadLibrary("PrivateSecurity");
}
I'm beginer to Android NDK. I want to build a RSA example base on openssl libary.
You can, but you have to be careful. Here's the reason Alex told you to use static libraries for libssl and libcrypto in your script.
The master Android process is zygote. Its like init in Linux. Zygote loads OpenSSL when its start, and it loads version 0.9.8. If you link against OpenSSL 1.0.1, then you will get mysterious runtime crashes. The crashes are due to the Android loader using the 0.9.8 version of the library (already mapped from Zygote), and not your version of OpenSSL.
You can use a shared object, but your shared object must be a wrapper around the static version of libssl and libcrypto.
If you are not using Android's build system, then you can find additional instructions for building purely from the command line at OpenSSL's wiki. The wiki page includes setting the envrionment and cross compiling. See FIPS Library and Android.
Another thing to watch out for: be sure to build with -mfloat-abi=softfp. The stock OpenSSL misses that when cross compiling. You need it to ensure floats are passed on the stack, and not through floating point registers. Otherwise, all your floats will mysteriously have 0.0f value (like the floats used to estimate entropy in RAND_add).
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.
I am trying to build an android application that uses static libraries from some existing c++ code. However I cannot seem to get things building, here are the steps I have taken so far..
I have ndk-r5b and have built the standalone toolchain as per ndk/docs/STANDALINE-TOOLCHAIN.html. I have then used the standalone toolchain compiler (arm-linux-androideabi-g++) instead of g++ for the CXX flag in the Makefile that compiles the static libraries I need. This compiles without errors and there are 3 static libraries produced.
Here is a code snippet of some of the flags used to build the prebuilt libraries:
CXX = arm-linux-androideabi-g++
SYSTEM_LIBS = -lstdc++ -lm
INCLUDE_PATH += ${NDK_PATH}/platforms/android-8/arch-arm/usr/include/
Here is a sample line that is produced from the makefile when compiling:
arm-linux-androideabi-g++ -c -DTIME_SIM -I./include -I/home/greg/dev/Android/android-ndk-r5b/platforms/android-8/arch-arm/usr/include/ -fpic -ggdb3 -SimTime.C -o SimTime.o
Next I build the app using ndk-build using the following for Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := engine
LOCAL_SRC_FILES := ../libs/libEngine.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := shmem
LOCAL_SRC_FILES := ../libs/libShMem.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := util
LOCAL_SRC_FILES := ../libs/libUtil.a
include $(PREBUILT_STATIC_LIBRARY)
# build server as a shared library
include $(CLEAR_VARS)
LOCAL_MODULE := libServer
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../include
LOCAL_SRC_FILES := \
Server.C \
Router.C \
RouterMsgs.C \
Federation.C \
cripName.C \
ver.C \
JNIWrapper.cpp
LOCAL_STATIC_LIBRARIES := engine shmem util
include $(BUILD_SHARED_LIBRARY)
The prebuilt libraries compile fine using the standalone toolchain compiler given in the android ndk. However there are many unresolved references to ostream when linking the shared library to the prebuilt libraries using ndk-build. For exampe:
/home/android/obj/local/armeabi/libShMem.a(SubscriptionItem.o): In function `SUBSCRIPTION_ITEM::Print(std::basic_ostream<char, std::char_traits<char> >&)':/home/src/comm/SubscriptionItem.C:97: undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
I assume I am missing some important flags or not doing something correct when I am compiling using the standalone compiler but any help or insight on this issue would be greatly appreciated as I cant seem to find this answer on google or in any of the android ndk docs. Thanks!
Well, you can actually fix that with creating a Application.mk file inside the same folder as the Android.mk file is, containing:
APP_STL := stlport_static
for using the static stlport that is located inside the Android NDK.
I had the same issue and resolved it by adding a module for the standard C++ library. The library linked by the ndk-build system is from the wrong location (platforms/android-9/arch-arm/usr/lib in my case).
include $(CLEAR_VARS)
LOCAL_MODULE := rightstdc
LOCAL_SRC_FILES := <path to the correct libstdc++.a>
include $(PREBUILT_STATIC_LIBRARY)
Add the module tag to the list of static libraries:
LOCAL_STATIC_LIBRARIES := engine shmem util rightstdc
The build/core/build-binary.mk prepends -L$(SYSROOT)/usr/lib if any libraries are specified in LOCAL_LDLIBS but in my case that is the wrong path.
I don't know if there is a missing step that should copy the correct libstdc++ to that location but the approach above will work.