I am trying to build an android application that calls into a C++ backend. This backend uses ZeroMQ for messaging. Per the android build page on the ZeroMQ guide, I have built a native toolchain of ndk version 6 and used that to (successfully) build ZeroMQ.
However, when I build my own .so with the JNI implementations, I can't seem to make everything load properly. Specifically, if I call System.LoadLibrary("zmq"), this completes successfully, but if I then call *System.LoadLibrary("my_lib")* I always get an UnsatisfiedLinkError complaining that:
Cannot load library reloc_library[1244]: 29 cannot locate zmq_msg_init'...
The libmy_lib.so has been generated several different ways, each with no success. After generating it, I always copies libmy_lib.so (as well as libzmq.so) to my android project's folder: libs/armeabi/.
# Compile all object files - this part was done for all options
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -fpic -c Client_Events.cpp \
Client Wrapper.cpp jni.cpp -I /opt/android-root/include/ -I /my/project/specific/stuff
# Option 1 - Don't link the lib in at all
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o
# Option 2 - Link ZeroMQ in statically
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o \
libzmq.a libstdc++.a -Wl,--whole-archive
# Option 3 - Explicitly link ZeroMQ in dynamically
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o \
-L /opt/android-root/lib/ -lzmq
With each of these options I tried both explicitly calling System.LoadLibrary("zmq") before loading my own library and not. Nothing varied the results. Using nm confirms that, at least in the case of option #2, the missing symbol *zmq_msg_init* is indeed present in libmy_lib.so.
Any ideas as to why it cannot find the ZeroMQ symbols that are linked in?
I just learnt how to compile a 2nd library and link it to my main library in android ndk. Let me see if I am of any use to you.
The following is how I create my 2nd library (In my case, I build bullet physics library and the irrlicht rendering engine as 2 separate libraries for my game).
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := HEADER FILES
LOCAL_MODULE := bullet
LOCAL_SRC_FILES := SRC FILES
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O3 -DANDROID_NDK -DDISABLE_IMPORTGL
LOCAL_LDLIBS := -ldl -llog
include $(BUILD_SHARED_LIBRARY)
Then copy your libxxxx.so (In my case, libbullet.so and libirrlicht.so) to your jni folder. And in your main library .mk file add the following.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for bullet)
LOCAL_MODULE := bullet
LOCAL_SRC_FILES := libbullet.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for irrlicht)
LOCAL_MODULE := irrlicht
LOCAL_SRC_FILES := libirrlicht.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for bullet + includes for irrlicht + includes for main code)
LOCAL_SRC_FILES := main code src files
LOCAL_MODULE := gamescript
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O3 -DANDROID_NDK -DDISABLE_IMPORTGL
LOCAL_LDLIBS := -lOpenSLES -landroid -ldl -llog
LOCAL_SHARED_LIBRARIES := bullet irrlicht
include $(BUILD_SHARED_LIBRARY)
And now, add all the libraries to your java code in right order.
System.loadLibrary("bullet");
System.loadLibrary("irrlicht");
System.loadLibrary("gamescript");
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.
Iam trying to compile my native code. Here is my android.mk file
//part1-static lib
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := irrlicht
IRRLICHT_LIB_NAME := lib$(LOCAL_MODULE).a
LOCAL_C_INCLUDES := include
LOCAL_SRC_FILES := \
CColorConverter.cpp \
CCSMLoader.cpp \
CCubeSceneNode.cpp \
CD3D8Driver.cpp \
include $(BUILD_STATIC_LIBRARY)
//part-2 shared lib
include $(CLEAR_VARS)
LOCAL_MODULE := irrlichttest
LOCAL_SRC_FILES := test-app.cpp test.cpp android-receiver.cpp
LOCAL_C_INCLUDES := include
LOCAL_CFLAGS := -O3 -DANDROID_NDK -DDISABLE_IMPORTGL -I$(LOCAL_PATH)/../include/ - I./include/
LOCAL_CPPFLAGS := -Wno-error=format-security
LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog -lGLESv2
LOCAL_STATIC_LIBRARIES := irrlicht
include $(BUILD_SHARED_LIBRARY)
and here is my application.mk
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-10
APP_MODULE := irrlicht irrlichttest
i want to compile "irrlicht" module first and then "irrlichttest' module. The problem iam facing is my irrlichttest module compile first and it start looking for reference and give me undefined reference error.Right now If i compile part1(static lib) only it successfully generate libirrlicht.a, But with part2 it start giving me error. What am i doing wrong.
You have one extra \ at the end of your first LOCAL_SRC_FILES definition, this makes the 'include $(BUILD_STATIC_LIBRARY)' part go into LOCAL_SRC_FILES, and the line is never parsed / executed. In other words, due to this your module definition for the 'iirlicht' module is completely ignored by ndk-build, hence the problem you're seeing.
Remove the \ after CD3D8Driver.cpp, and that should fix it.
NDK will compile the irrlichttest sources, then irrlich sources, then create libirrlich.a, and only after that it will link libirrlichttest.so. It is very insightful to run
ndk-build clean all V=1
and see in the build log which commands are actually executed to build the project.
I'm struggling to get a native Android application correctly link against a custom shared object built in the same AOSP tree.
I have a shared object built with
LOCAL_SRC_FILES += \
src/libscanengine.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/
LOCAL_C_INCLUDES += kernel/include/
#every module depending on us will
#automagically have this included
LOCAL_EXPORT_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libscanengine
LOCAL_PRELINK_MODULE := false
include $(BUILD_SHARED_LIBRARY)
It gets built and installed as the mm command invocation
build/core/dynamic_binary.mk:141: warning: overriding commands for target `.so'
build/core/dynamic_binary.mk:118: warning: ignoring old commands for target `.so'
build/core/shared_library.mk:54: warning: overriding commands for target `.so'
build/core/dynamic_binary.mk:141: warning: ignoring old commands for target `.so'
No private recovery resources for TARGET_DEVICE X
No recovery.fstab for TARGET_DEVICE X
make: Circular .so <- .so dependency dropped.
make: Circular .so <- out/target/product/X/symbols/system/lib/libscanengine dependency dropped.
make: Circular .so <- .so dependency dropped.
target Non-prelinked: libscanengine (out/target/product/X/symbols/system/lib/libscanengine)
target Strip: libscanengine (out/target/product/X/obj/lib/libscanengine)
Install: out/target/product/X/system/lib/libscanengine.so
Once I try to buil a native application linked against the newly created .so with the following Android.mk
LOCAL_SRC_FILES := \
src/mores.c
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include/
#not working: commented out
#LOCAL_LDLIBS += \
-lscanengine
#LOCAL_C_FLAGS += \
-L../../out/target/product/X/system/lib/
LOCAL_SHARED_LIBRARIES := \
libscanengine
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := mores
include $(BUILD_EXECUTABLE)
I get:
make: *** No rule to make target `out/target/product/X/obj/lib/libscanengine.so', needed by `out/target/product/X/obj/EXECUTABLES/mores_intermediates/LINKED/mores'. Stop.
I noticed two things: the shared library is installed under X/out/lib as libscanengine and not libscanenegine.so as it is required by the native application.
I have to manually copy the .so everytime, which is stupid since all of this should be handled in some way by the Android build system.
Furthermore, the LOCAL_EXPORT_C_INCLUDES directive does not work. Does it work only with PREBUILT_SHARED_OBJECTS?
Android version is 2.3, there is no Java involved, everything is built under AOSP.
Thank you
j
LOCAL_C_FLAGS += \
-L../../out/target/product/X/system/lib/
does not work because it should read
LOCAL_LDFLAGS += \
-Lout/target/product/X/system/lib
or
LOCAL_LDFLAGS += \
-L$(LOCAL_PATH)/out/target/product/X/system/lib
But this does not explain why LOCAL_SHARED_LIBRARIES is not working. What commands do you use to build?
Whilst not a good solution, if the libscanengine target can't be found implicitly via AOSP, then you can always include it manually, like so.
include $(AOSP_ROOT)/PATH/TO/libscanengine/Android.mk
Regarding why the shared object won't build correctly, a hacky solution is providing a static object directly after the shared one which references it, in the Android.mk. For instance, this I adapted from an existing jpeg port. What I wanted was a shared library I could work with in a separate compilation step, but it wouldn't be built unless it was required by something.
$(call my-dir)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := \
jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c \
jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c \
jcphuff.c jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c \
jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c \
jdinput.c jdmainct.c jdmarker.c jdmaster.c jdmerge.c jdphuff.c \
jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c jfdctfst.c \
jfdctint.c jidctflt.c jidctred.c jquant1.c \
jquant2.c jutils.c jmemmgr.c \
jmem-android.c
# the assembler is only for the ARM version, don't break the Linux sim
ifneq ($(TARGET_ARCH),arm)
ANDROID_JPEG_NO_ASSEMBLER := true
endif
# temp fix until we understand why this broke cnn.com
#ANDROID_JPEG_NO_ASSEMBLER := true
ifeq ($(strip $(ANDROID_JPEG_NO_ASSEMBLER)),true)
LOCAL_SRC_FILES += jidctint.c jidctfst.c
else
LOCAL_SRC_FILES += jidctint.c jidctfst.S
endif
LOCAL_CFLAGS += -I"$(LOCAL_PATH)/./include" -DAVOID_TABLES
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
#LOCAL_CFLAGS += -march=armv6j
LOCAL_MODULE:= jpeg
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := jpeg2
LOCAL_STATIC_LIBRARIES := jpeg
include $(BUILD_SHARED_LIBRARY)
Whilst neither of these are true solutions, as they don't address the underlying reason behind your problems, they may aid you, as they did me, in getting stuff working quickly and automatically.
I want to use ffmpeg library in my application so I wrote an Android.mk file as follow:
LOCAL_PATH := $(call my-dir)
TOP_LOCAL_PATH := $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/android-8/armv5te/include/
LOCAL_CPP_EXTENSION := .cpp
LOCAL_C_EXTENSION := .c
LOCAL_CFLAGS := -O3
LOCAL_MODULE := FilterEngine
LOCAL_SRC_FILES := \
decoding_encoding.c \
LOCAL_LDLIBS := -lm -llog -ljnigraphics -L$(LOCAL_PATH)/android-8/armv5te/lib/ -lavcodec -lavfilter -lavutil -lm -lz
LOCAL_STATIC_LIBRARIES := avcodec avfilter avutil
include $(BUILD_SHARED_LIBRARY)
This make file only builds the library for ARM v5 CPU, to create an ARM v7 build of the library I have to modify the Android.mk file (change from armv5te to armv7a). How can I specify 2 types of CPU in the make file so I can build the library for both CPUs at one.
Thanks in advance.
In your jni folder make "Application.mk" and add the desired target architectures, for example:
APP_ABI := armeabi armeabi-v7a x86
Next, change your Android.mk to use: $(TARGET_ARCH_ABI) where you have the architecture hardcoded.
I'm doing something similar with FFmpeg. Here is a link for further reference:
http://sourceforge.net/p/servestream/code/1217/tree/trunk/jni/
Let me know if you have any additional questions.
I have been trying to build the CSipSimple in my Win7 (X64) machine for couple of days.
I am using cygwin for building the code. But currently it is displaying me the below image.
Please give me some suggestions.
It would be useful if you showed us your "android.mk" file. Here is an example of an android.mk file which builds a library called "mylib" from 2 cpp files:
LOCAL_PATH := $(call my-dir)
LOCAL_ARM_MODE :=arm
include $(CLEAR_VARS)
LOCAL_MODULE := mylib
LOCAL_SRC_FILES := \
mysource1.cpp \
mysource2.cpp \
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -lz -lm -llog
include $(BUILD_SHARED_LIBRARY)