Problem loading C++ library in android

853 views
Skip to first unread message

Ashutosh

unread,
Jun 2, 2008, 12:29:20 AM6/2/08
to Android Internals
Hello All,

I am trying to call an API in a C++ library libNativeCpp.so and
Android does not load it. The error is --

DEBUG/dalvikvm(1185): LOADING path /system/lib/libNativeCpp.so
0x4001f6e8
INFO/dalvikvm(1185): Unable to dlopen(/system/lib/libNativeCpp.so):
Cannot find library

I have used arm-2008q1/bin/arm-none-linux-gnueabi-gcc, arm-2008q1/bin/
arm-none-linux-gnueabi-g++ for compilation.

How I tried to do that is explained below --

I have gone through the URL
http://davanum.wordpress.com/2007/12/09/android-invoke-jni-based-methods-bridging-cc-and-java/
and have been able to run the program successfully.

After this I have made some changes in the source code.
1) I have changed signature of function add() in class NativeAdd. It
is now 'public static native long add(int a, int b)'.
2) I have changed function Java_org_apache_NativeAdd_add() in file
org_apache_NativeAdd.c. It now looks like --

#include "org_apache_NativeAdd.h"

JNIEXPORT jlong JNICALL Java_org_apache_NativeAdd_add
(JNIEnv *env, jclass c, jint a, jint b)
{
long aa;
aa = ret_mul(a, b);
// aa = ret_mul_cpp(a, b);
return aa;
}

The function ret_mul() is written in another file called NativeC.c.
Content of file is --
#include <stdio.h>
int ret_mul(int a, int b)
{
return (a * b);
}

Now I compile these files and create libraries --

arm-none-linux-gnueabi-gcc -I /usr/java/jdk1.6.0_04/include -I /usr/
java/jdk1.6.0_04/include/linux -fpic -c org_apache_NativeAdd.c
arm-none-linux-gnueabi-ld -T armelf_linux_eabi.xsc -shared -o
libNativeAdd.so org_apache_NativeAdd.o


arm-none-linux-gnueabi-gcc -fpic -c NativeC.c
arm-none-linux-gnueabi-ld -T armelf_linux_eabi.xsc -shared -o
libNativeC.so NativeC.o

The file armelf_linux_eabi.xsc is modified as per the suggestion on
the URL http://honeypod.blogspot.com/2007/12/shared-library-hello-world-for-android.html
.

I pushed the library to android environment --
adb push libNativeAdd.so /system/lib
adb push libNativeC.so /system/lib

I have created an android project CallNative1 and in file
NativeAdd.java, I am loading libraries as below --
System.loadLibrary("NativeC");
System.loadLibrary("NativeAdd");

When I run the project CallNative1, it prints the result as
multiplication of two integers.

Now I write the same ret_mul() function in NativeCpp.cpp. Content of
NativeCpp.cpp is --

#include <iostream>
int ret_mul_cpp(int a, int b)
{
return (a * b);
}

Compiled it --

arm-none-linux-gnueabi-g++ -fpic -c NativeCpp.cpp
arm-none-linux-gnueabi-ld -T armelf_linux_eabi.xsc -shared -o
libNativeCpp.so NativeCpp.o

Pushed the library --

adb push libNativeCpp.so /system/lib

Now loading libraries as below --

System.loadLibrary("NativeCpp");
System.loadLibrary("NativeAdd");


When I run CallNative1 again I can see below errors in logcat.

DEBUG/dalvikvm(1185): LOADING path /system/lib/libNativeCpp.so
0x4001f6e8
INFO/dalvikvm(1185): Unable to dlopen(/system/lib/libNativeCpp.so):
Cannot find library


Below are the information about symbols in both the libraries --


arm-none-linux-gnueabi-nm libNativeC.so
00000244 a _DYNAMIC
0000029c a _GLOBAL_OFFSET_TABLE_
000002a8 A __bss_end__
000002a8 A __bss_start
000002a8 A __bss_start__
000002a8 D __data_start
000002a8 A __end__
00000244 A __exidx_end
00000244 A __exidx_start
000002a8 A _bss_end__
000002a8 A _edata
000002a8 A _end
00000214 T ret_mul


