Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use my own compiled library? #55

Closed
shekmun opened this issue Dec 22, 2015 · 29 comments
Closed

How to use my own compiled library? #55

shekmun opened this issue Dec 22, 2015 · 29 comments
Labels

Comments

@shekmun
Copy link

shekmun commented Dec 22, 2015

I want use gsl library on my android phone. I've tried the gsl of javacpp-presets but it didn't work. The error said that some .so library did not found. So I want to compile the gsl library myself. I've download the gsl library and do as the gsl presets's cppbuild.sh. The main three line:

./configure --prefix=*** .... arm-linux-androideabi-gcc ....
make -j4
make install-strip

It works fine. And now I have a gsl library compiled with arm-linux-androideabi-gcc. Now I'm using this C++ code:

// JavacppDemo.h
#include "gsl/gsl_sf_bessel.h"
class Demo {
public:
    int get() {
        double x = 5.0;
        double y = gsl_sf_bessel_J0(x);
        return (int) y;
    }
};

And the java code:

@Platform(include={"JavacppDemo.h"}, link={"gslcblas", "gsl"})
public class JavacppDemo {
****
}

And I've added the header file path and library path of my newly compiled gsl library to the gradle file. So now I can completely rebuild the project and no errors come out. But when I run it, it says that "could not load library "libgsl.so.19"". I unzip the generated apk file and libgsl.so is not there(only my libjniJavacppDemo.so).

If I copy the libgsl.so to the armeabi folder, it won't package into the apk file automatically. So how to fix this? Please help me.

@saudet
Copy link
Member

saudet commented Dec 22, 2015

This is something that's been fixed a few days ago for a similar issue: bytedeco/javacpp-presets#127

Make sure your source code includes this commit: bytedeco/javacpp-presets@f594e8d

@shekmun
Copy link
Author

shekmun commented Dec 23, 2015

Thanks, but firstly if I change the edition to 1.2-SNAPSHOT the gradle could not download the jar.

compile 'org.bytedeco.javacpp-presets:gsl:1.2-SNAPSHOT'

And secondly, I've noticed that one line of code was added in the cppbuild.sh before the ./configure->make->make install:

patch -Np1 < ../../../gsl-$GSL_VERSION-android.patch

And I read the android.patch file and runs it. But it's not totally correct. I've tried the gsl-1.6 and gsl-2.1 both. Something didn't match the patch file. For example, in the version gsl-2.1 the cblas/Makefile.in was like this:

libgslcblas_la_LDFLAGS = $(GSLCBLAS_LDFLAGS) -version-info $(GSL_LT_CBLAS_VERSION)

But the patch file is like this and so the patch won't work.

-libgslcblas_la_LDFLAGS = -version-info $(GSL_LT_CBLAS_VERSION)

So I do this manually. That is edit the cblas/Makefile.am, cblas/Makefile.in, Makefile.am and Makefile.in and replace the "-version-info $(GSL_LT_CBLAS_VERSION)" with "-avoid-version". Then ./configure and make and make install. This work fine too and no version information in the generated library files. For example, I got a libgsl.so.19 before but now it's libgsl.so.

But my problem is when I'm using the compiled gsl library in my android studio, the app installs well but crash when running. Without any linking error or compile error. It just says the libgsl.so not found:

12-23 20:19:53.224 17215-17215/com.ict.hci.iwatcher E/dalvikvm: dlopen("/data/app-lib/com.ict.hci.iwatcher-1/libjniJavacppDemo.so") failed: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libgsl.so" needed by "libjniJavacppDemo.so"; caused by load_library(linker.cpp:745): library "libgsl.so" not found
12-23 20:19:53.227 17215-17215/com.ict.hci.iwatcher W/dalvikvm: Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lcom/ict/hci/iwatcher/service/JavacppDemo$NativeDemo;
12-23 20:19:53.227 17215-17215/com.ict.hci.iwatcher W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x40d01930)

And the libgsl.so is not packaged into the apk file.

@shekmun
Copy link
Author

shekmun commented Dec 23, 2015

