Android Gradle使用自定义的CMake

本文约 1100 字,阅读需 3 分钟。

背景

最近重构项目的CMake后,开始了Android平台的适配,踩了些坑,简单记录下。

Cmake版本过低

test

重构后的CMake使用了一些高版本的特性,比如:

但Android内置的CMake只支持到3.22.1:

./cmdline-tools/latest/bin/sdkmanager --list | grep CMake
  .....
  cmake;3.10.2.4988404    | 3.10.2        | CMake 3.10.2.4988404
  cmake;3.18.1            | 3.18.1        | CMake 3.18.1
  cmake;3.22.1            | 3.22.1        | CMake 3.22.1
  cmake;3.6.4111459       | 3.6.4111459   | CMake 3.6.4111459

但是想想,Android用的CMake应该没啥特殊的魔改,官方文档也提到可以自定义:Configure a specific version of CMake

首先要准备好符合目标的CMake:

  • 通过brew update升级cmake,通过cmake --version查看版本
  • 直接从官方下载:Download CMake,然后加入PATH环境变量

有了高版本的CMake之后,具体如何让gradle工程使用自定义的CMake版本,分两种情况

  • 如果是通过命令行触发构建,即sh ./gradlew assembleDebug
    • 此时,Gradle会通过PATH查找目标Version,只要保证命令行的版本(cmake --version)符合要求即可
  • 如果是Android Studio的Run按钮触发构建:
    • 通过local.propertiescmake.dir来配置路径。细节比较多,比如路径不能带引号,是bin/cmake所在目录

此外,build.gradlecmake/version是一定要配置的,保证版本的一致性

Gradle报错

接下来,进入不太好理解的一个错误,如下:

* What went wrong:
Execution failed for task ':app:generateJsonModelDebug'.
> java.lang.NullPointerException (no error message)

看下堆栈也没有灵感:

at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
Caused by: java.lang.NullPointerException
        at com.android.build.gradle.external.cmake.server.ServerProtocolV1.readExpected(ServerProtocolV1.java:519)
        at com.android.build.gradle.external.cmake.server.ServerProtocolV1.readMessage(ServerProtocolV1.java:547)
        at com.android.build.gradle.external.cmake.server.ServerProtocolV1.decodeResponse(ServerProtocolV1.java:404)
        at com.android.build.gradle.external.cmake.server.ServerProtocolV1.decodeResponse(ServerProtocolV1.java:398)
        at com.android.build.gradle.external.cmake.server.ServerProtocolV1.connect(ServerProtocolV1.java:113)

GPT提出一个建议:CMake 服务器协议问题。

那就看下:.cxx/cmake/debug/arm64-v8a/cmake_server_log.txt文件:

CMAKE SERVER: null

于是以cmake server为关键词进行了检索,发现新版本确实不支持:

$cmake -E server --experimental
CMake Error: CMake server mode has been removed in favor of the file-api.

找到文档:

The cmake(1) server mode has been removed since CMake 3.20. Clients should use the cmake-file-api(7) instead. From: https://cmake.org/cmake/help/latest/manual/cmake-server.7.html

目前来看,我们一定要用CMake3.24+,但此时3.20后又没有Server了。既然Gradle支持了3.22.1,说明cmake-file-api肯定是支持了的。

看下当前的版本:

  • Gradle: 6.5
  • GradlePlugin: 4.1.0

按照GPT说的:“CMake File API 的支持从 Android Gradle 插件 4.1.0 开始”。应该不会出现问题,但报错显然是当前Gradle还在尝试CMake Server通信。

GPT比较适合启发思考,这种精确性问题还是自己研究。

于是升级:

  • Gradle: 7.0.2
  • GradlePlugin: 7.0.4

果然可以了!

老工程和新工程的.cxx目录对比:

pic

总结

虽然报错从未见过,但原因就那么些…..

总阅读量次。