Android Gradle使用自定义的CMake
背景
最近重构项目的CMake后,开始了Android平台的适配,踩了些坑,简单记录下。
Cmake版本过低
重构后的CMake使用了一些高版本的特性,比如:
CMP0135
: New in version 3.24. -> https://cmake.org/cmake/help/latest/policy/CMP0135.htmlFILE_SET <set-name>
: New in version 3.23 -> https://cmake.org/cmake/help/latest/command/install.html
但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
)符合要求即可
- 此时,Gradle会通过PATH查找目标Version,只要保证命令行的版本(
- 如果是Android Studio的
Run
按钮触发构建:- 通过
local.properties
的cmake.dir
来配置路径。细节比较多,比如路径不能带引号,是bin/cmake所在目录
- 通过
此外,build.gradle
的cmake/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
目录对比:
总结
虽然报错从未见过,但原因就那么些…..