I've copid the libgsl.so and libgslcblas.so into a folder lib/armeabi and then zip the lib folder into lib.zip and then rename it to lib.jar. And finally copy the lib.jar to my android libs folder. In this way the libgsl.so and libgslcblas.so was successfully packaged into the apk file. But I got the .so file not found error too and if I remember correctly the error was exactly the same error I got when I'm using gsl of javacpp-presets directly.

12-23 21:01:01.609 18106-18106/com.ict.hci.iwatcher E/dalvikvm: dlopen("/data/app-lib/com.ict.hci.iwatcher-2/libgsl.so") failed: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "cblas_sdsdot" referenced by "libgsl.so"...
12-23 21:01:01.609 18106-18106/com.ict.hci.iwatcher E/dalvikvm: dlopen("/data/app-lib/com.ict.hci.iwatcher-2/libjniJavacppDemo.so") failed: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libgsl.so" needed by "libjniJavacppDemo.so"; caused by find_library(linker.cpp:889): "libgsl.so" failed to load previously
12-23 21:01:01.609 18106-18106/com.ict.hci.iwatcher W/dalvikvm: Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lcom/ict/hci/iwatcher/service/JavacppDemo$NativeDemo;
12-23 21:01:01.609 18106-18106/com.ict.hci.iwatcher W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x40d01930)

@saudet
Copy link
Member

saudet commented Dec 23, 2015

I didn't notice GSL 2.x was released. We'll have to update that!

Anyway, for now, to get new binaries for 1.16, please try to follow the instructions here:
https://github.com/bytedeco/javacpp-presets/wiki/Build-Environments#android-arm-and-x86

@shekmun
Copy link
Author

shekmun commented Dec 24, 2015

I've found this link.

It says something about APP_PLATFORM in the android.mk. But we have no android.mk file in javacpp project. So does this really matters?

@saudet
Copy link
Member

saudet commented Dec 24, 2015

What error exactly do you get when running bash cppbuild.sh install?

@shekmun
Copy link
Author

shekmun commented Dec 24, 2015

Sorry, but I didn't run this bash directly. But I run the code in cppbuild.sh manually. The cppbuild.sh runs something like downloading the gsl.tgz and unzip it and then running the patch and configure->make->make install. The patch file has some errors cause it does not match my gsl library source code. But I can fix it by manually edit every file described upside. Until now no errors.
So I think "bash cppbuild.sh install" will have no error too(but need some edit to the patch file).

The error comes in the runtime. I'm sure the libgsl.so and libgslcblas.so and my own generated .so file was packaged and installed on my phone. But when I load the library with this:

Loader.load();
//or
//System.loadLibrary("gslcblas");
//System.loadLibrary("gsl");
//System.loadLibrary("jniJavacppDemo");

The error come out when loading gsl.

12-24 10:01:20.034 30345-30345/com.ict.hci.iwatcher E/dalvikvm: dlopen("/data/app-lib/com.ict.hci.iwatcher-1/libgsl.so") failed: Cannot load library: soinfo_relocate(linker.cpp:975): cannot locate symbol "cblas_sdsdot" referenced by "libgsl.so"...

@shekmun
Copy link
Author

shekmun commented Dec 24, 2015

By the way, which version of ndk did you used to compile the gsl-1.6? Some says r10 will lead to the "Cannot load library: soinfo_relocate" problem.

saudet added a commit to bytedeco/javacpp-presets that referenced this issue Dec 24, 2015
@saudet
Copy link
Member

saudet commented Dec 24, 2015

As per the message above, I've updated the presets for GSL 2.1, so executing bash cppbuild.sh install --platform android-arm should work now.

@shekmun
Copy link
Author

shekmun commented Dec 24, 2015

The patch file is OK now. But I've run the bash cppbuild.sh install --platform android-arm, there was some mistakes I think. I'm not familar with bash, but if I run this command the first "if" of cppbuild.sh will be true:

if [[ -z "$PLATFORM" ]]; then

and then when it goes to

pushd ..
bash cppbuild.sh "$@" gsl
popd

the bash cppbuild.sh "$@" gsl will fail and says that cppbuild.sh not found, I don't know why.

and what's more, the command download is not install on my ubuntu. And I can't install it with apt-get install.

But anyway, the cppbuild.sh is not my problem. I've make it work manually. So you could think that I can run bash cppbuild.sh install --platform android-arm without any errors.

