2

I am building libexif for Android. I am using the following cross compile script:

PLATFORM_PREFIX=/home/tishu/Documents/osx-wks/GC/Thdl/jni/libexif-0.6.21/arch-arm/
NDK_PATH=/home/tishu/Documents/android-ndk-r8e/
NDK_PLATFORM=android-14

rmdir $PLATFORM_PREFIX
mkdir $PLATFORM_PREFIX

$NDK_PATH/build/tools/make-standalone-toolchain.sh  --system=linux-x86_64 --platform=$NDK_PLATFORM --install-dir=$PLATFORM_PREFIX

PATH=$PLATFORM_PREFIX/bin:$PATH

./configure --host=arm-linux-androideabi --prefix=$PLATFORM_PREFIX --enable-static
make clean
make install

The output gives 3 .so files in the lib folder

  • libexif.so (symlink)
  • libexif.so.12 (looks like a symlink but content is big binary)
  • libexif.so.12.3.3 (actual binary)

I have renamed the last file to libexif.so and deleted the two symlinks as per some advice found on this website. I then wanted to build this with my app and use the following Android.mk, where libexif_native is my c file that uses the libexif library

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libexif
LOCAL_SRC_FILES := libexif-0.6.21/arch-arm/lib/libexif.so
LOCAL_EXPORT_C_INCLUDES := libexif-0.6.21/arch-arm/include
LOCAL_EXPORT_LDLIBS := libexif-0.6.21/arch-arm/lib/libexif.so
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := libexif_native
LOCAL_SRC_FILES := libexif_native1.1.4.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexif-0.6.21/arch-arm/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_SHARED_LIBRARY := libexif
LOCAL_LDLIBS    := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/libexif-0.6.21/arch-arm/lib/libexif.so
include $(BUILD_SHARED_LIBRARY)

This compiles correctly, but when I run it on my phone in debug mode I get this error:

11-01 15:05:06.919: E/AndroidRuntime(5638): FATAL EXCEPTION: main
11-01 15:05:06.919: E/AndroidRuntime(5638): java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libexif.so.12" needed by "libexif_native.so"; caused by library "libexif.so.12" not found

I then tried this modified Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := libexif
LOCAL_SRC_FILES := libexif-0.6.21/arch-arm/lib/libexif.so
LOCAL_EXPORT_C_INCLUDES := libexif-0.6.21/arch-arm/include
LOCAL_EXPORT_LDLIBS := libexif-0.6.21/arch-arm/lib/libexif.so
LOCAL_EXPORT_LDLIBS := libexif-0.6.21/arch-arm/lib/libexif.so.12
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := libexif_native
LOCAL_SRC_FILES := libexif_native1.1.4.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libexif-0.6.21/arch-arm/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_SHARED_LIBRARY := libexif
LOCAL_LDLIBS    := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/libexif-0.6.21/arch-arm/lib/libexif.so.12 -lm $(LOCAL_PATH)/libexif-0.6.21/arch-arm/lib/libexif.so.12
include $(BUILD_SHARED_LIBRARY)

With no more luck.

Anyone knows why it is looking for the .12 file and how to pass it on? I have tried a few naive tweaks but can't find out how to make this work.

Many thanks

tishu
  • 998
  • 15
  • 29

1 Answers1

5

The library libexif.so is part of the standard Android distribution. If you don't rely on some special feature of the latest version, you may find that /system/lib/libexif.so will just be OK for you. Instead of building the library and working around all the troubles (see below), you can link your libexif-native.so with the system lib: simply pull the library from your device:

> adb pull /system/lib/libexif.so /somepath

and then insert

LOCAL_LDLIBS += /somepath/libexif.so

into your Android.mk. Note that you will see

Android NDK: WARNING:jni/Android.mk:...: non-system libraries in linker flags: /somepath/libexif.so

In this speific case, you can safely ignore this warning.

The troubles you avoid this way

It is a typical problem with Android port of Linux libraries, that the latter use version suffix for SONAME, while Android NDK does not support such suffix. There is a good reason for that: on Android, libraries are not installed system-wide, they are always part of the application package, and so version tagging is unnecessary. But this inconsistency does not make Android developers' lives easier.

