6

I am moving my Android project that uses ndk-build to use the gradle build system as described in the examples of the new build tools for android. In this link http://tools.android.com/tech-docs/new-build-system. I am looked at the gradle-samples-0.11 at the bottom of the page for inspiration.

So I managed to configure all of the pieces I need by including the following code in my build.gradle default config section.

ndk {
            moduleName "MyModuleName"
            ldLibs "log"
            cFlags "-std=c++11 -fexceptions"
            stl "gnustl_static"
}

I have this line in my Application.mk file in the original project: NDK_TOOLCHAIN_VERSION := 4.9 It is the last piece I can't configure.

I am using NDK Revision 10. I need this NDK_TOOLCHAIN_VERSION:=4.9 because my build is reporting Error:(25, 11) error: expected nested-name-specifier before 'Integer' and the c++ code at that line looks like this.

using Integer = int16_t;

Does anyone have an idea on how I can solve this, please?

Janusz
  • 187,060
  • 113
  • 301
  • 369
maiatoday
  • 795
  • 2
  • 7
  • 15
  • adding something like abiFilters "x86_64" builds successfully as the 64bit build uses the toolchain 4.9 – maiatoday Aug 27 '14 at 11:40

4 Answers4

5

I've been trying to solve this too. But in the ended up by writing custom tasks to make Android Studio use Application.mk and Android.mk just like in eclipse.

My build.gradle looks like this

apply plugin: 'com.android.application'

android {

    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

    compileSdkVersion 20
    buildToolsVersion "20.0.0"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 20
        versionCode 1
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }

    sourceSets.main {
        jniLibs.srcDir 'src/main/libs'
        jni.srcDirs = [] //disable automatic ndk-build call
    }
}

task buildNative(type: Exec) {
    def ndkBuild = null;
    def ndkBuildingDir = new File("src/main/jni");
    def hasNdk = false;
    if (System.getenv("NDK_BUILD_CMD") != null) {
        hasNdk = true;
        ndkBuild = new File(System.getenv("NDK_BUILD_CMD"))
    }

    commandLine ndkBuild, "--directory", ndkBuildingDir

    doFirst {
        if (!hasNdk) {
            logger.error('##################')
            logger.error("NDK build failed!!")
            logger.error('Reason: NDK_BUILD_CMD not set.')
            logger.error('##################')
        }
        assert hasNdk: "NDK_BUILD_CMD not set."
    }
}
tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn buildNative }

task cleanNative(type: Exec) {
    def ndkBuild = null;
    def ndkBuildingDir = new File("src/main/jni");
    def hasNdk = false;

    if (System.getenv("NDK_BUILD_CMD") != null) {
        hasNdk = true;
        ndkBuild = new File(System.getenv("NDK_BUILD_CMD"))
    }

    commandLine ndkBuild, "--directory", ndkBuildingDir, "clean"

    doFirst {
        if (!hasNdk) {
            logger.error('##################')
            logger.error("NDK build failed!!")
            logger.error('Reason: NDK_BUILD_CMD not set.')
            logger.error('##################')
        }
        assert hasNdk: "NDK_BUILD_CMD not set."
    }
}
clean.dependsOn 'cleanNative'

For this to work, you need to set an environment variable NDK_BUILD_CMD to be set the the exact ndk-build executable.

On Windows, you can just set an environment variable NDK_BUILD_CMD point to your ndk-build.exe

On Mac,the path variables you set in your .bash_profile is not accessible on GUI applications(hence Android Studio will not be able to read them). So edit your .bash_profile to be something like

GRADLE_HOME={path_to_gradle}
ANDROID_SDK_ROOT={path_to_sdk_dir}
ANDROID_HOME=$ANDROID_SDK_ROOT/platform-tools
ANDROID_NDK_HOME={path_to_ndk}
NDK_BUILD_CMD=$ANDROID_NDK_HOME/ndk-build 

export PATH=$GRADLE_HOME/bin:$ANDROID_HOME:$ANDROID_SDK_ROOT/tools:$ANDROID_NDK_HOME:/opt/local/bin:/opt/local/sbin:$PATH

launchctl setenv GRADLE_HOME $GRADLE_HOME
launchctl setenv ANDROID_HOME $ANDROID_HOME
launchctl setenv ANDROID_NDK_HOME $ANDROID_NDK_HOME
launchctl setenv NDK_BUILD_CMD $NDK_BUILD_CMD

The launchctl lines will make your environment variables visible inside your Android Studio. PS: The .bash_profile is run every time you open the terminal. So for this to work properly with Android Studio, you need to launch the terminal once and then run Android Studio. Otherwise the build will fail saying NDK_BUILD_CMD not set. I haven't found any way to set the values when Mac starts. If someone else can find a way, please feel free to suggest.

Sugesh
  • 246
  • 2
  • 6
  • I have a custom build at the moment with similar custom tasks in my gradle build file. This is what I was trying to migrate away from. – maiatoday Aug 27 '14 at 10:34
  • After much testing I found that I had to revert to your solution Sugesh, the crux was to disable automatic ndk-build call by setting jni.srcDirs to empty and putting the Android.mk and Application.mk file back. So I am going to mark your answer as the solution. I also got it to work by setting an environment variable NDK_TOOLCHAIN_VERSION=4.9. So if there was a way to set and environment variable for this task it would have worked but I couldn't find a way to do this in gradle with the android plugin. – maiatoday Aug 28 '14 at 10:22
  • This blog post was also useful: http://ph0b.com/android-studio-gradle-and-ndk-integration/ but it suggests the same solution. – maiatoday Aug 28 '14 at 10:23
3

I've just had this problem, but my solution was actually in your initial question. The latest version of the NDK uses GCC 4.9 by default (https://developer.android.com/tools/sdk/ndk/index.html). This is only default on a 64bit machine it would seem. So you no longer need to set the NDK_TOOLCHAIN_VERSION property in your build.gradle file. So simply setting:

cFlags "-std=c++11 -fexceptions"
stl "gnustl_static"

in ndk{} Should be enough. Works for me.

docjaq
  • 71
  • 5
  • this worked however the 32bit abi still uses the old toolchain and it fails to build for 32bit abi's for my code. I can't load the 64bit build on the emulator it complains that the architecture does not match. – maiatoday Aug 28 '14 at 20:55
3

although this question was asked a long time ago, the proper solution as described in (https://developer.android.com/studio/projects/install-ndk): If you install a specific version of the NDK and want to use it in a module, you specify it using the android.ndkVersion property in the module's build.gradle file, as shown in the following code sample.

android {
    ndkVersion "major.minor.build"
}
1

In the latest version of Android Studio 1.5 and Gradle 2.10 with Experimental Plugins 0.7.0-alpha4, you can specify like this example it uses Clang toolchain with version 3.6..

ndk {
                moduleName "MyModuleName"
                ldLibs "log"
                cFlags "-std=c++11 -fexceptions"
                stl "gnustl_static"
                toolchain "clang"
                toolchainVersion = "3.6" 
}

You can refer your NDK directory to know which toolchain and which versions are available.
For NDK r10e, GCC (4.8, 4.9) and Clang (3.5, 3.6) options are available. If you don't specify toolchain it will by default use GCC 4.9.

Refer LINK to know more about app gradle configurations.

Arpan
  • 613
  • 7
  • 18