My problem is in the runtime. I've packaged the libgsl.so and libgslcblas.so into my apk file. But when I excute

System.loadLibrary("gsl");

The error come out tells me that

12-24 23:42:25.820 21735-21735/com.ict.hci.iwatcher E/art: dlopen("/data/app/com.ict.hci.iwatcher-1/lib/arm/libgsl.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "cblas_sdsdot" referenced by "libgsl.so"...

@saudet
Copy link
Member

saudet commented Dec 25, 2015

Right, so try to use libraries built with the cppbuild.sh scripts. The error that you are getting indicates that the parent cppbuild.sh file is missing. So make sure that you haven't deleted it by mistake.

@shekmun
Copy link
Author

shekmun commented Dec 25, 2015

Indeed, I missed the parent cppbuild.sh and now I've added it to the parent directory. But then the case $PLATFORM in will go to linux-x86_64 branch. And what's more, if I change the code and make it go into the android-arm branch, the ANDROID_ROOT and ANDROID-BIN need to be set up to. I've set them to this:

ANDROID_ROOT=/home/shekmun/android/android-ndk-r10e/platforms/android-14/arch-arm
ANDROID_BIN=/home/shekmun/android/android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi

Is this right? Now it runs and generates the library.
And... even though, I don't think this will make any difference to my manual way. In fact I've checked the md5 of generated libgsl.so and libgslcblas.so, they are the same file to my manual way. In fact it's executing the same commands in both ways.

@saudet
Copy link
Member

saudet commented Dec 26, 2015

Calling System.loadLibrary("gsl") isn't needed. If you want to do that though, make sure to call System.loadLibrary("gslcblas") beforehand.

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

I'm doing this:

Loader.load();
//or
//System.loadLibrary("gslcblas");
//System.loadLibrary("gsl");
//System.loadLibrary("jniJavacppDemo");

Then I got the error. So how can I use the library without loading it?

This is my java code:

@Name("Demo")
public static class NativeDemo extends Pointer {
    static {
        System.loadLibrary("gslcblas");
        System.loadLibrary("gsl");
        System.loadLibrary("jniJavacppDemo");
        //Loader.load();
    }
    public NativeDemo() {
        allocate();
    }
    private native void allocate();
    private native int get();
}

In the C++ code of get(), I used the gsl function.

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

I checked the symbol link of libgsl.a and libgslcblas.a:

shekmun@shekmun-desktop:~/android/libs/lib$ nm libgsl.a | grep cblas_sdsdot
         U cblas_sdsdot
shekmun@shekmun-desktop:~/android/libs/lib$ nm libgslcblas.a | grep cblas_sdsdot
00000000 T cblas_sdsdot

Note that I'm checking the .a file not .so. The .so gives nothing. Does this help?

@saudet
Copy link
Member

saudet commented Dec 28, 2015

Why are you looking at the .a files?

Anyway, make sure your app's target SDK version is not 23 or higher: bytedeco/javacv#245

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

The output of .so:

shekmun@shekmun-desktop:~/android/libs/lib$ nm libgsl.so
nm: libgsl.so: no symbols

Targeting 20 gives the same error.

12-28 10:39:22.120 726-726/com.ict.hci.iwatcher E/art: dlopen("/data/app/com.ict.hci.iwatcher-2/lib/arm/libgsl.so", RTLD_LAZY) failed: dlopen failed: cannot locate symbol "cblas_sdsdot" referenced by "libgsl.so"...

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

It's weird. I run nm libgsl.a | grep U to see all the undefined symbol link, and some line of output and cblas_sdsdot is not the first one:

         ......
         U cblas_scnrm2
         U cblas_scopy
         U cblas_sdot
         U cblas_sdsdot
         U cblas_sgemm
         U cblas_sgemv
         U cblas_sger
         ......

And I've used the readelf command to check the .so file:

shekmun@shekmun-desktop:~/android/libs/lib$ readelf -Ws libgsl.so | grep cblas_sdsdot
   189: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND cblas_sdsdot
shekmun@shekmun-desktop:~/android/libs/lib$ readelf -Ws libgslcblas.so | grep cblas_sdsdot
    12: 0000298c   268 FUNC    GLOBAL DEFAULT    8 cblas_sdsdot

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

if I use readelf to check the undefined symbol link, the cblas_sdsdot is the first one of cblas library:

shekmun@shekmun-desktop:~/android/libs/lib$ readelf -Ws libgsl.so | grep UND
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND malloc
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND free
    10: 00000000     0 FUNC    GLOBAL DEFAULT  UND memset
    52: 00000000     0 FUNC    GLOBAL DEFAULT  UND fread
    54: 00000000     0 FUNC    GLOBAL DEFAULT  UND fwrite
    62: 00000000     0 FUNC    GLOBAL DEFAULT  UND putc
    63: 00000000     0 FUNC    GLOBAL DEFAULT  UND fprintf
    65: 00000000     0 FUNC    GLOBAL DEFAULT  UND fscanf
   189: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND cblas_sdsdot
   191: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND cblas_dsdot
   193: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND cblas_sdot
   195: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND cblas_ddot

So I think the error comes because of the system doesn't know where to find the symbol link. Maybe we should tell it to find it from "libgslcblas.so"? But how?

@saudet
Copy link
Member

saudet commented Dec 28, 2015

On Android, the official way is to call System.loadLibrary("gslcblas"). If that doesn't work on your version of Android, you should report this issue upstream to Google so they can have it fixed.

@shekmun
Copy link
Author

shekmun commented Dec 28, 2015

Ok, I will try as you said and do a bit more work on this. And if it works at last, I will post my solution here.

Thanks all the same!

@saudet
Copy link
Member

saudet commented Dec 28, 2015

Well, it looks like a bug in Android, but it would be nice to know the workaround, yes. I'll try out the new version myself next week, just to make sure that it still works :)

@saudet
Copy link
Member

saudet commented Dec 30, 2015 via email

@shekmun
Copy link
Author

shekmun commented Dec 31, 2015

Still no lucky for the ReLinker library. It's the same error. Thanks.

I tried to load the library in c++ code:

    int ret = 0;
    void *cblas = dlopen("/sdcard/Download/libgslcblas.so", RTLD_LAZY | RTLD_GLOBAL);
    if (cblas == NULL) ret += 1;
    else {
        void (*sdsdot)() = (void (*)()) dlsym(cblas, "cblas_sdsdot");
        ret += (sdsdot == NULL) ? 10 : 100;
    }
    void *gsl = dlopen("/sdcard/Download/libgsl.so", RTLD_LAZY | RTLD_GLOBAL);
    if (gsl == NULL) ret += 1000;
    return ret;

And the ret's value always be 1100! It seems that the RTLD_LAZY and RTLD_GLOBAL do not make any differences.

@saudet
Copy link
Member

saudet commented Jan 10, 2016

I've just tested here, and I'm getting the same exact problem, so it looks like a bug in Android. It should be reported upstream to the Android team, but if you're looking for a quick solution, I guess linking everything statically would work.

@saudet saudet removed the duplicate label Jan 10, 2016
saudet added a commit to bytedeco/javacpp-presets that referenced this issue Jan 10, 2016
@saudet
Copy link
Member

saudet commented Jan 10, 2016

Ok, I found a workaround. Check the latest commit I've made above, it works here. Basically, it looks like not only do we need to load manually all the libraries at runtime, but also we need to make sure that their names are linked in at build time as well.

@shekmun
Copy link
Author

shekmun commented Jan 12, 2016

Great Job!!! Now it works, fantastic, it's long time since I was stuck on the problem.

I'v added the GSL_LDFLAGS="-Lcblas/.libs/ -lgslcblas" to the ./configure to declare the dependency as the newly updated cppbuild.sh file, and nothing else changed, and it finally worked.

Thanks again. I've almost given it up. Really nice job and I appreciate it very very much. It helps me a lot 👍

@saudet
Copy link
Member

saudet commented May 19, 2016

Work around included in version 1.2. Thanks for reporting and spending time debugging this!

@saudet saudet closed this as completed May 19, 2016
@saudet
Copy link
Member

saudet commented May 21, 2020

BTW, a build plugin for Gradle is now available here:
https://github.com/bytedeco/gradle-javacpp
If you try it out and find anything missing, please let me know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants