使用 CMake 进行Android NDK编译的原理

介绍

Android Studio 2.2 及以后的版本默认使用CMake进行 NDK 编译, 其中最吸引人的地方是,在开发NDK程序时可以进行联机调试,这真是大在的方便了开发者开发NDK程序的效率了。 那么使用CMake编译NDK程序是否与我们之前介绍的使用ndk-build编译有很大的不同呢?下面我们就来一窥它的原理。

前面我给大家介绍了两种交叉编译的方式,没看过的同学可以浏览一下( Linux/Mac 交叉编译 Android 程序 和 深入理解Android NDK编译(一) )

什么是CMake

CMake是个开源的跨平台自动化建构系统,它用配置文件控制建构过程(build process)的方式和Unix的Make相似,只是CMake的配置文件取名为CMakeLists.txt。Cmake并不直接建构出最终的软件,而是产生标准的建构档(如Unix的Makefile或Windows Visual C++的projects/workspaces),然后再依一般的建构方式使用。“CMake”这个名字是"cross platform make"的缩写。虽然名字中含有"make",但是CMake和Unix上常见的“make”系统是分开的,而且更为高级。

Android Studio 如何使用 CMake

其实通过 CMake 进行 NDK 交叉编译的方式与我们之前介绍的两种方式的原理是相同的。 都是要先设定交叉编译各种工具的环境, 包括编译器、链接器等。 然后再通过自动化构建工具进行编译。

Android Studio在执行 CMake build 之前,会将需要的参数存放在 cmake_build_command.txt 文件中,针对每种ABI(arm, mips, x86等)及每种build类型(debug, release),Android Studio都会拷贝一份 cmake_build_command.txt 到//.externalNativeBuild/cmake///目录下。

我们来看一下在 cmake_build_command.txt 里都是些什么内容:

Executable : ~/Library/Android/sdk/cmake/3.6.3155560/bin/cmake
arguments :
-H~/mytest/MyApplication/app
-B~/mytest/MyApplication/app/.externalNativeBuild/cmake/debug/arm64-v8a
-GAndroid Gradle - Ninja
-DANDROID_ABI=arm64-v8a
-DANDROID_NDK=~/Library/Android/sdk/ndk-bundle
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=~/mytest/MyApplication/app/build/intermediates/cmake/debug/obj/arm64-v8a
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_MAKE_PROGRAM=~/Library/Android/sdk/cmake/3.6.3155560/bin/ninja
#下面这个参数特别重要
-DCMAKE_TOOLCHAIN_FILE=~/Library/Android/sdk/ndk-bundle/build/cmake/android.toolchain.cmake
-DANDROID_PLATFORM=android-21
-DCMAKE_CXX_FLAGS=-std=c++11 -frtti -fexceptions
Build Arguments Description
-G < build-system > 一般设置为 “Android Gradle - Ninja” 它指明 CMake 使用 ninja build system 编译并链接C/C++ ,同时 CMake 还会产生android_gradle_build.json 文件,该文件包含了Gradle CMake 插件使用的信息,如编译参数,产生的目标名等。
-DANDROID_ABI < abi > NDK 支持的 ABIs, 如 armeabi,armeabi-v7a,armeabi-v7a with NEON,arm64-v8a等。
-DANDROID_NDK < path > NDK安装路径
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY < path > 输出库的位置
-DCMAKE_BUILD_TYPE < type > build 类型, release 或 debug
-DCMAKE_MAKE_PROGRAM < program-name > 启动 native build 系统的工具
-DCMAKE_TOOLCHAIN_FILE < path > CMake 用于交叉编译 Andriod配置文件的路径。它位于 $NDK/build/cmake/ directory 目录下。
-DANDROID_PLATFORM < level > CMake 编译 Android API 级别

在这些参数里,-DCMAKE_TOOLCHAIN_FILE 这个参数特别重要,因为 Android Stuido 在这个参数指定的文件里设置了交叉编译工具的环境变量,下面我们来大体看一下它流程:

