一、CMake 介绍

CMake是一个跨平台的安装/编译工具,通过CMake我们可以通过简单的语句来描述所有平台的安装/编译过程。它能输出各种makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件。

CMake的所有语句都写在一个CMakeLists.txt文件中,CMakeLists.txt 文件编写完成后,直接使用CMake命令进行运行即可 ,但是需要这个命令需要指向CMakeLists.txt 所在的目录。在AndroidStudio中,IDE会帮我们执行命令,我们可以暂时不需要了解CMake和CmakeList.txt之间的关系,但是我们需要了解如何编写CmakeList.txt 来配置我们的项目,以保证相关的库能正常的加载和运行。

二、CMakeLists 指令

在讲CMakeLists相关指令之前,可以看一下常见的CMakeLists.txt文件的内容,下面是使用CameraX+Rtmp开发推流功能的时候,创建的CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.4.1)
set(rtmp_lib_src_DIR ${PROJECT_SOURCE_DIR}/src/main/cpp)
add_subdirectory(${rtmp_lib_src_DIR}/librtmp)
include_directories(
${CMAKE_SOURCE_DIR}/src/main/cpp/include
)
# build application's shared lib
# For Java Call,the file of C/C++ Use UpperCase Name Space
add_library(rtmp-push-lib SHARED
${CMAKE_SOURCE_DIR}/src/main/cpp/RtmpPushLib.cpp
...other cpps
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log
)
set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS} -L${rtmp_lib_src_DIR}/libs/${ANDROID_ABI}")
# Include libraries needed for MediaEditor lib
target_link_libraries(rtmp-push-lib
rtmp
x264
android
log
${log-lib}
)

下面我们根据上面的配置文件,来逐步讲解各个指令的使用方式和意义:

1. cmake_minimum_required(VERSION 3.4.1) 指令

此指令的作用就是规定cmake程序的最低版本,属于可选的指令,但是一般情况下都会添加这个指令。如果CMakeLists.txt中使用了一些高版本cmake特有的命令的时候,是必须要加上的,这样能够提醒使用者升级到该版本之后再执行camke。

2. set 指令

set指令用于显式的定义变量。使用方式为set(var [value] [cache type docstring] [force]). 其中定义时必须填写的参数为:var 和 value。

3. add_subdirectory 指令

用于添加需要编译的源文件的子目录;语法为:add_subdirectory(source_dir [binary_dir][exclude_from_dir])。其中source_dir:向当前工程添加存放源文件的子目录,[binary_dir]:指定目标文件存放的位置,[exclude_from_dir]:将该目录从编译过程中排除。

注意:子目录也需要有CmakeLists.txt文件,以保证子目录下的源文件能够正常编译。

4. add_library 指令

add_library():用于将一组源文件编译生成一个库文件,并保存为 libname.so (lib 前缀是生成文件时 CMake自动添加上去的)。可传入多个源文件,其语法为:add_library(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] [source])。

其中生成的有三种库文件类型,不写的话,默认为 STATIC。下面我们简单的讲解一下生成的库文件类型:

SHARED:表示生成的为动态库,可以在Java代码中使用System.loadLibaray(name)进行动态调用。

STATIC:表示生成的为静态库,集成到代码的时候,会在编译时调用。

MODULE:只有在dyld的系统有效,如果不支持dyld,则会被当作SHARED对待。

5. find_library 指令

这个指令是Android NDK开发提供的特有的Cmake指令,用于添加NDK API。语法为:find_library( name1 path1 path2 ...)。例如上面的CMakeList.txt文件中,我们就添加了日志支持的API。

6. target_link_libraries 指令

target_link_libraries 指令用来为 target 添加需要链接的共享库,同样也可以用于为自己编写的共享库添加共享库链接。语法为:target_link_libraries(target library library2…)