Tuesday, December 18, 2012

How to Cross-Compile libiconv for Android

If your legacy C/C++ code includes <iconv.h> to convert the encoding of characters from one coded character set to another, and you need to cross-compile it with the Android NDK, you will get the following error:

   error: iconv.h: No such file or directory

In fact there is currently no iconv.h available in the Android NDK and you will have to port libiconv to Android yourself.
I successfully used the following instructions to cross-compile libiconv.so for Android.

Get the source code for libconv-1.13.1:
 
   $ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz
 
Unzip and untar the file:

   $ tar zxvf libiconv-1.13.1.tar.gz
 
Patch localcharset.c using the following patch file (or else you will get another error: : langinfo.h: No such file or directory) :
 
   $ echo "diff --ignore-file-name-case -wuprN libiconv-1.13.1.orig/libcharset/lib/localcharset.c libiconv-1.13.1/libcharset/lib/localcharset.c
--- libiconv-1.13.1.orig/libcharset/lib/localcharset.c  2009-06-21 07:17:33.000000000 -0400
+++ libiconv-1.13.1/libcharset/lib/localcharset.c       2012-12-18 10:20:27.000000000 -0500
@@ -44,7 +44,7 @@
 # endif
 #endif

-#if !defined WIN32_NATIVE
+#if !defined(WIN32_NATIVE) && !defined(__ANDROID__)
 # if HAVE_LANGINFO_CODESET
 #  include <langinfo.h>
 # else
@@ -328,7 +328,7 @@ locale_charset (void)
   const char *codeset;
   const char *aliases;

-#if !(defined WIN32_NATIVE || defined OS2)
+#if !(defined WIN32_NATIVE || defined OS2 || defined __ANDROID__)

 # if HAVE_LANGINFO_CODESET " > iconv.patch

   $ patch -b -p0 < ./iconv.patch


Run the configure script and generate iconv.h:

   $ cd libiconv-1.13.1
   $ ./configure

Create a jni sub-directory:
 
$ mkdir jni
 
And save the following lines in jni/Android.mk:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_ARCH_ABI := armeabi-v7a
LOCAL_MODULE    := iconv
LOCAL_CFLAGS    := \
    -Wno-multichar \
    -D_ANDROID \
    -DLIBDIR="\"c\"" \
    -DBUILDING_LIBICONV \
    -DIN_LIBRARY
LOCAL_C_INCLUDES := \
    ../libiconv-1.13.1 \
    ../libiconv-1.13.1/include \
    ../libiconv-1.13.1/lib \
    ../libiconv-1.13.1/libcharset/include
LOCAL_SRC_FILES := \
    ../libiconv-1.13.1/lib/iconv.c \
    ../libiconv-1.13.1/lib/relocatable.c \
    ../libiconv-1.13.1/libcharset/lib/localcharset.c
include $(BUILD_SHARED_LIBRARY)
 
Finally cross-compile iconv using the ndk-build tool:

   $ cd jni
   $ ndk-build V=1
If everything goes well, you will find iconv.h under libiconv-1.13.1/include and libiconv.so under libs/armeabi.

11 comments:

  1. Thanks your hack for langinfo really helped!

    ReplyDelete
  2. Thanks dude! This helped me a lot. :-) -- Sreekanth

    ReplyDelete
  3. Hi,

    Thanks for the post. How did you do it? My app crashes when it starts on Android.

    Please help

    Thank you

    Joe

    ReplyDelete
    Replies
    1. I couldnt find libcharset.c anywhere. so I patched /libcharset/lib/localcharset.c.

      Joe

      Delete
    2. Joe,

      unless you post the error from logcat I cannot tell what kind of problems your app is having.

      Delete
    3. Joe,

      yes you are right you were supposed to patch localcharset.c and not libcharset.c. I will fix the blog post to reflect this.

      Delete
  4. Hi Danilo

    The output of adb logcat has the following:

    D/dalvikvm(27366): Trying to load lib /data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so 0x43cbfc18
    E/dalvikvm(27366): dlopen("/data/app-lib/org.qtproject.example.AndroidTest-1/libAndroidTest.so") failed: dlopen failed: could not load library "libiconv.so" needed by "libAndroidTest.so"; caused by library "libiconv.so" not found
    D/AndroidRuntime(27366): Shutting down VM
    W/dalvikvm(27366): threadid=1: thread exiting with uncaught exception (group=0x41bffd88)
    E/AndroidRuntime(27366): FATAL EXCEPTION: main
    E/AndroidRuntime(27366): Process: org.qtproject.example.AndroidTest, PID: 27366
    E/AndroidRuntime(27366): java.lang.UnsatisfiedLinkError: dlopen failed: could not load library "libiconv.so" needed by "libAndroidTest.so"; caused by library "libiconv.so" not found

    It seems that the application cant find the liiconv.so file, not sure where to copy this, as I've copied it to my application folder to test with, then build the QZxing lib with it when the application builds.

    I appreciate your help

    Joe

    ReplyDelete
    Replies
    1. Hi

      Found the problem, needed to copy libiconv.so to android-build/libs.

      Your tip on logcat helped me alot, I'm still an android noob.

      thank you.

      Delete
  5. Hi Danilo,

    Thanks for the very helpful post. In case anyone is interested, here are the modifications I had to make to localcharset.c to get it to work with libiconv-1.14:

    Line 48:
    #if !defined WIN32_NATIVE && !defined(__ANDROID__)

    Line 127:
    #if !(defined DARWIN7 || defined VMS || defined WIN32_NATIVE || defined __CYGWIN__ || defined __ANDROID__)

    Line 364:
    #if !(defined WIN32_NATIVE || defined OS2 || defined __ANDROID__)

    Greg

    ReplyDelete
  6. I tried this method with gkbrown's changes and at first it didn't work. I nneded ARMv7a But it only compiled for ARMv5 even with TARGET_ARCH_ABI := all. The thing is that you should apparantly not set target arch this way. Add a file 'Application.mk' with:

    APP_ABI := all

    and remove TARGET_ARCH_ABI line. Now ndk-build will build for all targets :)

    ReplyDelete