提问人:DoDo 提问时间:6/5/2023 最后编辑:DoDo 更新时间:6/7/2023 访问量:288
如何修改 Android build.gradle 中 ':app:configureCMakeDebug[arm64-v8a]' 和类似任务的依赖关系?
How to modify dependencies of `:app:configureCMakeDebug[arm64-v8a]` and similar tasks in Android's build.gradle?
问:
我正在尝试集成柯南包管理器,为我的 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 安装任务是执行的,但并行执行或在任务之后执行。clean
configureCMakeDebug[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...
答: 暂无答案
评论