arm-none-linux-gnueabi-nm libNativeCpp.so
=========================================
000007a0 a _DYNAMIC
00000840 a _GLOBAL_OFFSET_TABLE_
000006ec t _GLOBAL__I__Z11ret_mul_cppii
00000460 T _Z11ret_mul_cppii
00000640 t _Z41__static_initialization_and_destruction_0ii
U _ZNKSs4sizeEv
U _ZNKSsixEj
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
00000490 t _ZSt17__verify_groupingPKcjRKSs
00000708 W _ZSt3minIjERKT_S2_S2_
00000868 b _ZSt8__ioinit
U __aeabi_atexit
U __aeabi_unwind_cpp_pr0
U __aeabi_unwind_cpp_pr1
0000086c A __bss_end__
00000868 A __bss_start
00000868 A __bss_start__
00000868 B __data_start
U __dso_handle
0000086c A __end__
0000079c A __exidx_end
00000774 A __exidx_start
0000086c A _bss_end__
00000868 A _edata
0000086c A _end

I have gonr through the discussion at
http://groups.google.com/group/android-internals/browse_thread/thread/780ba5316409cf5d
and I also feel that the problem is with unresolved symbols.

I pulled whole /system directory from Android and treid to grep one of
the undefined symbols _ZNKSs4sizeEv, in /system but could not find it.
But if I grep them in arm-2008q1 directory I find many matches.

