Undefined reference to opus functions while the appropriate header is included - android

In an effort to reduce bandwidth usage of an application, I tried to make an implementation of opus.
First, I cross-compiled the sources into a shared library. I copied the resulting .so file into an opus folder inside my jni folder. I also copied all opus header files into an include subfolder in the opus folder. Finally, I created an Android.mk file to allow the usage of this .so file in my implementation.
So my file structure is as follows:
/jni
/opus
/include
All opus header files
Android.mk
libopus.so
Android.mk
OpusEncoder.h
OpusDecoder.h
OpusEncoder.c
OpusDecoder.c
The Android.mk file in the opus subfolder has the following content:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := opus
LOCAL_SRC_FILES := jni/opus/libopus.so
LOCAL_C_INCLUDES := jni/opus/include
include $(PREBUILD_SHARED_LIBRARY)
As is recommended to expose the .so file for usage.
Now, in my implementation of the Encoder/Decoder, I import opus.h, and use the appropriate functions in order to expose them through JNI to the Java layer.
The Android.mk in my jni folder (which should build my JNI layer) is as follows:
LOCAL_PATH := $(call my-dir)
MY_DIR := $(LOCAL_PATH)
include $(CLEAR_VARS)
include jni/opus/Android.mk
APP_ABI := armeabi armeabi-v7a
LOCAL_PATH := $(MY_DIR)
LIB_PATH := $(LOCAL_PATH)/../lib
LOCAL_LDLIBS += -llog -landroid
#LOCAL_LDLIBS += $(LIB_PATH) -lopus
LOCAL_SHARED_LIBRARIES := opus
LOCAL_MODULE := OpusCodec
LOCAL_SRC_FILES := OpusEncoder.c \
OpusDecoder.c
include $(BUILD_SHARED_LIBRARY)
However, when I run the ndk-build command, I get the following 6 error messages:
error: undefined reference to 'opus_encoder_create'
error: undefined reference to 'opus_encode'
error: undefined reference to 'opus_encoder_destroy'
error: undefined reference to 'opus_decoder_create'
error: undefined reference to 'opus_decode'
error: undefined reference to 'opus_decoder_destroy'
Which are all methods exposed by opus.h in libopus.so. Any ideas?

Okay, so this all turned out to be a typographical error on my behalf.
For the keen observer, to make the prebuilt opus library, I used the call include $(PREBUILD_SHARED_LIBRARY) where it should have been include $(PREBUILT_SHARED_LIBRARY) (the difference being the T instead of D at the end of PREBUILT).
As a result, it didn't create the library that I tried to link to with LOCAL_SHARED_LIBRARIES := opus in my main Android.mk file.
So this is how I have my Android.mk file for the prebuilt library:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libopus
LOCAL_SRC_FILES := libopus.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
And this is my Android.mk file for the code I wrote:
MY_PROJECT_PATH := $(call my-dir)
LOCAL_PATH = $(MY_PROJECT_PATH)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
APP_ABI := armeabi armeabi-v7a
LOCAL_PATH = $(MY_PROJECT_PATH)
LOCAL_MODULE := OpusCodec
LOCAL_SHARED_LIBRARIES := libopus
LOCAL_LDLIBS += -llog -landroid
LOCAL_SRC_FILES := OpusEncoder.c OpusDecoder.c
include $(BUILD_SHARED_LIBRARY)
Other than the cosmetic change to the prebuilt library module, and restructuring my main Android.mk file, I didn't have to change a thing (you don't need to specify the LIB_PATH as I originally tried).

Related

Using JsonCpp on X-Cross platform library

I'm making a library in C++ with OpenCV and JsonCpp towards building a library for Android and iOS.
On testing my library for Android, I'm making the JNI files but when I try to load the library I'm getting
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol
"_ZN4Json6WriterD2Ev" referenced by "libXYZ.so"...
and that's because I think I'm not building my Json library very well.
The library that I use is this one: https://github.com/open-source-parsers/jsoncpp
My Android.mk is:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_CAMERA_MODULES:=off
OPENCV_INSTALL_MODULES:=on
include $(LOCAL_PATH)/jsoncpp/Android.mk
include /Users/localmac/Desktop/AndroidDevelopment/OpenCV-2.4.9-android-sdk/sdk/native/jni/OpenCV.mk
OPENCV_LIB_TYPE:=SHARED
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_C_INCLUDES += /Users/localmac/mylibrary/OpenCVtry/
LOCAL_C_INCLUDES += /Users/localmac/Desktop/RD/OpenCVtry/Libraries/jsoncpp-master/include
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_MODULE := libXYZ
LOCAL_SRC_FILES := androidClass.cpp main.cpp utils.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
I have no idea of how to do this.
Thank you in advance.
EDIT it's not the NDK Compiling's fault.
Even if I compile the JsonCpp, I get the
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZN4Json6WriterD2Ev" referenced by "libXYZ.so"...
EDIT My jsoncpp/Android.mk :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cpp LOCAL_MODULE := libJsoncpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)/jsoncpp/include
LOCAL_SRC_FILES := src/lib_json/json_reader.cpp \
src/lib_json/json_value.cpp \
src/lib_json/json_writer.cpp
include $(BUILD_SHARED_LIBRARY)
You're not linking against Jsoncpp in your makefile. You should add the following line:
LOCAL_SHARED_LIBRARIES := libJsoncpp
before the last include $(BUILD_SHARED_LIBRARY).
You must specify module names for this variable (and its sister LOCAL_STATIC_LIBRARIES), that is, what you specified for the LOCAL_MODULE variable.
Also, that spares you from specifiying the includes in the LOCAL_C_INCLUDE variable (as the makefile will include them directly when specifying the library in the variable I mentioned at the top of my post).
EDIT: For the sake of completeness, I'll add that you can specify multiple libraries like that:
LOCAL_SHARED_LIBRARIES = libJsoncpp \
libOpenCV \
...
and the same goes for LOCAL_STATIC_LIBRARIES.

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.

