如何修改 Android build.gradle 中 ':app:configureCMakeDebug[arm64-v8a]' 和类似任务的依赖关系?

How to modify dependencies of `:app:configureCMakeDebug[arm64-v8a]` and similar tasks in Android's build.gradle?

提问人:DoDo 提问时间:6/5/2023 最后编辑:DoDo 更新时间:6/7/2023 访问量:288

问:

我正在尝试集成柯南包管理器,为我的 Android 应用程序安装 C++ 依赖项。我首先遵循了柯南的官方教程,它有效。但是,官方示例中的任务始终运行,并且永远不会是最新的。这是有问题的,因为每次运行此任务时,它都会重新生成 cmake 依赖文件,使 cmake 重新运行并且需要重新编译所有代码。这大大增加了编辑-构建-调试周期。

因此,我正在尝试制作一个更复杂的 gradle 任务,该任务将知道 conan 安装何时是最新的,从而避免每次运行应用程序时都重新运行 cmake。

这是我想出的:

apply plugin: 'com.android.application'

// https://stackoverflow.com/a/69099942/213057
tasks.register("prepareKotlinBuildScriptModel"){}

abstract class ConanInstallTask extends DefaultTask {
    @Internal
    String buildType;

    @Internal
    String abi;

    @TaskAction
    void conanInstall() {
        def buildDir = new File("app")
        buildDir.mkdirs()
        def cmd = ['conan', 'install', '/path/to/conanfile/folder/', '-of', '.',
                    "--profile:host", "android-ndk-r25c-" + abi,
                    "--profile:build", "macos-xcode-universal-clang-14.0.3",
                   "--settings", "build_type=" + buildType,
                   "--build", "missing",
                   "-c", "tools.cmake.cmake_layout:build_folder_vars=['settings.arch']",
                   "-c", "tools.cmake.cmaketoolchain:generator=Ninja"]
        print(">> ${cmd} \n")

        def sout = new StringBuilder(), serr = new StringBuilder()
        def proc = cmd.execute(null, buildDir)
        proc.consumeProcessOutput(sout, serr)
        proc.waitFor()
        println "$sout $serr"
        if (proc.exitValue() != 0) {
            throw new Exception("out> $sout err> $serr" + "\nCommand: ${cmd}")
        }
    }
}

android {
    // the usual cmake-based android NDK project
}

dependencies {
    // also as usual
}

android.applicationVariants.all { variant ->
    def buildType = variant.buildType.name
    android.defaultConfig.externalNativeBuild.cmake.abiFilters.each { abi ->
        def conanInstallTask = project.tasks.create( "conanInstall${abi.capitalize()}${buildType.capitalize()}", ConanInstallTask)
        conanInstallTask.buildType = buildType.capitalize()
        conanInstallTask.abi = abi
        conanInstallTask.inputs.file '/path/to/conanfile/folder/conanfile.py'
        // note: https://discuss.gradle.org/t/unexpected-up-to-date-task-while-output-file-is-missing/5216/2
        conanInstallTask.outputs.upToDateWhen {
            def arch = {
                switch( abi ) {
                    case 'arm64-v8a': return 'armv8'
                    case 'armeabi-v7a': return 'armv7'
                    default: return abi
                }
            }()
            file( "build/${arch}/${buildType.capitalize()}/generators/conan_toolchain.cmake" ).exists()
        }

        // how to make configureCMake${buildType}[${abi}] depend on conanInstallTask?
        variant.externalNativeBuildProviders[0].get().dependsOn conanInstallTask
        // needed for Android Studio code model to be aware of conan
        project.tasks.findByName('prepareKotlinBuildScriptModel').dependsOn( conanInstallTask )
    }
}

上面的代码段可以正常工作,直到我点击 Android Studio。然后,下一个构建会失败,因为 和类似的构建会失败,因为它们找不到 conan 安装任务应该生成的文件。conan 安装任务是执行的,但并行执行或在任务之后执行。cleanconfigureCMakeDebug[arm64-v8a]configureCMake...

如何使用 Android Gradle 插件 v8 的 API 使任务依赖于我新添加的任务?configureCMake...

从上面的代码片段中可以看出,它不是指 cmake configure 任务 - 它指的是实际的代码构建任务,它发生得“太晚”了。variant.externalNativeBuildProviders[0].get()

我也尝试过按名称查找任务,但这不起作用(见下文):

// doesn't work - NullPointerException on gradle sync
project.tasks.findByName(":app:configureCMake${buildType.capitalize()}[${abi}]").dependsOn( conanInstallTask ) 

// also doesn't work, gradle sync passes, but throws NPE on app run (app build, however, does work)
project.tasks.findByName("configureCMake${buildType.capitalize()}[${abi}]").dependsOn( conanInstallTask )

// also doesn't work, gradle sync passes, but throws NPE on app run (app build, however, does work)
project.tasks.findByPath(":app:configureCMake${buildType.capitalize()}[${abi}]").dependsOn( conanInstallTask)

编辑:

出于某种奇怪的原因,这似乎可以正常工作,尽管我没有任何解释原因:


def cmakeConfigureTask = project.tasks.findByPath(":app:configureCMake${buildType.capitalize()}[${abi}]") 
// or def cmakeConfigureTask = project.tasks.findByName("configureCMake${buildType.capitalize()}[${abi}]")
if ( cmakeConfigureTask != null ) {
    cmakeConfigureTask.dependsOn(conanInstallTask)
}

似乎有时存在,有时不存在 🤷 ♂️:app:configureCMake...

安卓 android-ndk android-gradle-plugin 柯南

评论


答: 暂无答案