1 概念

CMake 是一个开源的跨平台自动化构建系统。官网地址:CMake

2 使用步骤

之前做 NDK 开发或者老的项目都是基于 Android.mk、Application.mk 来构建项目的,但从 AS 2.2 之后便开始采用 CMake 的方式来构建 C/C++ 项目,采用 CMake 相比与之前的 Android.mk、Application.mk 方便简单了许多。“Talk is cheap. Show me the code.”下面我们介绍 CMake 的使用步骤。

2.1 安装 NDK 和 CMake

打开 Android Studio ,博主的软件版本是3.6.3,选择 Tools->SDK Manager->Android SDK->SDK Tools,勾选 NDK 和 CMake,然后点击 OK,如图所示:


此时系统会显示一个对话框,告诉您 NDK 软件包占用了多少磁盘空间。点击 OK,安装完成后,点击 Finish。
除了以上两个组件,调试原生代码还需要一个组件:LLDB。默认情况下,LLDB 是跟随 Android Studio 一起安装的。所以在 SDK Tools 列表中没有找到 LLDB 的同学也不用担心,调试原生代码的时候会出现 LLDB 的控制台。

2.2 新建一个项目



后面就用默认的设置,直到完成。项目创建完成后,如果底部的状态栏窗口弹出这样一个错误:
Caused by: org.gradle.api.InvalidUserDataException: NDK not configured. Download it with SDK manager. Preferred NDK version is ‘20.0.5594570’.
这是由于没有配置 NKD 路径,这时候我们选择File->Project Structure->SDK Location,设置Android NDK location,如图所示:


然后等待编译完成即可。

2.3 项目文件介绍

现在我们已经创建成功一个 CMake 项目,我们来看看项目目录。


这两个文件夹是相比普通项目新增的部分:

  • .cxx :CMake 编译的临时文件,类似于 build 文件夹。
  • cpp :存放 native 代码,包括 .c、.cpp、.h 文件。还有 CMakeLists.txt,CMake 脚本配置的文件。

另外,module 下的 build.gradle 文件也有差异:

  • 上面的 externalNativeBuild 是 CMake 的一些编译参数。
  • 下面的 externalNativeBuild 是 CMakeLists.txt 的路径和 CMake 的版本信息。

2.4 运行

运行代码,就能看到效果,调用了 C++方法在界面上显示了“Hello from C++”。下面我们来分析下执行逻辑。
首先打开 MainActivity.java


这里是在界面的 TextView 调用了 stringFromJNI() 方法设置了一个字符串,该方法是一个 native 声明的方法,所以这个方法会调用 c++ 的函数。我们注意到上面有个静态代码块,当 MainActivity 这个类被加载进内存的时候就执行了该部分代码,这里是 System.loadLibrary(“native-lib”) ,加载一个名为 native-lib 的动态链接库,所以才可以调用里面的 c++ 函数。我们打开 native-lib.cpp


这里有个 Java_com_example_cmakesample_MainActivity_stringFromJNI 函数,返回了一个"Hello from C++"字符串,即 java 代码中调用的 native 方法。我们发现该 native 方法的名字与java方法的名字是一一对应关系,格式为Java_<包名><类名><方法名>(<参数>),这是静态注册的方式,还有另外一种动态注册的方式,详细请见 NDK 开发之 JNI 方法静态注册与动态注册。

3 语法介绍

下面介绍 CMake 的基础语法。

#1. 指定 cmake 的最小版本
cmake_minimum_required(VERSION 3.4.1)#2. 设置项目名称
project(demo)#3. 设置编译类型
add_executable(demo test.cpp) # 生成可执行文件
add_library(common STATIC test.cpp) # 生成静态库
add_library(common SHARED test.cpp) # 生成动态库或共享库#4. 明确指定包含哪些源文件
add_library(demo test.cpp test1.cpp test2.cpp)#5. 自定义搜索规则并加载文件
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(demo ${SRC_LIST}) //加载当前目录下所有的 cpp 文件
## 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
## 或者
aux_source_directory(. SRC_LIST)//搜索当前目录下的所有.cpp文件
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})#6. 用来显式地定义变量,多个变量用空格或分号隔开,引用的时候使用${SRC_LIST}
set(SRC_LIST main.cpp test.cpp)#7. 在列表末尾添加新的对象
list(APPEND SRC_LIST new_test.cpp)#8. 向终端输出用户定义的信息,包含了三种类型:SEND_ERROR,产生错误,生成过程被跳过;
# STATUS,输出前缀为—-的信息;FATAL_ERROR,立即终止所有 CMake 过程
message([SEND_ERROR | STATUS | FATAL_ERROR] “message to display” … )#9. 查找指定库文件
find_library(log-lib //为 log 定义一个变量名称log ) //ndk 下的 log 库#10. 设置包含的目录
include_directories(${CMAKE_CURRENT_SOURCE_DIR}${CMAKE_CURRENT_BINARY_DIR}${CMAKE_CURRENT_SOURCE_DIR}/include
)#11. 设置链接库搜索目录
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs
)#12. 设置 target 需要链接的库
target_link_libraries( # 目标库demo# 目标库需要链接的库# log-lib 是上面 find_library 指定的变量名${log-lib} )#13. 指定链接动态库或者静态库
target_link_libraries(demo libtest.a) # 链接libtest.a
target_link_libraries(demo libtest.so) # 链接libtest.so#14. 根据全路径链接动态静态库
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libtest.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libtest.so)#15. 指定链接多个库
target_link_libraries(demo${CMAKE_CURRENT_SOURCE_DIR}/libs/libtest.atest.aboost_threadpthread)

