Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build and link multiple NDK libraries using gradle

I have an Android project that links together a bunch of sources into a single monolithic JNI library. I would like to split this single library out into multiple smaller libraries with some dependencies between them. How can I achieve this with the new gradle build system?

like image 228
Alex Flint Avatar asked Nov 10 '22 05:11

Alex Flint


1 Answers

You can achieve this with the standalone android native plugin from the experimental gradle plugin family. The new plugins are based on the gradle component approach towards modeling builds. There are many advantages to using the new system.

For example:

root
+ lib -> 'com.android.model.native'
+ lub -> 'com.android.model.native'
+ aar -> 'com.android.model.library'
+ app -> 'com.android.model.application'

build.gradle

configure([project(':lib'), project(':lub'), project(':aar'), project(':app')]) {
    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle-experimental:0.6.0-alpha5'
        }
    }
}

lib/build.gradle

apply plugin: "com.android.model.native"

model {
    android {
        compileSdkVersion 23
    ndk {
        moduleName "foo"
    }
    sources {
        main {
            jni {
                exportedHeaders {
                    srcDir "src/main/headers"
                }
            }
        }
    }
}

lub/build.gradle

apply plugin: "com.android.model.native"

model {
    android {
        compileSdkVersion 23
    ndk {
        moduleName "bar"
    }
    sources {
        main {
            jni {
                exportedHeaders {
                    srcDir "include"
                }
            }
        }
    }
}

aar/build.gradle

apply plugin: "com.android.model.library"

model {
    android {
        buildToolsVersion '23.0.2'
        compileSdkVersion 23
    ndk {
        moduleName "aggregate-jni"
        stl "stlport_shared" // using cpp?
    }
    sources {
        main {
            jni {
                dependencies {
                    project ":lib"
                    project ":lub"
                }
            }
        }
    }
}    

app/build.gradle

apply plugin: 'com.android.model.application'

model {
    android {
        buildToolsVersion '23.0.2'
        compileSdkVersion 23 

        defaultConfig {
            applicationId "com.example.app"
            minSdkVersion.apiLevel 21
            targetSdkVersion.apiLevel 23
            versionCode 1
            versionName "1.0"
        }
    }
}

dependencies {
    compile project(':aar')
}

If linkage is dynamic (default for ndk), the aar will contain:

libfoo.so libbar.so libaggregate-jni.so libstlport.so

and your mirror java classes. You can simply

System.load("aggregate-jni");

in your java classes and referenced libraries will load too. If linkage is static, you'll end up with a single libaggregate-jni.so anyway. Note that it's bad to link a bunch of things statically against the stl as you will end up with multiple copies of the stl in your binary. This can really mess things up.

Note that the default gcc toolchain is now deprecated. It's probably best to use:

model {
    android {
        ndk {
            toolchain 'clang'
            stl 'c++_shared'
        }
    }
} 

Finally, you absolutely don't need an aar, I simply included it for completeness. The app project can depend directly on standalone native lib projects as the application plugin fully support the ndk, too.

like image 99
dcow Avatar answered Jan 04 '23 03:01

dcow