How to link .so file in android

I have two projects. The output of first one is libtest.so file. Using this shared object file in the 2nd project, i want to generate final android executable, AndroidExe.
I generated libtest.so and its Android.mk is given below
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -g
LOCAL_ARM_MODE := arm
LOCAL_MODULE :=test
LOCAL_SRC_FILES := test.c
export LD_LIBRARY_PATH=/data/local/tmp
include $(BUILD_SHARED_LIBRARY)
Here the problem i am facing is that, i don't know how to link this .so file in my final executable project. In this final project, i am using one of the function (sum(a,b)) defined in the .so lib.While do build, showing error undefined reference to 'sum'.Its Android.mk file is given below:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS := -g
LOCAL_ARM_MODE := arm
LOCAL_MODULE :=AndroidExe
LOCAL_SHARED_LIBRARIES := libtest.so
LOCAL_SRC_FILES := AndroidExe.c
include $(BUILD_EXECUTABLE)
just check ndk documentation and try some of the samples.

Include shared dynamic library in jni ndk build

I am trying to compile a ndk module for my android app with a Shared Library provided with these drivers:
http://www.extendo-printer.de/fileadmin/user_upload/extendo/Drivers/X-56-Hengstler-Extendo-LinuxDrivers-S684018-R2-V1_01-FINAL-2009JUL15.zip
I can compile fine with the defaults (using Hello JNI example). But when I add my code the my C file which references a .so library I need to work with I get compile errors stating it can not find the methods defined in the library. When I try to include it in Android.mk in LOCAL_SRC_FILES i get warnings when it builds (unsupported file extension) but it builds, but than my native method call fails (java.lang linkage error). Is there a proper way to include a .so and than reference it's functions in your native C code?
current Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := x56-jni
LOCAL_LDLIBS := libExoApi.so
LOCAL_SRC_FILES := x56-jni.c
include $(BUILD_SHARED_LIBRARY)
I tried with LOCAL_SHARED_LIBRARIES as well with same build error. I've also tried adding to LOCAL_SRC_FILES as stated above (LOCAL_SRC_FILES := x56-jni.c libExoApi.so) with a "," and as well as \ syntax.
Update
I've updated Android.mk to:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libExoApi
LOCAL_SRC_FILES := libExoApi.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := x56-jni
LOCAL_LDLIBS := libExoApi.so
LOCAL_SRC_FILES := x56-jni.c
LOCAL_SHARED_LIBRARIES := libExoApi
include $(BUILD_SHARED_LIBRARY)
This fails at:
[exec] Unable to recognise the format of the input file `/var/folders/_6/6jjydzjs457fnpsc9_5cgl980000gn/T//michael/usbserial-generated/libs/armeabi/libExoApi.so'

Error in linking C++ static library with android ndk(Error: file format not recognized)

I am trying to include static cpp library in android. This library is already compiled(on mac os) and i have its include files.
Here is my Android.mk file
LOCAL_PATH := $(call my-dir)
include $(call all-subdir-makefiles)
include $(CLEAR_VARS)
LOCAL_MODULE:= utils
LOCAL_SRC_FILES:= libUtils.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/utils
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := sample
LOCAL_SRC_FILES := sample_cpp.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_STATIC_LIBRARIES := utils
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
and here is Application.mk file
APP_STL := stlport_static
APP_CPPFLAGS = -fexceptions
but whenever it try to compile it using NDK i get the error
(Path of file)/libUtils.a: file not recognized: File format not recognized
collect2: ld returned 1 exit status
From the comments and so on it sounds like you trying to use a non arm version of the library. You should build the library with the ndk. The documentation has even documentation on how to do that.
For example building sigc++ could be like (from a project of mine, where sigc++ resides in the sigc++ subdirectory)
# SIGC++ Library built as static library
LOCAL_MODULE := sigc
LOCAL_PATH = $(CURRENT_DIR)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := sigc++/signal.cc sigc++/signal_base.cc sigc++/trackable.cc
LOCAL_SRC_FILES += sigc++/functors/slot_base.cc sigc++/adaptors/lambda/lambda.cc
LOCAL_SRC_FILES += sigc++/connection.cc sigc++/functors/slot.cc
LOCAL_C_INCLUDES := sigc++
include $(BUILD_STATIC_LIBRARY)
But you should really read how the compiling linking works. I am afraid building for android with ndk is more low level than using Xcode or Msvc.

Categories

Resources