前言 {#前言}
本文主要讲解,在Android使用NDK所必须的构建工具 --- CMake。
注意:本文是面向Android开发者编写的Cmake基础教程,完全不适用于非Android开发者阅读!
CMake 概述 {#CMake-概述}
CMake 简介 {#CMake-简介}
CMake是个一个开源的跨平台自动化建构系统,用来管理软件建置的程序,并不依赖于某特定编译器,并可支持多层目录、多个应用程序与多个库。 它用配置文件控制建构过程(build process)的方式和Unix的make相似,只是CMake的配置文件取名为CMakeLists.txt。CMake并不直接建构出最终的软件,而是产生标准的建构档(如Unix的Makefile或Windows Visual C++的projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是CMake和SCons等其他类似系统的区别之处。
CMake配置文件(CMakeLists.txt)可设置源代码或目标程序库的路径、产生适配器(wrapper)、还可以用任意的顺序建构可执行文件。CMake支持in-place建构(二进档和源代码在同一个目录树中)和out-of-place建构(二进档在别的目录里),因此可以很容易从同一个源代码目录树中建构出多个二进档。CMake也支持静态与动态程序库的建构。
"CMake"这个名字是"Cross platform Make"的缩写。虽然名字中含有"make",但是CMake和Unix上常见的"make"系统是分开的,而且更为高端。 它可与原生建置环境结合使用,例如:make、ninja、苹果的Xcode与微软的Visual Studio。
初学者需要注意,Cmake并不是只能构建C/C++语言编写的程序,CMake默认支持所有语言。
CMake 的官方网站:https://cmake.org/
CMake 在Android中的作用 {#CMake-在Android中的作用}
Android应用开发时,我们只需要知道,CMake是一个外部构建工具,可与 Gradle 搭配使用来构建原生库即可。
CMake 基础语法 {#CMake-基础语法}
CMake 构建脚本是一个纯文本文件,必须将其命名为 CMakeLists.txt,并在其中包含 CMake 构建 C/C++ 库时需要使用的命令CMakeLists.txt都是由一个个指令组成的。
我们来看一个简单的例子,不需要理解它的含义。
|---------------------|----------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 | project(HELLO) if(TRUE) set(SRC_LIST "main.cpp") add_executable(hello ${SRC_LIST}) endif() |
- project()就是一个指令,而HELLO就是具体的参数。
- 指令不区分大小写。在Android中默认推荐小写。
- 参数与参数之间,用空格 或;分割。
- 引用定义好的变量,使用${}。但是在IF控制语句中直接使用变量名即可。
诸如 while、foreach等语句,在Android开发中不是很常用就不介绍了。
CMake 常用常量 {#CMake-常用常量}
在CMake中系统定义的常量极多,不过大多数都能见名知意,所以这里只介绍一些相对常用的。
- CMAKE_VERSION: 当前CMake使用的版本
- CMAKE_BINARY_DIR / PROJECT_BINARY_DIR: 工程编译发生的路径
- CMAKE_SOURCE_DIR / PROJECT_SOURCE_DIR: 工程的顶层路径
- CMAKE_CURRENT_BINARY_DIR: 工程编译结果存放的路径
- CMAKE_CURRENT_SOURCE_DIR: 当前处理的CMakeLists.txt所在的路径
- CMAKE_PROJECT_NAME: 工程的名字
- CMAKE_CURRENT_LIST_FILE: 当前CMakeLists.txt所在的完整路径
- CMAKE_CURRENT_LIST_LINE: 调用这个变量时,在CMakeList.txt中所在的行数
- CMAKE_ANDROID_ARCH_ABI: 编译的二进制接口(armeabi-v7a、arm64-v8a、x86、x86_64)
Cmake 常用指令 {#Cmake-常用指令}
- 
cmake_minimum_required 
 设定Cmake所需要的最低版本,一般在CMakeLists.txt的开头声明。
 cmake_minimum_required(VERSION 3.18.1)
- 
project 
 设定工程名。
 project("jnidemo")
 该指令还可以配置工程支持的语言,缺省时默认支持所有语言,也是推荐使用的方式。|-------------|-----------------------------------------------------------------------------| | 1 2|project("jnidemo" CXX) # 支持C++ project("jnidemo" C CXX) # 支持C 和 C++|
- 
add_library 
 使用指定的源文件向工程中添加一个共享库,主要有一下几种形式。|---------------|-------------------------------------------------------------| | 1 2 3|add_library(<name> [STATIC | SHARED] [<source>...])|设定共享库的名字。最终编译出的共享库会自动加上lib前缀。例如,如果设定目标库名为jnidemo,最终编译出的目标库的名字会是 libjnidemo。
 [STATIC | SHARED] :设定共享库的类型,STATIC是静态库(libname.a),SHARED是动态库(libname.so)
 [...] :设定源文件。
 使用示例:|---------------|----------------------------------------------------| | 1 2 3|add_library(jnidemo SHARED native-lib.cpp)|一个工程中可以设定添加多个目标库,gradle会自动将这些共享库打包到APK中。 
 add_library还有一些其他的用法,不过在Android开发中不常用,就不介绍了,以免增加入门学习的门槛。
- 
find_library 
 在系统中查找共享库的路径,并赋值给变量。|-----------------|---------------------------------------------------------| | 1 2 3 4|find_library( <Varname> [<path1> <path2> ...] )|变量名。 
 [...] :需要查找的NDK共享库名称。
 使用示例:|---------------|------------------------------------| | 1 2 3|find_library( log-lib log)|查找Android中的log库,并将路径赋值给变量log-lib。 
- 
target_link_libraries 
 将指定的库链接到另一个目标上,这样就可以在目标中调用被链接库的函数。|---------------|----------------------------------------------------------------| | 1 2 3|target_link_libraries( [<name>...] [${<Varname>}...] )|目标库的名字 
 **${}**: 需要链接的共享库
 使用示例:|---------------|----------------------------------------------------| | 1 2 3|target_link_libraries( jnidemo ${log-lib})|该示例中,将log-lib变量对应的库,链接到jnidemo这个目标库中。 
- 
set_target_properties 
 设定目标可以具有影响其构建方式的属性。|---------------|---------------------------------------------------------------------------------------------| | 1 2 3|set_target_properties(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)|
- 
set 
 为一个CMake变量赋值。
 set(SRC log-lib)
 也可以将一个变量设置成多个值|-----------|----------------------------------------------------| | 1|set(SRC_LIST main.cpp test1.cpp test2.cpp)|
- 
message 
 用于在终端向用户输出消息。|-----------|----------------------------------------------------| | 1|message([<mode>] "message to display" ...)|[] : 可选的输出形式(这里介绍几种常用) 
 缺省:信息打印到终端。
 message("message to display")
 WARNING :打印警告信息,但是不中断构建过程。
 message(WARNING "message to display")
 FATAL_ERROR :打印错误信息,终止构建过程。
 message(FATAL_ERROR "message to display")
 SEND_ERROR :打印错误信息,跳过构建过程。
 message(SEND_ERROR "message to display")
- 
include_directories 
 将给定的目录添加到编译器用于搜索包含文件的目录。
 在编写JNI程序导入我们自己编写的头文件时,需要使用include "xxx...h",而不能使用include <xxx.h>,这是因为""是从相对路径查找,而<>是从搜索路径查找。使用include_directories就可以将我们自己编写的头文件导入到搜索路径,这样就可以使用<>导入自定义的头文件。
 include_directories([<path1> <path2> ...])
 使用示例:
 include_directories(${CMAKE_SOURCE_DIR})
- 
add_executable 
 使用指定的源文件将可执行文件添加到项目中。
- 
include 
 从文件或模块加载并运行CMake代码。
 include(${OTHER_DIR}/CMakeLists.txt)
- 
target_include_directories 
 将包含目录添加到目标。|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3|target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])|
- 
add_definitions 
 在源文件的编译中添加-D define标志。
 add_definitions(-DFOO -DBAR ...)
CMake的更多指令以及含义,可以参考官方手册cmake-commands(7) ‒ CMake 3.18.6 Documentation
总结 {#总结}
以上就是CMake的基础教程,CMake本身虽然很复杂但是在Android应用开发中的使用却相对比较简单,一般只需要记住几个常用的指令即可。
参考链接:https://blog.csdn.net/linkwj/article/details/126220118
 51工具盒子
51工具盒子 
                 
                             
                         
                         
                         
                         
                         
                         
                        