当我们新建了一个NDK项目,打开CMakeLists.txt,会有如下内容,下面对这些命令做了注解
#指定CMake最小支持版本
cmake_minimum_required(VERSION 3.18.1)
#项目名称
project("myndktest")
# 添加一个库,根据native-lib,cpp源文件编译一个native-lib的动态库
add_library(
myndktest #设置库的名称
SHARED #将库设置为动态链接库(即.so文件)
native-lib.cpp) # 源文件的相对路径
# 查找系统库,这里查找的是系统日志库,并赋值给变量lig-lib
# 实际路径:D:\Android\SDK\ndk-bundle\platforms\android-21\arch-arm\usr\lib\liblog.so
find_library(
log-lib #设置名称
log) # 指定在NDK库中的路径
# 设置依赖的库 (第一个参数必须为目标模块,顺序不能换)
target_link_libraries( # Specifies the target library.
myndktest
${log-lib})
指定Cmake最低支持的版本
查找当前目录所有源文件,并将源文件名称列表保存到DIR_SRCS变量,但是不能查找子目录
add_library(<name> [STATIC|SHARED|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
name:设置库的名称
STATIC|SHARED|MODULE:指定库的类型。STATIC:静态库,SHARED:动态库(.so文件),MODULE:在使用dyld的系统有效,若不支持dyld,等同于STATIC
EXCLUDE_FROM_ALL:表示该库不会被默认构建
source1 source2 ... sourceN: 用来指定库的源文件
添加一个已存在的预编译库,名为
一般配合set_target_properties使用
add_library(<name> <STATIC|SHARED|MODULE|UNKNOWN> IMPORTED)
比如
add_library(test SHARED IMPORTED)
set_target_properties(
test #指定目标库名
PROPERTIES IMPORTED_LOCATION #指明要设定的参数
库路径/${ANDROID_ABI}/xxxxx.so #导入库的路径
)
用来设置CMake的变量
# 设置可执行文件的输出路径 (EXECUTABLE_OUTPUT_PATH是全局变量)
set(EXECUTABLE_OUTPUT_PATH [output_path])
# 设置库文件的输出路径 (LIBRARY_OUTPUT_PATH是全局变量)
set(LIBRARY_OUTPUT_PATH [output_path])
# 设置C++编译参数 (CMAKE_CXX_FLAGS是全局变量)
set(CMAKE_CXX_FLAGS "-Wall std=c++11")
# 设置源文件集合 (SOURCE_FILES是本地变量即自定义变量)
set(SOURCE_FILES main.cpp test.cpp ...)
设置头文件目录,相当于g++选项中的-l参数
#可以使用相对或绝对路径,也可以用自定义的变量值
include_directories(./include ${MY_INCLUDE})
添加可执行文件
add_executable(<name> ${SRC_LIST})
将若干库链接到目标库文件
target_link_libraries(<name> lib1 lib2 lib3)
add_definitions(-DFOO -DDEBUG ...)
为当前路径以及子目录的源文件加入由-D引入的define flag,通常用来添加编译参数
如果当前目录下还有子目录时可以用add_subDirectory,子目录中也需要包含有CMakeLists.txt
进行文件操作

set_directory_properties(PROPERTIES prop1 value1 prop2 value2)
设置某个路径的一种属性
prop1、prop2代表属性,取值为
INCLUDE_DIRECTORIES
LINK_DIRECTORIES
INCLUDE_REGULAR_EXPRESSION
ADDITIONAL_MAKE_CLEAN_FILES
在给定的作用域内设置一个命名的属性
如果源文件很多,把所有文件一个个加入很麻烦,可以使用aux_source_directory命令或file命令,查找指定目录下的所有源文件,然后将结果存进指定变量名。
# 查找当前目录所有源文件,并将名称保存到 DIR_SRCS 变量,不能查找子目录
aux_source_directory(. DIR_SRCS)
# 也可以使用
file(GLOB DIR_SRCS *.c *.cpp)
add_library(
myndktest
SHARED
${DIR_SRCS})
主目录中的CMakeLists.txt中添加add_subdirectory(child)命令,指明本项目包含一个子项目child。
并在target_link_libraries指明本项目需要链接一个名为child的库。
aux_source_directory(. DIR_SRCS)
# 添加 child 子目录下的cmakelist
add_subdirectory(child)
add_library(
native-lib
SHARED
${DIR_SRCS}
)
target_link_libraries(native-lib child)
子目录child中创建CMakeLists.txt,这里child编译为动态库
aux_source_directory(. DIR_LIB_SRCS)
add_library(
child
SHARED
${DIR_LIB_SRCS}
)
在Android6.0及以上版本,使用这种方式添加预编译动态库
# set命令定义一个变量
# CMAKE_C_FLAGS : c的参数,会传递给编译器
# 如果是c++文件,需要用CMAKE_CXX_FLAGS
# -L : 库的查找路径
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L[SO所在目录]")
为了确保CMake可以字啊编译时定位头文件,使用include_directories,相当于g++选项中的-l参数。
这样就可以使用#include ,否则需要使用#include "path/xx.h"
# 设置头文件目录
include_directories(<文件目录>)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L[SO所在目录]")
aux_source_directory(. DIR_SRCS)
add_library(
native-lib
SHARED
${DIR_SRCS}
)
target_link_libraries(native-lib imported-lib)
android {
//...
defaultConfig {
//...
externalNativeBuild {
cmake {
//使用的编译器 clang/gcc
//cmake默认就是 gnustl_static arguments "-DANDROID_TOOLCHAIN=clang","-DANDROID_STL=gnustl_static"
//指定cflags和cppflags,效果和cmakelist使用一样
cFlags ""
cppFlags ""
//指定需要编译的CPU架构
abiFilters "armeabi-v7a","arm64-v8a"
}
}
}
externalNativeBuild {
cmake {
//指定CMakeLists.txt文件相较于当前Build.gradle的路径
path file('src/main/cpp/CMakeLists.txt')
//设置CMake版本
version '3.18.1'
}
}
//...
}