Saturday, August 2, 2014

Problem on linking OpenSSL into your NDK application

This week, I tried to compile a simple NDK application and link it with the OpenSSL library. Most of libraries (including OpenSSL) are not supported by the NDK, what makes it a bit more complicated to use. So, in this post, I describe what I usually do to properly compile applications that need external libs.

The project structure is as follows:

    + jni/my_code.c
    + jni/
    + jni/
    + libs/system

Problem #01: How my looks like?

In this example, I need two libraries: and So, the final looks like this

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := my_exec
LOCAL_SRC_FILES := my_code.c
LOCAL_C_INCLUDES += $(ANDROID_SRC)/external/openssl/include \ 
                    $(ANDROID_SRC)/external/openssl/crypto \ 
LOCAL_LDLIBS += -L$(LOCAL_PATH)/../libs/system
LOCAL_SHARED_LIBRARIES := libandroid libdl libz libcrypto libssl
LOCAL_LDLIBS += -landroid -ldl -lz


See, as an example, that we also include the headers for the library (in ANDROID_SRC/external/openssl/include).

NDK does not provide support for and -- we need to have access to the libraries somehow. So, you should create a folder (for example, my_project/libs/system) and push the files /system/lib/ and /system/lib/ from the device to such folder.

Problem #02: Where do I get the libs from?

You shall get all of them (including from your rooted device. The point is that, as I said, NDK does not provide support for and Therefore, you need to get such libraries from the device. However, there's another problem: most likely, the and libraries don't recognize the symbols from the NDK and libraries. Regarding this problem, it will be discussed on item #04.

Problem #03: Where do I get the headers from?

Usually, you get them from the android source code. For OpenSSL, they are located inside the folder ANDROID_SRC/external.

Problem #04: Why does my lib complain about libc symbols?

As I described in topic #02, you need to copy the libraries from the device. However, and do not recognize some symbols from the and libraries (most likely, the libraries provided by NDK are not compatible with the ones in the device). Usually, you will have the following compilation error:

/home/raul/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/ error: undefined reference to '__strlen_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/ error: undefined reference to '__memcpy_chk'
/home/raul/android_development/android-ndk-r10/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/ error: undefined reference to '__memset_chk'
/home/raul/my_project/jni/../libs/system/ error: undefined reference to '__strchr_chk'
x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: /home/raul/my_project/jni/../libs/system/ error: undefined reference to '__strcat_chk'

That's easy to solve. Here comes the trick: you have to replace NDK's libraries by those ones from the device. NDK contains several libraries for distinct platforms, as we can see from the path NDK_FOLDER/platforms:

@desktop:$ ls NDK_FOLDER/platforms
android-12  android-13  android-14  android-15  android-16  android-17  
android-18  android-19  android-3   android-4   android-5   android-8  android-9

 Considering that your application is using NDK for platform android-17 (you can define that in file, replace the main libraries of folder NDK_PATH/platforms/android-17

@desktop:$ ls NDK_FOLDER/platforms/android-17/arch-arm/usr/lib
crtbegin_dynamic.o  crtend_android.o  libc.a libm_hard.a
crtbegin_so.o       crtend_so.o             libstdc++.a

crtbegin_static.o     libm.a 

So, push the libraries /system/lib/, and /system/lib/ from the device to the folder NDK_FOLDER/platforms/android-17/arch-arm/usr/lib. After that, compile the application again and voilĂ  -- all problems solved :-) 

No comments: