Cmake Notes

本文记录cmake相关的笔记

基础

一个最简单的cmake示例

1
2
3
4
5
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is Binary dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

PROJECT的指令语法

1
PROJECT(projectname [CXX] [C] [Java])

上指令隐式的定义了两个cmake变量:<projectname>_BINARY_DIR,<projectname>_SOURCE_DIR,同时还预定义了变量PROJECT_BINARY_DIR, PROJECT_SOURCE-DIR(等价于之前两个变量)。

SET指令语法:

1
SET (VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

例子: SET (SRC_LIST main.cpp t1.cpp t2.cpp)

用于显式的定义变量,引用变量可使用${}。但是在IF控制语句中是直接使用变量名。参数之间可以使用分号或空格来进行分割

MESSAGE指令的语法

1
MESSAGE ([SEND_ERROR | STATUS | FATAL_ERROR] "message to display" ...)

用于向终端输出用户定义的信息

ADD_EXECUTABLE(hello ${SRC_LIST})

定义了这个工程会生成一个文件名为hello的可执行文件

ADD_SUBDIRECTORY指令的语法

1
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置。

例子: ADD_SUBDIRECTORY(src bin)将src子目录加入工程,并指定编译输出路径为bin目录

条件控制命令为 if命令:

1
2
3
4
5
6
7
if(expression)
     # ...
   elseif(expression2)
     # ...
   else()
     # ...
   endif()

循环控制示例:

1
2
3
4
5
6
7
8
9
foreach 循环范例:

set(VAR ab c)

foreach(f${VAR})

   message(${f})

endforeach()

while 循环范例:

1
2
3
4
5
6
7
8
9
set(VAR5)

while(${VAR}GREATER 0)

   message(${VAR})

   math(EXPR VAR "${VAR} - 1")

endwhile()

aux_source_directory命令

命令语法:aux_source_directory(<dir><variable>) 命令简述:用于将 dir 目录下的所有源文件的名字保存在变量variable中 使用范例:aux_source_directory(. DIR_SRCS)

add_executable命令

命令语法:add_executable(<name> [WIN32][MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN) 命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个可执行文件且命名为 name 使用范例:add_executable(Main ${DIR_SRCS})

add_library命令

命令语法:add_library([STATIC | SHARED |MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN) 命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为 name 使用范例:add_library(one STATIC two.cpp three.h)

add_dependencies命令

命令语法:add_dependencies(target-namedepend-target1 depend-target2 …) 命令简述:用于指定某个目标(可执行文件或者库文件)依赖于其他的目标。这里的目标必须是add_executable、add_library、add_custom_target命令创建的目标

add_subdirectory命令

命令语法:add_subdirectory(source_dir[binary_dir] [EXCLUDE_FROM_ALL]) 命令简述:用于添加一个需要进行构建的子目录 使用范例:add_subdirectory(Lib)

target_link_libraries命令

命令语法:target_link_libraries([item1 [item2 […]]] [[debug|optimized|general] ] …) 命令简述:用于指定 target 需要链接 item1item2 …。这里 target必须已经被创建,链接的item可以是已经存在的 target(依赖关系会自动添加) 使用范例:target_link_libraries(Main Lib)

set命令

命令语法:set( [[CACHE [FORCE]] | PARENT_SCOPE]) 命令简述:用于设定变量 variable 的值为 value。如果指定了 CACHE变量将被放入 Cache(缓存)中。 使用范例:set(ProjectName Main)

unset命令

命令语法:unset([CACHE]) 命令简述:用于移除变量 variable。如果指定了CACHE变量将被从 Cache中移除。 使用范例:unset(VAR CACHE)

message命令

命令语法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]“message to display” …) 命令简述:用于输出信息 使用范例:message(“Hello World”)

include_directories命令

命令语法:include_directories([AFTER|BEFORE][SYSTEM] dir1 dir2 …) 命令简述:用于设定目录,这些设定的目录将被编译器用来查找 include 文件 使用范例:include_directories(${PROJECT_SOURCE_DIR}/lib)

find_path命令

命令语法:find_path(name1 [path1 path2 …]) 命令简述:用于查找包含文件 name1 的路径,如果找到则将路径保存在 VAR中(此路径为一个绝对路径),如果没有找到则结果为-NOTFOUND。默认的情况下,VAR会被保存在 Cache中,这时候我们需要清除 VAR 才可以进行下一次查询(使用 unset命令)。 使用范例:

1
2
3
4
5
6
7
find_path(LUA_INCLUDE_PATHlua.h ${LUA_INCLUDE_FIND_PATH})

if(NOT LUA_INCLUDE_PATH)

   message(SEND_ERROR "Header file lua.hnot found")

endif()

find_library命令

命令语法:find_library(name1 [path1 path2 …]) 命令简述:用于查找库文件 name1 的路径,如果找到则将路径保存在 VAR中(此路径为一个绝对路径),如果没有找到则结果为-NOTFOUND。一个类似的命令link_directories已经不太建议使用了

add_definitions命令

命令语法:add_definitions(-DFOO-DBAR …) 命令简述:用于添加编译器命令行标志(选项),通常的情况下我们使用其来添加预处理器定义 使用范例:add_definitions(-D_UNICODE -DUNICODE)

file命令

命令简述:此命令提供了丰富的文件和目录的相关操作(这里仅说一下比较常用的) 使用范例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#目录的遍历

# GLOB用于产生一个文件(目录)路径列表并保存在 variable中

#文件路径列表中的每个文件的文件名都能匹配 globbing expressions(非正则表达式,但是类似)

#如果指定了 RELATIVE路径,那么返回的文件路径列表中的路径为相对于 RELATIVE 的路径

# file(GLOB variable [RELATIVE path] [globbingexpressions]...)

#获取当前目录下的所有的文件(目录)的路径并保存到 ALL_FILE_PATH变量中

file(GLOB ALL_FILE_PATH ./*)

#获取当前目录下的 .h文件的文件名并保存到 ALL_H_FILE 变量中

#这里的变量 CMAKE_CURRENT_LIST_DIR表示正在处理的CMakeLists.txt文件的所在的目录的绝对路径(2.8.3以及以后版本才支持)

file(GLOB ALL_H_FILE RELATIVE${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*.h)

target_include_directories(one PUBLIC include)命令 为目标添加include文件夹。

cmake中如何生成动态库和静态库 参考ADD_LIBRARY和SET_TARGET_PROPERTIES用法 t3示例

cmake中如何使用动态库和静态库(查找库的路径) 参考INCLUDE_DIRECTORIES, LINK_DIRECTORIES, TARGET_LINK_LIBRARIES用法 t4示例使用动态库或静态库 t5示例如何使用cmake预定义的cmake模块(以FindCURL.cmake为例演示) t6示例如何使用自定义的cmake模块(编写了自定义的FindHELLO.cmake) 注意读t5和t6的CMakeLists.txt和FindHELLO.cmake中的注释部分

cmake中如何指定生成文件的输出路径 如上ADD_SUBDIRECTORY的时候指定目标二进制文件输出路径(推荐使用下面这种) 使用SET命令重新定义EXECUTABLE_OUTPUT_PATH和LIBRARY_OUTPUT_PATH变量来指定最终的二进制文件的位置 SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 上面的两条命令通常紧跟ADD_EXECUTABLE和ADD_LIBRARY,与其写在同一个CMakeLists.txt即可 cmake中如何增加编译选项 使用变量CMAKE_C_FLAGS添加C编译选项 使用变量CMAKE_CXX_FLAGS添加C++编译选项 使用ADD_DEFINITION添加

cmake中如何增加头文件路径 参考INCLUDE_DIRECTORIES命令用法

cmake中如何在屏幕上打印信息 参考MESSAGE用法

cmake中如何给变量赋值 参考SET和AUX_SOURCE_DIRECTORY用法

建议:在Project根目录先建立build,然后在build文件夹内运行cmake ..,这样就不会污染源代码, 如果不想要这些自动生成的文件了,只要简单的删除build文件夹就可以

updatedupdated2021-11-062021-11-06