在 ndk{} DSL 中定义 LOCAL_SRC_FILES [英] define LOCAL_SRC_FILES in ndk{} DSL

查看:26
本文介绍了在 ndk{} DSL 中定义 LOCAL_SRC_FILES的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to know whether it is possible to define LOCAL_SRC_FILES in gradle.build ndk {} block.

我目前正在使用:

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

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

in my top level gradle.build file.

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

My jni module gradle.build file looks like this:

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.

The reason I am asking is that under my jni sources there is code targeting different platforms, not just Android, but also iOS and WinRT.

我有点不愿意迁移到实验性的com.android.tools.build:gradle-experimental:0.2.0",但如果上述模块解决了问题,我可以试一试.

I am a bit reluctant to migrate to experimental 'com.android.tools.build:gradle-experimental:0.2.0' but if the aforementioned module solves the problem I could give it a try.

我也不想使用:

jni.srcDirs = []

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

and override the creation of Android.mk and thus use my own custom one, given that I am not sure if I could debug C++ natively from Android Studio thereafter (I could be wrong here though, I am definitely not an expert user of Android Studios ndk plugin).

非常感谢,

马诺斯

推荐答案

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

With experimental plugin 0.4.0, it is possible to exclude files from NDK build by pattern, e.g.

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

感谢 Paul Spark

PS(感谢 rajveer):不要'更改exclude后不要错过Build/Clean

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

Unfortunately this is not supported by current gradle plugins. Even the "experimental" plugin only allows to add directories. I recommend to keep the traditional Android.mk which does this job reliably.

我也建议不要设置jni.srcDirs = [],而是保留${jniSrc} 让Android Studio 显示这些文件以便于访问和语法高亮.如果您正确设置 cppFlagscFlags,您也将拥有通过标题进行交叉引用的全部功能.

I also recommend not to set jni.srcDirs = [], but rather keep ${jniSrc} to let Android Studio display these files for easy access and syntax highlight. If you set cppFlags and cFlags correctly, you will have full power of cross referencing through headers, too.

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

The trick is to disable the regular NDK build tasks, and inject a buildNative task instead:

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',但任务匹配不同:

Similar approach work for 'com.android.tools.build:gradle-experimental:0.2.0', but task matching is different:

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 会抱怨它找不到包含模块应用程序中带有符号的目标文件的文件夹.

UPDATE

buildNative does not produce a debuggable setup. Specifically, when running Android Native debug configuration, Android Studio complains that it Could not locate folder containing object files with symbols within module app.

我建议采用以下解决方法,我仅在将本机源分成(至少)两个目录的情况下进行测试:Android 特定文件(我将它们称为 JNI 桥)是在一个单独的目录中,其余的在别处.解决方法包括使用 ndk-build 构建一个静态库,并将其与将从该库中提取所有必要符号的最少对象集链接起来.

I suggest the following workaround, which I only tested in scenario when the native sources are split in (at least) two directories: the Android-specific files (I will call them JNI bridge) are in a separate directory, and the rest are elsewhere. The workaround involves building a static library with ndk-build and linking it with the minimal set of objects that will pull all necessary symbols from that library.

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

For simplicity, let us assume that the Android-specific files (Application.mk, Android.mk, and "android-jni.cpp" are in the directory ~/srcs/jni, while the platform-independent files are in ~/srcs and its other subdirectories.

这是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)

LOCAL_MODULEAndroid.mk 中适合您用于 LOCAL_MODULEbuild.gradle 中.

It is important for LOCAL_MODULE in Android.mk to fit the name you use for LOCAL_MODULE in build.gradle.

由于 jforce,这仍然是可能的,请参阅将单个本机源文件链接到 Android Studio 项目"!

这篇关于在 ndk{} DSL 中定义 LOCAL_SRC_FILES的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