在ndk {} DSL中定义LOCAL_SRC_FILES

时间:2015-09-17 17:09:27

标签: android c++ android-ndk android-gradle

我想知道是否可以在gradle.build ndk {}块中定义LOCAL_SRC_FILES。

我目前正在使用:

dependencies {
    classpath 'com.android.tools.build:gradle:1.3.0'
}

在我的顶级gradle.build文件中。

我的jni模块gradle.build文件如下所示:

apply plugin: 'com.android.library'

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
}

android {
    compileSdkVersion 11
    buildToolsVersion "22.0.1"

    def jniSrc = System.getProperty("user.home") + "/srcs/jni"

    defaultConfig {
        ndk {
            moduleName "core"
            stl "gnustl_shared"
            cFlags "-std=c++11"
        }
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
            jniLibs.srcDirs = ['libs']
            jni.srcDirs = ["${jniSrc}"]
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            jniDebuggable true
        }
    }

    productFlavors {
        x86 {
            ndk {
                abiFilter "x86"
            }
        }
        arm {
            ndk {
                abiFilter "armeabi-v7a"
            }
        }
        mips {
            ndk {
                abiFilter "mips"
            }
        }
    }
}

我之所以要问的是,在我的jni源代码下,有针对不同平台的代码,不仅仅是Android,还有iOS和WinRT。

我有点不愿意迁移到实验性的com.android.tools.build:gradle-experimental:0.2.0'但如果前面提到的模块解决了这个问题,我可以尝试一下。

我也不想使用:

jni.srcDirs = []

并覆盖Android.mk的创建,因此使用我自己的自定义,因为我不确定我是否可以从Android Studio本地调试C ++(虽然我可能错了,但我绝对不是专家用户Android Studios ndk插件)。

非常感谢,

马诺斯

1 个答案:

答案 0 :(得分:11)

使用实验插件0.4.0,可以通过模式从NDK构建中排除文件,例如

android.sources {
    main {
       jni.source {
            srcDirs = ["~/srcs/jni"]
            exclude "**/win.cpp"
        }
    }
}

感谢Paul Spark

P.S。(感谢rajveer):更改Build/Clean后不要错过exclude

旧答案

不幸的是,当前的gradle插件不支持此功能。即使“experimental”插件也只允许添加目录。我建议保留传统的 Android.mk ,以便可靠地完成这项工作。

我还建议不要设置jni.srcDirs = [],而是保留${jniSrc}让Android Studio显示这些文件,以便于访问和语法突出显示。如果您正确设置 cppFlags cFlags ,您也可以完全通过标头进行交叉引用。

诀窍是禁用常规NDK构建任务,并注入buildNative任务:

def ndkBuild = android.ndkDirectory
import org.apache.tools.ant.taskdefs.condition.Os
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
    ndkBuild += '.cmd'
}

task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
    commandLine '$ndkBuild', 'NDK_PROJECT_PATH="$jniSrc/..'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
    commandLine '$ndkBuild', 'clean', 'NDK_PROJECT_PATH="$jniSrc/..'
}

clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn buildNative
}

tasks.all {
    task -> if (task.name.contains('compileDebugNdk') || task.name.contains('compileReleaseNdk')) task.enabled = false
}

类似方法适用于 'com.android.tools.build:gradle-experimental:0.2.0' ,但任务匹配不同:

tasks.all {
    task ->
        if (task.name.startsWith('compile') && task.name.contains('MainC')) {
            task.enabled = false
        }
        if (task.name.startsWith('link')) {
            task.enabled = false
        }
        if (task.name.endsWith("SharedLibrary") ) {
            task.dependsOn buildNative
        }
}

更新

buildNative 不会产生可调试的设置。具体来说,在运行 Android Native 调试配置时,Android Studio会抱怨找不到包含模块应用中符号的对象文件的文件夹。

我建议采用以下解决方法,我只测试了本地源在(至少)两个目录中拆分的情况:特定于Android的文件(我将其称为 JNI bridge )在一个单独的目录中,其余的在其他地方。解决方法涉及使用 ndk-build 构建静态库,并将其与最小的对象集链接,从而从该库中提取所有必需的符号。

为简单起见,我们假设特定于Android的文件( Application.mk Android.mk 和“android-jni.cpp”)位于目录中~/srcs/jni,而与平台无关的文件位于~/srcs及其他子目录中。

以下是 build.gradle 的相关片段:

def LOCAL_MODULE = "staticLib"
def appAbi = "armeabi-v7a"
def ndkOut = "build/intermediates/$LOCAL_MODULE"
def staticLibPath = "$ndkOut/local/$appAbi/lib${LOCAL_MODULE}.a"
task buildStaticLib(type: Exec, description: 'Compile Static lib via NDK') {
    commandLine "$ndkBuild", "$staticLibPath", "NDK_PROJECT_PATH=~/srcs", "NDK_OUT=$ndkOut", "APP_ABI=$appAbi", "APP_STL=gnustl_static"
}

tasks.all {
    task ->
        if (task.name.startsWith('link')) {
            task.dependsOn buildStaticLib
        }
}

model {
    android.ndk {
        moduleName = "hello-jni"
        abiFilters += "$appAbi".toString()
        ldFlags += "$staticLib".toString()
        ldLibs += "log"
        cppFlags += "-std=c++11"
    }

    android.sources {
        main.jni.source {
            srcDirs = ["~/srcs/jni"]
        }
}
}

〜/ srcs / Android.mk 文件可能如下所示:

LOCAL_PATH := $(call my-dir)/..

include $(CLEAR_VARS)

LOCAL_MODULE    := staticLib
LOCAL_SRC_FILES := HelloJni.cpp

LOCAL_CPPFLAGS += -std=c++11

include $(BUILD_STATIC_LIBRARY)

Android.mk LOCAL_MODULE 对于 LOCAL_MODULE 所使用的名称非常重要的的build.gradle

更新2

有可能,感谢 jforce ,请参阅“Link individual native source file to Android Studio project”!