1. 如何设置编译器的版本:
# 设置指定的C++编译器版本是必须的,如果不设置,或者为OFF,则指定版本不可用时,会使用上一版本。
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 指定为C++17 版本
set(CMAKE_CXX_STANDARD 17)
  1. cmake的IF()语句中,变量可以不用${},直接写变量名即可;
  2. 设定工程名称时会自动设置好两个环境变量:
# 设定工程名称为projectname ,后面可以跟工程的语言环境
PROJECT(projectname [CXX] [C] [Java])

# PROJECT_BINARY_DIR为最终二进制文件的位置,如果建立了build目录并在build目录里面执行cmake ..,则就是这个build目录里面
message(STATUS PROJECT_BINARY_DIR) 

# PROJECT_SOURCE_DIR为项目目录,即使建立了build目录并在build目录里面执行cmake ..,仍然表示build上一层的目录
message(STATUS PROJECT_SOURCE_DIR)
  1. 使用set将最终编译的二进制结果输出到指定位置:
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

这两个命令一般放在ADD_EXECUTABLE或者ADD_LIBRARY命令的位置;

  1. 关于cmake中安装位置(INSTALL),详见:
  2. 如何同时构建动态库和静态库:
# 首先使用不同的target名称创建动态库和静态库
add_library(hello SHARED hello.cpp)
add_library(hello_static STATIC hello.cpp)

# 然后使用set_target_properties()来重命名
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")

这样就可以同时得到libhello.so以及libhello.a两个库了
另外,还可以使用此命令添加动态库版本号:

# VERSION指代动态库版本,SOVERSION指代API版本
set_target_properties(hello PROPERTIES VERION 1.2 SOVERSION 1)
  1. 添加头文件路径的时候,可以选择添加的头文件路径是放在已有的头文件搜索路径的前面还是后面:
include_directories(BEFORE xxx)
include_directories(AFTER xxx)
# 或者用这个:
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
  1. 链接共享库方式:
# 添加将要搜索的共享库的目录
link_directories([AFTER|BEFORE] dir1 dir2)

# 将需要的库链接到target上,可以指定每个链接的库是debug还是optimized
target_link_libraries(target library1 <debug | optimized> library2...)

link_directories支持绝对路径和相对路径(相对路径的前缀是变量CMAKE_CURRENT_SOURCE_DIR,也就是当前CMakeLists.txt所在)。如果有其他选择,应该尽量避免link_directories,实在无法避免使用绝对路径增加工程的可移植性。绝对路径可以配合find_library()+target_link_libraries()

  1. CMAKE_INCLUDE_PATH以及CMAKE_LIBRARY_PATH是两个环境变量,可以使用export来指定需要查找的默认查找路径,然后在cmake中就可以直接使用find_path以及find_library来获取头文件路径或者库文件路径了;
  2. cmake常用变量:
# 这三个变量都是一样的,如果是内部编译则指的是工程顶层目录,如果是外部编译则指的是工程编译发生的目录
CMAKE_BINARY_DIR
PROJECT_BINARY_DIR
<projectname>_BINARY_DIR

# 这三个变量的内容是一致的,不论采用何种编译方式,都是工程顶层目录
CMAKE_SOURCE_DIR
PROJECT_SOURCE_DIR
<projectname>_SOURCE_DIR

# 指的是当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_SOURCE_DIR

# 指的是当前CMakeLists.txt所生成的二进制文件的所在的目录
CMAKE_CURRENT_BINARY_DIR

# 输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_FILE

# 输出这个变量所在的行
CMAKE_CURRENT_LIST_LINE

# 指定cmake最终输出的二进制文件的目录(不包括中间文件),只针对当前CMakeLists.txt所生成的目标文件有效
set(EXECUTABLE_OUTPUT_PATH dir)
set(LIBRARY_OUTPUT_PATH dir)

# 通过project()指定的名称
PROJECT_NAME

# 不包含版本的系统名
CAMKE_SYSTEM_NAME

# 如果是linux系统在,则为TRUE
UNIX

# 如果是windows系统,则为TRUE
WIN32
  1. cmake调用环境变量:
# 使用 $ENV{NAME}调用环境变量	
MESSAGE(STATUS "HOME dir: $ENV{HOME}")

# 使用 set(ENV{变量名} 值)设置环境变量
  1. 一些cmake基本指令:
# 给编译器添加-D宏
add_definitions(-Dxxxx)

# 定义target依赖的其他的target,确保在编译本target之前,其他的target已经被构建
add_dependencies(target_name depend1 depend2)
  1. cmake中执行其他命令:
# execute_process是exec_program更强大的版本,exec_program只能执行一条指令,而execute_process可以顺序执行多条指令
# 且前一个指令的输出可以作为后一个指令的输入,命令作为管道并发执行,每个进程的标准输出通过管道传输到下一个进程的标准输入
exec_program(exe_file [run_dir] [ARGS args] [OUTPUT_VARIABLE <var>] [RETURN_VALUE <var>])
execute_process(COMMAND <cmd1> [<arguments>] [COMMAND <cmd2> [<arguments>]]... [WORKING_DIRECTORY <directory>] .........)

exec_program(ls ARGS "-la")
execute_process(COMMAND ls "-la")
  1. cmake中文件按条件查找:
file(GLOB .......) # 按照正则要求查找匹配文件
file(GLOB_RECURSE ........) # 递归查找
  1. cmake中一些文件操作指令:
# 文件重命名
file (RENAME <oldname> <newname>)

# 删除文件或目录
file(RENAME_RECURES [<files> ...])

# 创建目录
file(MAKE_DIRECTORY [<directories> ...])

# 将文件copy到目标目录中
file(COPY <files> ... DESTINATION <dir> ......) # 不显示详细拷贝信息
file(INSTALL <file> DESTINATION <dir> ......) # 会显示详细拷贝信息

# 根据指定的<file>文件推断出该文件相对于<directory>目录的相对路径,并保存到<variable>变量中,其中<file>要带绝对路径
file(RELATIVE_PATH <variable> <directory> <file>)

# 用于将路径格式转成统一的linux格式(windows,linux格式不一致,用于统一的)
file(TO_CMAKE_PATH "<path>" <variable>)

# 用于将路径格式转成各自平台的路径格式
file(TO_NATIVE_PATH "<path>" <variable>)

# 下载,上传
file(DOWNLOAD <url> <file> [<option> ...])
file(UPLOAD <file> <url> [<option> ...])
  1. cmake中列表list的操作:
list(LENGTH ......) # 获取列表长度
list(GET ......) # 获取某个位置元素
list(APPEND ......) # 追加一个元素
list(FILTER ......) # 过滤清理
list(FIND ......) # 查找
list(INSERT ......) # 插入

# 删除
list(REMOVE_ITEM ......)
list(REMOVE_AT ......) 
list(REMOVE_DUPLICATES ......)

list(REVERSE ......) # 反转元素
list(SORT ......) # 排序元素
  1. cmake foreach用法:
# 从0到3(0 1 2 3),其中3是终止的意思
foreach(n RANGE 3)
......
endforeach()

# [0 2 4 6 8 10] 0是开始,10是结束,2是step
foreach(n RANGE 0 10 2)
......
endforeach()

set(W a b c)
foreach(n IN_LISTS W)
......
endforeach()

set(A 1 2 3)
set(B 2 3 4)
set(C 3 4 5)
foreach(n IN_LISTS A B C)
......
endforeach()

......
  1. cmake自定义target:
    默认生成的target(如add_library()或者add_executable()生成的这些target)都是存储在all target中的,也就是说只要执行make,就会生成这些target,但是使用add_custom_target()生成的target一般不在all target中,单独执行make并不会生成,需要make abc这样才能生成这样的target:
# 自定义一个target:abc,执行make abc的时候,会执行后面的命令,即 touch abc.txt
# 注意,后面的命令,命令和参数是分开的
add_custom_target(abc COMMAND "touch" "abc.txt")

# 定义一个ls的target,执行make ls的时候,由于添加了DEPENDS,这个ls的target会依赖于abc,
# 也就是说它会先生成abc这个target(此时会自动执行),然后才会生成ls这个target并执行后面的ls命令
add_custom_target(ls COMMAND "ls" "./" DEPENDS abc)

# 另外,也可以使用add_dependencies()来给两个顶层target添加依赖关系
add_dependencies(target depend_target)

# 此处加了ALL,表示cp这个target会放到all target中,也就是说直接执行make时,就会类似于add_library()生成
# 的那些target类似,直接生成,而不需要单独make cp,只需要make即可
# 注意,此处后面的命令每个参数都单独的,不能放在一个双引号里面
add_custom_target(cp ALL COMMAND "cp" "abc.txt" "math/" DEPENDS ls)

# 一个target可以同时执行多个命令
add_custom_target(my_target 
				  COMMAND .....
				  COMMAND .....
				  COMMAND .....)