zmartin
zmartin

Reputation: 211

Include Pre-compiled Static LIbrary using NDK

I am looking to include a static library that is pre-compiled in my Android Studio NDK project. I am using Android Studio 1.0.1, and any solutions that attempt this problem on SO seem outdated (or involves creating a library project and including it).

The structure is as follows:

app
/--src
/--main
/--java
+--jni
+--jniLibs
   /--armeabi
       /--libpng.a
    --armeabiv7
       /--libpng.a
    ...(for each abi)

I am attempting to include the library libpng. I tried creating jniLibs (as per ph0b (awesome guide, btw) and adding libpng.a to the respective ABI folder. This still gives me the error - cannot find -llibpng when I try to compile with the below code:

ndk {
        moduleName "game" 
        cFlags "-std=c++11 -fexceptions -DANDROID -I${project.buildDir}/../src/main/jni/include \
                -I${project.buildDir}/../src/main/jni/include/png"
        ldLibs "EGL", "GLESv3", "dl", "log", "android", "libpng"
        stl "gnustl_static"
}

Upvotes: 18

Views: 14803

Answers (5)

Rob Pridham
Rob Pridham

Reputation: 4938

This now works properly via the experimental plugin.

For a full description, see this whole excellent article, which is where I'm taking this from, but I am also using it myself and it works.

This is my build.gradle - note that in my case it's for a library project, and I'm using static links rather than shared.

buildscript {
    dependencies
            {
                classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha3"
            }
}
apply plugin: 'com.android.model.library'

model {
    repositories {
        libs(PrebuiltLibraries) {
            v8_base {
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("src/main/jni/libs/${targetPlatform.getName()}/libv8_base.a")
                }
            }
            v8_libbase {
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("src/main/jni/libs/${targetPlatform.getName()}/libv8_libbase.a")
                }
            }
            v8_libplatform {
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("src/main/jni/libs/${targetPlatform.getName()}/libv8_libplatform.a")
                }
            }
            v8_nosnapshot {
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("src/main/jni/libs/${targetPlatform.getName()}/libv8_nosnapshot.a")
                }
            }
        }
    }

    android {

        compileSdkVersion 23
        buildToolsVersion "23.0.2"

        sources {
            main {
                jni {
                    source {
                        srcDir "src/main/jni"
                    }
                    dependencies {
                        library "v8_base" linkage "static"
                        library "v8_libbase" linkage "static"
                        library "v8_libplatform" linkage "static"
                        library "v8_nosnapshot" linkage "static"
                    }
                }
            }
        }

        ndk {
            moduleName "v8example"
            cppFlags.add("-std=c++11")
            cppFlags.add("-I${file("src/main/jni/include")}".toString())
            cppFlags.add("-fexceptions")
            ldLibs.add("log")
            stl "stlport_static"
            abiFilters.add("armeabi armeabi-v7a x86")
        }
    }
}

The alternative is that you use the old Gradle approach of calling ndkBuild yourself, thus using the .mk files. That also works fine but you lose the nice integration with Android Studio, e.g. your jni files showing up appropriately.

Upvotes: 3

Aavaas
Aavaas

Reputation: 807

you cannot just include the .so files, you also need to have the src folders that actually provide the interface to access the methods in those .so files. I would recommend against coupling your project to the library that way.

The best way is to include it as a library module from android studio and discard the jni folders to disable ndkbuild and point the jnilib to the /libs folder by adding following to the build.gradle file

jni.srcDirs = [] //disable automatic ndk-build call
jniLibs.srcDirs = [ 'libs' ] //no need to copy the .so files from /libs to /jniLibs folder

(check that the libs directory has also been imported correctly by android studio with .so files)

importing the library as a module takes care of following automatically

a)yourlibrary library folder in your project folder and restructured according to gradle convention b)imported the project(include ':yourlibrary' in settings.gradle) and
c)created the dependencies (“File -> Project Structure -> Select main app module from the left subwindow -> Dependencies (last tab) -> Press the green “+” on your right -> yourlibrary as Module Dependency -> OK”)

Upvotes: 1

user4958329
user4958329

Reputation: 11

As ndk support is now limited in gradle, you could try this for static libraries of different abi.

    ndk {
        moduleName "game" 
        ....
        ldLibs ..., file(projectDir).absolutePath+"/src/main/jniLibs/\$(TARGET_ARCH_ABI)/libpng.a"
        ....
    }

Upvotes: 1

Keith
Keith

Reputation: 1133

This is really ugly, but it works! You can trick Gradle into allowing you to inject code into the generated Android.mk file:

    ndk {
        abiFilter "armeabi-v7a"

        // We need to inject the static library into the
        // NDK build, and Gradle doesn't offer a way to directly
        // modify the Android.mk file... So we hack it!
        //
        // You can see the end result at:
        //   build/intermediates/ndk/debug/Android.mk

        moduleName "This_is_a_terrible_Gradle_hack\n" +

        "include \$(CLEAR_VARS)\n" +

        "LOCAL_MODULE := mystaticlib_prebuilt\n" +
        "LOCAL_EXPORT_C_INCLUDES := mystaticlib/include\n" +
        "LOCAL_SRC_FILES := mystaticlib/libmystaticlib.a\n" +

        "include \$(PREBUILT_STATIC_LIBRARY)\n" +

        "include \$(CLEAR_VARS)\n" +
        "LOCAL_MODULE := MyActualModule\n" +
        "LOCAL_STATIC_LIBRARIES += mystaticlib_prebuilt"

        cFlags "-std=c++11 -fexceptions -frtti -pthread"
        stl "gnustl_shared"
        ldLibs "log", "OpenSLES", "z"
    }

Upvotes: 0

Vasanth
Vasanth

Reputation: 6385

Adding .so Library in Android Studio 1.0.2

  1. Create Folder "jniLibs" inside "src/main/"
  2. Put all your .so libraries inside "src/main/jniLibs" folder
  3. Folder structure looks like,
    |--app:
    |--|--src:
    |--|--|--main
    |--|--|--|--jniLibs
    |--|--|--|--|--armeabi
    |--|--|--|--|--|--.so Files
  4. No extra code requires just sync your project and run your application.

    Reference
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main

Upvotes: 1

Related Questions