Search code examples
javac++libgdxjava-native-interface

UnsatisfiedLinkError on iOS but not Android, loadLibrary always succeeds


I have some Java and C++ code that I can compile on both platforms and build native libraries. I can verify that the libraries contain the functions I expect, and Java is able to load the libraries on Android and iOS. On Android everything goes smoothly with no crash, but on iOS I get a very frustrating error:

2015-05-11 11:34:48.418 IOSLauncher[52454:851038] [info] test: initializing native libraries...
2015-05-11 11:34:48.418 IOSLauncher[52454:851038] [info] test: library path set to:       "/Users/test/Library/Developer/CoreSimulator/Devices/A189459D-B2D5-4E78-A6E4-A7EAD19DA017/data/Containers/Bundle/Application/DF265D55-DA3C-4C10-851D-20591C4C8C06/IOSLauncher.app"
2015-05-11 11:34:48.419 IOSLauncher[52454:851038] [info] test: loading native libraries on x86_64...
2015-05-11 11:34:48.419 IOSLauncher[52454:851038] [info] test:  test
2015-05-11 11:34:48.424 IOSLauncher[52454:851038] [info] test: loaded libraries successfully

java.lang.UnsatisfiedLinkError: com/test/Native.getPointer()J
    at com.test.Native.getPointer(Native Method)
    at com.test.WavApp.initNativeEngine(WavApp.java)
    at com.test.WavApp.create(WavApp.java)
    at com.badlogic.gdx.backends.iosrobovm.IOSGraphics.draw(IOSGraphics.java)
    at com.badlogic.gdx.backends.iosrobovm.IOSGraphics$1.draw(IOSGraphics.java)
    at com.badlogic.gdx.backends.iosrobovm.IOSGraphics$1.$cb$drawRect$(IOSGraphics.java)
    at org.robovm.apple.uikit.UIApplication.main(Native Method)
    at org.robovm.apple.uikit.UIApplication.main(UIApplication.java)
    at com.test.IOSLauncher.main(IOSLauncher.java)


BUILD SUCCESSFUL

Total time: 18.262 secs

A snapshot of the java code in com/test/Native.java:

static 
{
      System.loadLibrary("test");
      Log.i("loaded libraries successfully");
}

public static native long getPointer();
public static native void freePointer(long enginePointer);

And the C++ code that compiles into libtest.dylib:

extern "C"
{
    JNIEXPORT jlong JNICALL Java_com_test_Native_getPointer(JNIEnv* env, jobject thiz)
    {
        return (jlong)(new PointerTest());
    }

    JNIEXPORT void JNICALL Java_com_test_Native_freePointer(JNIEnv* env, jobject thiz,
        jlong enginePtr)
    {
        if ((PointerTest*)enginePtr)
            delete (PointerTest*)enginePtr;
    }
}

Some more info about the built shared library:

Release$ file libtest.dylib
libtest.dylib: Mach-O 64-bit dynamically linked shared library x86_64

And verifying the exports:

$ nm -g libtest.dylib | grep Native
0000000000011ce0 T _Java_com_test_Native_freePointer
0000000000011c40 T _Java_com_test_Native_getPointer

Any ideas? This has been driving me crazy for hours. I can reproduce this error on my Android device by simply using a different library and searching for that function. I'm guessing xcode is somehow hiding or stripping the symbols, but that doesn't seem to correlate with my nm output above which shows they are there.


Solution

  • The solution was in front of me, as usual, in this line:

    libtest.dylib: Mach-O 64-bit dynamically linked shared library x86_64
    

    Building for iOS, the architecture should be armv7+. Misconfigured xcode subproject.