The straightforward resolution was suggested in How to modify librtmp Makefile to remove version suffix?: Get rid of -Wl,--soname=... somewhere in your Makefile. Unfortunately, this trick does not work with NDK r9d, or r10c.

But you can specify extra LDFLAGS for ./configure. Here is the command:

./configure LDFLAGS=-Wl,soname=libexif.so <other parameters>
make
mv /arch-arm/lib/libexif.so.12.3.3 /arch-arm/lib/libexif.so

Note that you also need to explicitly load the dependency libraries from Java, in the correct order. I.e. a static constructor will look like:

static {
    System.load("/data/data/your.package.name/lib/libexif.so");
    System.loadLibrary("exif-native");
}

You must specify the full path to libexif.so because otherwise the library from /system/lib will be loaded.

Alternatively, you should rename the library

./configure LDFLAGS=-Wl,soname=libexif.12.3.3.so <other parameters>
make
mv /arch-arm/lib/libexif.so.12.3.3 /arch-arm/lib/libexif.12.3.3.so

Now your Java code may be cleaner:

    System.loadLibrary("exif.12.3.3");
    System.loadLibrary("exif-native");

And here is the relevant fragment of Android.mk:

LOCAL_MODULE := libexif
LOCAL_SRC_FILES := libexif-0.6.21/arch-arm/lib/libexif.12.3.3.so
LOCAL_EXPORT_C_INCLUDES := libexif-0.6.21/arch-arm/include
include $(PREBUILT_SHARED_LIBRARY)

Actually, one trick that I never dared to try could be to manually pack the file libexif.so.12 into the assets folder, unpack it to some known path after APK installs, and use

    System.load("/known/path/libexif.so.12");
    System.loadLibrary("exif-native");

It is a pity that the Android pack/install framework performs filtering of the files in libs/armeabi folder to only allow pattern lib<whatever>.so.

Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Thanks for the great answer, I have a couple more questions on this: - If I use the first quick method, which include folder should I use? I need it to code my own c file using the library - I could not get the second one to work ./configure LDFLAGS=-Wl,-soname=libexif.12.3.3.so --host=arm-linux-androideabi --prefix=$PLATFORM_PREFIX --disable-static --enable-shared make clean make install mv arch-arm/lib/libexif.so.12.3.3 arch-arm/lib/libexif.12.3.3.so then System.loadLibrary("exif.12.3.3"); System.loadLibrary("exif_native"); I still get the error about so.12 – tishu Nov 02 '14 at 10:12
  • Issue on point 2 is very likely incorrect configure parameters as i get the following readelf -d libexif.12.3.3.so | grep SONAME 0x0000000e (SONAME) Library soname: [libexif.so.12] – tishu Nov 02 '14 at 10:23
  • Presumably, you can use the headers you downloaded with libexif from SourceForge. To be on the safe side, you can get the same [from `android.googlesource.com`](https://android.googlesource.com/platform/external/libexif/) – Alex Cohn Nov 02 '14 at 11:08
  • instead of `LDFLAGS`, it may be worth while to use **`LDLIBS`**. – Alex Cohn Nov 02 '14 at 11:10
  • For the first method, code does not compile when using the built in .so file. There are a lot of undefined symbol errors that break the build when switching to that system .so file in LOCAL_LDLIBS. LOCAL_LDLIBS := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/libexif.so – tishu Nov 02 '14 at 11:28
  • Really? Can you post the build log on pastebin or something? The better format would be `LOCAL_LDLIBS := -llog -ljnigraphics -lz -lm -L$(LOCAL_PATH) -lexif` – Alex Cohn Nov 02 '14 at 13:10
  • On the second thought, you can simply download the source from [googlesource](https://android.googlesource.com/platform/external/libexif/+/master) to build the 6.21 version for Android on your PC. Here is the command: `ndk-build APP_BUILD_SCRIPT=libexif/Android.mk NDK_PROJECT_PATH=. LOCAL_C_INCLUDES=.` – Alex Cohn Nov 02 '14 at 16:07
  • Thanks for all the help, in the end I got it working by referencing the .a file: LOCAL_LDLIBS := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/libexif-0.6.21/arch-arm/lib/libexif.a – tishu Nov 09 '14 at 11:59
  • This way, you use static linking to `libexif`. Please note that the library is available under LGPL, thus static linking may impose undesirable consequences. – Alex Cohn Nov 09 '14 at 16:13