207 ...... 208 # ABI.
209 set(CMAKE_ANDROID_ARCH_ABI ${ANDROID_ABI})
210 if(ANDROID_ABI MATCHES "^armeabi(-v7a)?$")
211         set(ANDROID_SYSROOT_ABI arm)
212         set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi)
213         set(ANDROID_TOOLCHAIN_ROOT ${ANDROID_TOOLCHAIN_NAME})
214         set(ANDROID_HEADER_TRIPLE arm-linux-androideabi)
215         if(ANDROID_ABI STREQUAL armeabi)
216                 set(CMAKE_SYSTEM_PROCESSOR armv5te)
217                 set(ANDROID_LLVM_TRIPLE armv5te-none-linux-androideabi)
218         elseif(ANDROID_ABI STREQUAL armeabi-v7a)
219                 set(CMAKE_SYSTEM_PROCESSOR armv7-a)
220                 set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)
221         endif()
222
223   ......

android.toolchain.cmake 在第 208 行根据 cmake_build_command.txt 文件中ABI的值,设置 ANDROID_SYSROOT_ABI、ANDROID_TOOLCHAIN_NAME、ANDROID_TOOLCHAIN_ROOT等参数。 然后走到 318 行,设置 CMAKE_SYSROOT 值如下:

317  ......318 # Sysroot.
319 if(ANDROID_DEPRECATED_HEADERS)
320         set(CMAKE_SYSROOT
321                 "${ANDROID_NDK}/platforms/${ANDROID_PLATFORM}/arch-${ANDROID_SYSROOT_ABI}")
322 else()
323         set(CMAKE_SYSROOT "${ANDROID_NDK}/sysroot")324 ......

设置完 CMAKE_SYSROOT 走到 355 行,设置ANDROID_TOOLCHAIN_ROOT 和 C/C++ 编译器,代码如下:

354 ......355 # Toolchain.
355 # 首先判断运行的宿主机是什么
356 if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux)
357         set(ANDROID_HOST_TAG linux-x86_64)
358 elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin)
359         set(ANDROID_HOST_TAG darwin-x86_64)
360 elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
361         set(ANDROID_HOST_TAG windows-x86_64)
362 endif()362 # 设置 ANDROID_TOOLCHAIN_ROOT
363 set(ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_ROOT}-4.9/prebuilt/${ANDROID_HOST_TAG}")
364 set(ANDROID_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_NAME}-")
365 ......
368
369 set(ANDROID_HOST_PREBUILTS "${ANDROID_NDK}/prebuilt/${ANDROID_HOST_TAG}")
370 # 如果编译器是 clang
371 if(ANDROID_TOOLCHAIN STREQUAL clang)
372         set(ANDROID_LLVM_TOOLCHAIN_PREFIX "${ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}/bin/")
373         set(ANDROID_C_COMPILER   "${ANDROID_LLVM_TOOLCHAIN_PREFIX}clang${ANDROID_TOOLCHAIN_SUFFIX}")
374         set(ANDROID_CXX_COMPILER "${ANDROID_LLVM_TOOLCHAIN_PREFIX}clang++${ANDROID_TOOLCHAIN_SUFFIX}")
375         set(ANDROID_ASM_COMPILER "${ANDROID_LLVM_TOOLCHAIN_PREFIX}clang${ANDROID_TOOLCHAIN_SUFFIX}")
376         ......
396 # 如果编译器是 gcc
397 elseif(ANDROID_TOOLCHAIN STREQUAL gcc)
398         set(ANDROID_C_COMPILER   "${ANDROID_TOOLCHAIN_PREFIX}gcc${ANDROID_TOOLCHAIN_SUFFIX}")
399         set(ANDROID_CXX_COMPILER "${ANDROID_TOOLCHAIN_PREFIX}g++${ANDROID_TOOLCHAIN_SUFFIX}")
400         set(ANDROID_ASM_COMPILER "${ANDROID_TOOLCHAIN_PREFIX}gcc${ANDROID_TOOLCHAIN_SUFFIX}")

所以通过上面的分析我们可以了解到,Android Studio 通过cmake_build_command.txt指定的 android.toolchain.cmake 文件就把交叉编译的环境设置好了。

CMake NDK 编译过程

当我们在Android Studio中build我们的NDK工程时,AS会通过上面的步骤为我们设置好交叉编译环境,然后再将CMakelists.txt文件传给 CMake, CMake解析里面的内容,并最终调用不同平台的工具,编译出我们需要的目标环境程序。

小结

通过上面的分析,我们知道了 Android Studio 在开发 NDK 程序时,是如何使用 CMake Gradle plugin 设置交叉编译环境的,也基本了解了 CMake 编译 NDK 程序的基本流程。希望本篇文章可以帮助大家理解最新的 Andriod Studio 是如何使用 CMake进行交叉编译的。


csdn地址:http://blog.csdn.net/u012534831
github地址:https://github.com/qht1003077897 \