常用预定义变量

预定义变量 说明
PROJECT_SOURCE_DIR 工程的根目录
PROJECT_BINARY_DIR 运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build
PROJECT_NAME 返回通过 project 命令定义的项目名称
CMAKE_CURRENT_SOURCE_DIR 当前处理的 CMakeLists.txt 所在的路径
CMAKE_CURRENT_BINARY_DIR target 编译目录
CMAKE_CURRENT_LIST_DIR CMakeLists.txt 的完整路径
CMAKE_CURRENT_LIST_LINE 当前所在的行
CMAKE_MODULE_PATH 定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH 重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH 重新定义目标链接库文件的存放位置

官方文档链接,选择最新的 Documentation ->Reference Manuals 中的 cmake-commands(7),就可以看到全部的命令了。

4 安装特定版本的 NDK

要安装特定版本的 NDK,请执行以下操作:
选择 Tools->SDK Manager->Android SDK->SDK Tools,选中 Show Package Details 复选框,选中 NDK (Side by side) 复选框及其下方与您要安装的 NDK 版本对应的复选框。Android Studio 会将所有选中版本的 NDK 安装到 android-sdk/ndk/ 目录中。


如果要安装特定版本的 CMake,方法也是一样的。

NDK 开发之 CMake 的使用相关推荐

  1. AndroidStudio2.2 Preview3中NDK开发之CMake和传统 JNI在目录结构和配置文件上的区别

    自从AndroidStudio更新到2.2,就有了CMake和传统JNI两种开发NDK的方法,主要就是在目录结构和build.gradle上的区别,下面我们将分别介绍目录区别和build.gradle ...

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

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

  3. Android NDK开发之旅31 FFmpeg音频解码

    ###前言 #####基于Android NDK开发之旅30--FFmpeg视频播放这篇文章,我们已经学会视频解码基本过程.这篇文章就对音频解码进行分析. #####音频解码和视频解码的套路基本是一样 ...

  4. Android NDK开发之 NEON基础介绍

    原文:http://blog.csdn.net/app_12062011/article/details/50434259 Android NDK开发之 NEON基础介绍 这是官方介绍: http:/ ...

  5. Android NDK开发之旅25 NDK 模仿QQ变声特效

    ###前言 我们这次用到的是fmod这个库,fmod是音效引擎游戏开发革命引擎,著名的游戏开发引擎CosCos2D.U3D都封装了这个库. 学习NDK的目的就是为了让我们的APP能够使用C/C++开源 ...

  6. NDK 开发之 ndk-build 的使用

    1 概念 ndk-build 本质上是一个脚本,它的位置就在 NDK 目录的最上层,即在< NDK >/ndk-build 路径下.运行 ndk-build 脚本相当于运行以下命令: $G ...

  7. NDK 开发之 JNI 方法静态注册与动态注册

    1 前言 上文说到,进行 NDK 开发的时候,我们首先需要把 Java 方法声明为 native,然后编写对应的 C/C++ 代码,并编译成为动态链接库,在调用 Java 方法前加载动态链接库即可调用 ...

  8. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg

    ###前言 因为在Linux环境下编译FFmpeg生成库和头文件下比较方便,所以接下来主要操作在Linux环境下进行.但是对于Android NDK 开发新手来说,自己电脑配置Ubuntu Linux ...

  9. Android NDK开发之旅1 NDK介绍

    ###一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第三方应用都必须使用Ja ...

  10. Android studio中的NDK开发之NDK环境变量的配置(图文教程)

    为什么总是图文教程? 因为本人对抽象事物联想不到位,更喜欢具体能看到的东西,简单明了,一目了然,更是一步到位!如下图: 第一步找到你通过android studio下载好的NDK目录,如果不知道下载到 ...

最新文章

  1. Android常见面试题(一)
  2. C#发现之旅第九讲 ASP.NET验证码技术
  3. condest--1-范数的条件数估计
  4. 优先级调度算法实现_「kernel」 - 磁盘IO调度算法
  5. 什么镜头最适合拍风景_35mm F1.8定焦镜头,拍人拍风景都可以!
  6. 回型数组 C语言上机题,2014年全国计算机等级二级C语言上机考前预测(含答案)6...
  7. java中spring的注解_Java代码中spring注解浅析
  8. pycharm的安装及破解
  9. linux读取U盘操作
  10. FPGA--IP核之FIFO
  11. 003java面试笔记——【java基础篇】从团八百失败面试总结的java面试题(未完待续)
  12. centos上部署rap2
  13. 2019ICPC徐州 H - Yuuki and a problem (动态(带修)主席树 + 区间Mex问题)
  14. mac pe 制作教程
  15. larval 策略模式
  16. 为什么说继承是把双刃剑
  17. 【码农学编曲】认识五线谱
  18. USNEWS美国大学计算机工程,想从事编程?2019年USNews美国大学计算机工程专业排名值得一看...
  19. Hadoop实战-MR倒排索引(三)
  20. 监听from的submit事件

热门文章

  1. 对涉密计算机检查内容,保密工作检查内容主要有哪些
  2. Bug Algorithms
  3. 调用情迁机器人发送微信或者QQ消息等即时通讯消息
  4. 阿铭Linux_网站维护学习笔记201903015
  5. 在html css中加粗显示,css字体怎么加粗?
  6. 二级mysql刷题_计算机二级通手机版(计算机二级刷题软件)V1.1 简化版
  7. 深度学习 简介 综述
  8. Excel透视表实操,只需6步就能搞定!
  9. 大地坐标系与经纬度转换(一):大地坐标系简介
  10. Silvaco TCAD 2014 Win10下安装说明!