grep -r _ZNKSs4sizeEv arm-2008q1/*
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/armv4t/usr/lib/
libstdc++.so.6 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/armv4t/usr/lib/
libstdc++.a matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/armv4t/usr/lib/
libstdc++.so.6.0.9 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/armv4t/usr/lib/
libstdc++.so matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/thumb2/usr/lib/
libstdc++.so.6 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/thumb2/usr/lib/
libstdc++.a matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/thumb2/usr/lib/
libstdc++.so.6.0.9 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/thumb2/usr/lib/
libstdc++.so matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/usr/lib/libstdc+
+.so.6 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/usr/lib/libstdc++.a
matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/usr/lib/libstdc+
+.so.6.0.9 matches
Binary file arm-2008q1/arm-none-linux-gnueabi/libc/usr/lib/libstdc+
+.so matches

I don't know why these symbols are not there in /system/lib at
android. Statically linking a C++ library is not advisable.

Could anyone please suggest me how do I go about it ?

Thanks
Ashutosh


Diluka Moratuwage

unread,
Jun 2, 2008, 1:15:23 AM6/2/08
to android-...@googlegroups.com
Hi,
You might have missed the linker option. Please make sure that your
library doesn't use the default linux linker; /lib/ld-linux.so.2 , if
it's used then you are in trouble. You have to use the custom linker and
build your library from scratch and check regularly for the
functionality. Most of the default C/C++ stuff are missing in the
Android platform, so you might spend a whole lot of time and then
finally get into trouble. I'm writing you because same thing happened to
me. Please make sure if there is a list of available functions in the
platform as well, if you are using some functions from the Android platform.

I'm quite sure this problem is due to the incompatibility of the
libraries. So, I advise you to hit ldd, and check the libraries it loads.

Thanks,
Diluka.

Ashutosh Malviya

unread,
Jun 2, 2008, 7:11:40 AM6/2/08
to android-...@googlegroups.com
I have tried dynamic linker option also but still, dlopen() fails.

arm-none-linux-gnueabi-ld --dynamic-linker /system/bin/linker -T armelf_linux_eabi.xsc -shared -o libNativeCpp.so NativeCpp.o

Also I have looked at object file below --

arm-none-linux-gnueabi-nm NativeCpp.o

         U _GLOBAL_OFFSET_TABLE_
0000028c t _GLOBAL__I__Z11ret_mul_cppii
00000000 T _Z11ret_mul_cppii
000001e0 t _Z41__static_initialization_and_destruction_0ii

         U _ZNKSs4sizeEv
         U _ZNKSsixEj
         U _ZNSt8ios_base4InitC1Ev
         U _ZNSt8ios_base4InitD1Ev
00000030 t _ZSt17__verify_groupingPKcjRKSs
00000000 W _ZSt3minIjERKT_S2_S2_
00000000 b _ZSt8__ioinit

         U __aeabi_atexit
         U __aeabi_unwind_cpp_pr0
         U __aeabi_unwind_cpp_pr1
         U __dso_handle

Object file itself has many symbols that I did not find in /system/lib.

When I try to hit ldd for this library, I get message as "not a dynamic executable".

I have tried to find _ZNKSs4sizeEv in /usr/lib and this symbol matches many libraries including standard c++ library.

objdump -T /usr/lib/gcc/i486-linux-gnu/4.1/libstdc++.so | grep _ZNKSs4sizeEv
000931b0  w   DF .text    0000000d  GLIBCXX_3.4 _ZNKSs4sizeEv

I can also see these symbols in the library in the arm toolchain arm-2008q1.

I am not able to understand why these symbols are not there in /system/lib. Do we need separate compiler for this, as there is no standards for mangling the names ?

Regards
Ashutosh

David Given

unread,
Jun 2, 2008, 7:59:56 AM6/2/08
to android-...@googlegroups.com
Ashutosh wrote:
[...]

> INFO/dalvikvm(1185): Unable to dlopen(/system/lib/libNativeCpp.so):
> Cannot find library

This error usually shows up for unresolved symbols.

[...]


> System.loadLibrary("NativeC");
> System.loadLibrary("NativeAdd");

It's entirely possible that System.loadLibrary() doesn't allow libraries
to see symbols defined in other libraries, so you won't be able to have
NativeAdd depend on NativeC. However, I suspect your main problem is...

[...]
> #include <iostream>

iostream could well be trying to pull in symbols that the very
stripped-down libc supported by the dalvik executable won't have.

--
┌─── dg@cowlark.com ───── http://www.cowlark.com ─────
│ "I have always wished for my computer to be as easy to use as my
│ telephone; my wish has come true because I can no longer figure out
│ how to use my telephone." --- Bjarne Stroustrup

signature.asc

Keelong

unread,
Jun 2, 2008, 10:27:25 PM6/2/08
to Android Internals

Did anyone ever build JNI library *.so for Android by C++ code
successfully?
I only can build and run the library by pure C on Android, but fail in
C++.
If you can, please show the sample code of C++ JNI.
Thanks.
Keelong

Ashutosh Malviya

unread,
Jun 4, 2008, 1:40:01 AM6/4/08
to android-...@googlegroups.com
On Mon, Jun 2, 2008 at 5:29 PM, David Given <d...@cowlark.com> wrote:
>>Ashutosh wrote:
>>[...]
> INFO/dalvikvm(1185): Unable to dlopen(/system/lib/libNativeCpp.so):
> Cannot find library

>>This error usually shows up for unresolved symbols.
 
David Given wrote:
>>[...]
> System.loadLibrary("NativeC");
> System.loadLibrary("NativeAdd");

>>It's entirely possible that System.loadLibrary() doesn't allow libraries
>>to see symbols defined in other libraries, so you won't be able to have
>>NativeAdd depend on NativeC. However, I suspect your main problem is...

 I tried to change the order of loading library (i.e. loading NativeAdd first and NativeC later, but android failed to load NativeAdd library, probably because it was not able to resolve symbol ret_mul .

 David Given wrote:
>>[...]
> #include <iostream>

>>iostream could well be trying to pull in symbols that the very
>>stripped-down libc supported by the dalvik executable won't have.

Removing iostream and using 'extern "C"' made the library which has only one undefined symbol '__aeabi_unwind_cpp_pr0' which is available in /system/lib


arm-none-linux-gnueabi-nm libNativeCpp.so
0000029c a _DYNAMIC
000002f4 a _GLOBAL_OFFSET_TABLE_
         U __aeabi_unwind_cpp_pr0
00000300 A __bss_end__
00000300 A __bss_start
00000300 A __bss_start__
00000300 D __data_start
00000300 A __end__
0000029c A __exidx_end
00000294 A __exidx_start
00000300 A _bss_end__
00000300 A _edata
00000300 A _end
00000260 T ret_mul_cpp

Thanks for the help.

But does this mean that all that big chunk of C and C++ source code that I wanted to port to android will not be possible ?

I think Diluka had also experience problem porting his C/C++ code to android.

Diluka, would you please comment on this. Could you port all your C/C++ source code to android? If yes could please give some points which I need to take care while porting my C/C++ source code?

Thanks
Ashutosh



Diluka Moratuwage

unread,
Jun 4, 2008, 2:25:39 AM6/4/08
to android-...@googlegroups.com
I'm really sorry for not being so specific about the topic. I gave up
the idea after trying trying and trying on that, so didn't even like to
dig into that again :-) .

The main problem which you will need to address is that the libraries we
use inside from your *.so files, will need the default linux linker
(ld-linux.so*), and some other *.so files. So we can get rid of the
problem of not having libraries in the Android platform by copying it
into the Android platform with other libraries and setting rpath
variable while compiling. Then all the libraries+programs you run on
Android will run successfully. They you also can run a C/C++ binary from
Android platform (using it's console).

But remember your all capabilities end when you try on using JNI, if you
have a look into the dalvik VM (I actually have forgotten the binary
name correspond to the vm inside Android), it will use a custom linker
(also do not remember the name, you can do a ldd after copying that
binary into the local machine-actually not ldd, but I guess
arm-none-linux-gnueabi-ldd as far as I remember). Then you will realize
that it will load a custom linker (NOT ld-linux as in ALL the other
Linux distributions), so when you see that point it's almost done buddy.
You can't load your libraries which you copied from cross-platform
development system, and the ones you built using that platform.

But I guess for very very simple *.so files, we can load from JNI, which
might have the neccessary symbols in libraries that included with
Android. Basically for me I wasted a lot of time doing these things.

My suggestion for you is that, do not go for serious development using
native libraries until the list of API functions in Android becomes
available. Else you will soon meet lots of troubles.

Thanks,
Diluka.

David Given

unread,
Jun 4, 2008, 8:36:54 AM6/4/08
to android-...@googlegroups.com
Ashutosh Malviya wrote:
[...]

> I tried to change the order of loading library (i.e. loading NativeAdd
> first and NativeC later, but android failed to load NativeAdd library,
> probably because it was not able to resolve symbol ret_mul .

That's not quite what I meant. System.loadLibrary() will ultimately call
the C system function dlopen() to do the work. When you call dlopen(),
you tell it that the symbols in the library are public (which means
other libraries can see them), or private (which means other libraries
can't see them). We don't know what option System.loadLibrary() is
using. I suspect it's going to be using the private option, which means
you won't be able to have one library refer to symbols in another one.

[...]


> Removing iostream and using 'extern "C"' made the library which has only
> one undefined symbol '__aeabi_unwind_cpp_pr0' which is available in
> /system/lib

Unfortunately it's not quite that easy...

My experimentation seems to show that only the symbols used in the
dalvik executable are available to JNI libraries. Since dalvik only uses
some of the symbols from the run-time library, that means you only have
those available to play with. (Remember this stuff is a hack!)

In my experience only the very simplest C code works reliably, and
you're probably going to have to implement workarounds for missing
run-time functions. In addition, dlopen() has some very serious bugs in
it which means that some code will simply be loaded incorrectly. (See
#599 on the bug tracker at http://code.google.com/p/android/issues/list
--- you would not *believe* the workaround I had to do to get around this.)

> But does this mean that all that big chunk of C and C++ source code that
> I wanted to port to android will not be possible ?

I would suggest not wasting time trying to make this work for now. For
my project, I did enough proof-of-concept code to verify that it *would*
all work, eventually, and then left it at that. Hopefully the next SDK
version will have some of these things fixed (particularly #599, which
is very critical).

signature.asc

Ashutosh Malviya

unread,
Jun 5, 2008, 1:19:20 AM6/5/08
to android-...@googlegroups.com
Hello Diluka,

Thanks for suggestion. I think I will wait for full documentation for development in C/C++ on android and then port my existing C/C++ code.

Ashutosh
 

2008/6/4 Diluka Moratuwage <dil...@wso2.com>:
Reply all
Reply to author
Forward
0 new messages