如有帮助,请多多点赞支持哦。

深入理解使用CMake编译 NDK 程序相关推荐

  1. linux opengl配置编译,Linux下OpenGL的安装与cmake编译OpenGL程序

    Linux下OpenGL的安装与cmake编译OpenGL程序 OpenGL安装 安装命令如下: $ sudo apt install build-essential $ sudo apt insta ...

  2. stm32 vscode 编译_linux 下 VSCODE 使用CMake编译STM32程序

    摘要: M32L0xx_HAL_Driver/Src/stm32l0xx_hal_uart_ex.c.obj[67%]Builttargetstm32l051Scanningdependencieso ...

  3. cmake编译pcl程序时出现‘boost::this_thread::hiden::sleep_until(timespec const)’未定义的引用

    CMakeFiles/main.dir/main.cpp.o:在函数'boost::this_thread::sleep(boost::posix_time::ptime const&)'中: ...

  4. CMake编译Widget UI Qt程序

    自从CMake被引入到KDE项目的编译系统中后,CMake的使用者日益增多,Qt也不例外,除了使用QMAKE编译Qt程序外,也可以使用CMake来编译Qt程序,并且CMake在使用上更灵活,特别是大型 ...

  5. win10子系统linux下cmake编译32位程序

    文章目录 Ubuntu 18运行32位程序 添加软件源 安装编译环境 编写CMakeLists.txt cmake编译 运行程序 SUSE 15.0运行32位程序 m32编译 添加软件源 安装qemu ...

  6. cmake编译build

    基于cmake编译C++程序,书名<视觉SLAM十四讲> 1.环境需求 ubuntu g++ cmake 安装方式: sudo apt install g++/cmake 2.helloS ...

  7. NDK开发之CMake编译构建原生库

    参考地址:https://blog.csdn.net/liu3364575/article/details/80091506                 https://blog.csdn.net ...

  8. CMake 安卓NDK编译常用语法

    目录 CMake 安卓NDK编译常用语法 CMake版本 设置项目名称 平台 32&64 路径相关配置 设置生成动态库文件 常用的编译和链接选项 编译选项 `CMAKE_CCXX_FLAGS_ ...

  9. 今天终于将第一个 Android NDK 程序编译、运行成功

    今天终于将第一个 NDK 程序编译.运行成功. 起先看资料和书籍时,都要求安装 CygWin.我也安装了,并将 Sample: hello-jni 编译成功.编译的 LOG 如下:  LeoZheng ...

最新文章

  1. 看完这篇Exception 和 Error,和面试官扯皮就没问题了
  2. 动态删除nod linux_Linux文件操作实用笔记
  3. url的三个js编码函数escape(),encodeURI(),encodeURIComponent()简介【转】
  4. 如何补救数据中心电缆
  5. c语言 函数指针开销,函数指针是否使程序变慢?
  6. qthread run结束了算销毁吗_Java线程的run()方法和start()方法有什么区别?
  7. 参加博客大赛,多谢大家支持
  8. bzoj 3110: [Zjoi2013]K大数查询(树套树)
  9. ngrok下载并运行实现内网穿透
  10. mysql数据库实操笔记20170418
  11. 中职计算机考证的软件
  12. 人工智能——技术体系
  13. DirectX11:DirectX11下载和环境配置
  14. js根据出生日期计算年龄及根据年龄计算出生日期
  15. c语言源文件经过编译后生成文件的后缀是什么?
  16. 简信CRM:CRM科学服务体系,促进企业销售增长
  17. 【紫书】UVA714 抄书 Copying Books
  18. matlab画动物轮廓图,MATLAB一维插值的应用实例—画左右手的轮廓图
  19. 太原师范学院计算机考研率,太原师范学院怎么样(太原师范学院考研率)
  20. 图像修复模型——TV模型

热门文章

  1. 冠珠瓷砖打造民族文化品牌,让中国陶成为中国潮
  2. 小孩分油问题 (附python代码)
  3. keepalived实现harbor高可用
  4. Spring: ApplicationContext cannot be resolved to a type
  5. 使用 Go 和 Web 技术构建桌面应用程序
  6. UniApp+Vue3.2+ts实现请求API配置
  7. 计算机统考专业课推荐参考书与辅导书
  8. linux日志不支持中文,Nginx日志不支持中文解决方法
  9. Python flappy bird 小游戏
  10. mySQL主表与子表一对多关系,left join关联查询子表中其中一条记录