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

Missing: How to configure Android project for GNUstep use #7

Closed
mehlkelm opened this issue Feb 12, 2020 · 15 comments
Closed

Missing: How to configure Android project for GNUstep use #7

mehlkelm opened this issue Feb 12, 2020 · 15 comments

Comments

@mehlkelm
Copy link

As an iOS developer with little Android experience (which makes GNUstep especially tempting) I had no problem going from the toolchain setup instructions to the sample project. However, configuring your own new or existing Android project for GNUstep is not yet documented.

Looking at the linked android-examples I tried the following (maybe this can be used as a draft for a new section at the end of the existing README, once it works):

  1. New project in Android Studio
    a. Basic Fragment with View Model
    b. Enable Kotlin

  2. Create folder app/src/main/cpp

  3. Add CMakeLists.txt () to cpp folder

  4. Edit CMakeLists.txt to include your Objective-C implementation (.m) files in OBJECTIVEC_SRCS

  5. Edit app/build.gradle. Add:

    externalNativeBuild {
    cmake {
    cppFlags ""
    }
    }
    ndk {
    // ABIs supported by GNUstep toolchain
    abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
    }

  6. Edit MainActivity class: Add

    init {
    System.loadLibrary(„native-lib“)
    }

So far this fails at System.loadLibrary("native-lib") with following error:

2020-02-12 12:32:19.933 985-985/zoziapps.ch.sousvidecelsius E/AndroidRuntime: FATAL EXCEPTION: main
Process: zoziapps.ch.sousvidecelsius, PID: 985
java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "_ZNSt6__ndk111__call_onceERVmPvPFvS2_E" referenced by "/data/app/zoziapps.ch.sousvidecelsius-qgnwdnfRmeXSFCUffVd7bw==/lib/x86/libgnustep-base.so"...
at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
at java.lang.System.loadLibrary(System.java:1669)
at zoziapps.ch.sousvidecelsius.MainActivity.(MainActivity.kt:15)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:43)
at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2831)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

@triplef
Copy link
Member

triplef commented Feb 12, 2020

Thanks for your feedback! One step that’s missing is setting the NDK path in the app settings > SDK Location. If you’re on a Mac you should set it to the custom NDK that is installed by the toolchain in:
~/Library/Android/android-ndk-r20-clang-r353983c1

Can you check if that helps with the linker error?

@mehlkelm
Copy link
Author

I can't find "App settings".
Do you mean "Android NDK location" in File > Project Structure… > SDK Location?
Setting it there doesn't help.

@triplef
Copy link
Member

triplef commented Feb 12, 2020

Yeah that’s the right setting.

I found that for me, if I understand it correctly _ZNSt6__ndk111__call_onceERVmPvPFvS2_E is defined in (not referenced by) libgnustep-base.so. Can you run the following and see if you get the same result?

$ nm ~/Library/Android/GNUstep/x86/lib/libgnustep-base.so | grep _ZNSt6__ndk111__call_onceERVmPvPFvS2_E
00758380 T _ZNSt6__ndk111__call_onceERVmPvPFvS2_E

@triplef
Copy link
Member

triplef commented Feb 12, 2020

Also, does the hello-objectivec example work for you?

@mehlkelm
Copy link
Author

The hello-objectivec example works perfectly, and that without any "Android NDK location" setting!

My result:

$ nm ~/Library/Android/GNUstep/x86/lib/libgnustep-base.so | grep _ZNSt6__ndk111__call_onceERVmPvPFvS2_E
         U _ZNSt6__ndk111__call_onceERVmPvPFvS2_E

@triplef
Copy link
Member

triplef commented Feb 13, 2020

Hmm interesting. Looks like your libgnustep-base.so (unlike mine) doesn’t define the function. Could you attach your (zipped) ~/Library/Android/GNUstep/build.log?

That being said, question is why the example still works... I noticed in step 6 above you wrote that you call System.loadLibrary() in an init method. Can you try putting it in a static initializer as in the example?

static {
    System.loadLibrary("native-lib");
}

@mehlkelm
Copy link
Author

mehlkelm commented Feb 13, 2020

I'm on Kotlin, so static won't work here. I tried to do it according to the "Native C++" Android Studio template (like below) which also doesn't work:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        initializeGNUstep(this);

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val navView: BottomNavigationView = findViewById(R.id.nav_view)

        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_temperatures
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }

    external fun initializeGNUstep(context: Context?)

    companion object {

        // Used to load the 'native-lib' library on application startup.
        init {
            System.loadLibrary("native-lib")
        }
    }
}

@triplef
Copy link
Member

triplef commented Feb 13, 2020

I’ve never used Kotlin – could you try it with a Java project just to narrow it down further?

@mehlkelm
Copy link
Author

Kotlin can't be the issue:
a) I get the same problem with a brand new Java Project (no Kotlin, no AndroidX)
b) I can convert your hello-objectivec and its MainActivity to Kotlin while still being able to load native-lib

@triplef
Copy link
Member

triplef commented Feb 13, 2020

I see. I have no idea why the example project works and a new project doesn’t, and I cannot reproduce the issue. But the core issue seems to be that your GNUstep library file doesn’t define some symbols that mine does. If you could send me your build.log I can see if I can spot some differences in your build process that might be specific to your machine/setup.

@mehlkelm
Copy link
Author

The good news: I got it working!
The bad news: I still have to find out how…
Will analyze a bit more and then post step by step how it works reproducibly for me.

@mehlkelm
Copy link
Author

This pull request would document what worked for me: #8.

@triplef
Copy link
Member

triplef commented Feb 25, 2020

Thanks for the PR! Can you tell what the missing bit was to get it working in the end?

@mehlkelm
Copy link
Author

mehlkelm commented Mar 5, 2020

In the end I tried so much stuff that I'm not sure what exactly worked but I suspect step 6: "Link to C++" was missing.

triplef added a commit that referenced this issue Mar 10, 2020
This is the correct thing to do when using multiple shared libraries, and fixes libgnustep-base.so referencing C++ symbols like "call_once" without actually linking against the C++ standard libray.

See also #7.
@triplef
Copy link
Member

triplef commented Mar 10, 2020

I fixed the underlying issue causing the linker error with _ZNSt6__ndk111__call_onceERVmPvPFvS2_E: the toolchain libraries were not correctly linking against the shared C++ runtime library.

Please try rebuilding the toolchain with the latest changes, and also update your Gradle setup to use the shared C++ runtime library like this:
gnustep/android-examples@d3f5aba

Regarding instructions to integrate this in your own project I hope to be able to create a standalone CMake toolchain file that can simply be included in Android Studio (that’s why I haven’t merged your PR yet).

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

No branches or pull requests

2 participants