基本命令
-
CMakeLists.txt. 保存cmake的命令,当cmake在一个目录下运行时,就会自动执行这个文件.
-
cmake .. 解析执行cmakelists配置,并生成用于告诉构建系统如何编译的文件。
-
cmake --build. 使用相应的生成器编译项目。
-
cmake --help。查看生成器名单。
-
cmake -G "MinGW Makefiles" .. 该命令可以指定生成器.注意第二个参数需要指到cmakelists所在的目录。
-
cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6.设置编译器.
-
cmake -H. -Bbuild. -H表示再当前目录搜索txt文件,-B表示将生成的文件放在build文件夹下.
-
cmake_minimum_required. 指定cmake的最低版本.
cmake_minium_required(VERSION 3.5 FATAL_ERROR) # cmake版本号不满足要求则报错
-
project. 指定项目名称,在构建多个项目时,可以方便的指定一些变量.给命令会产生一个变量PROJECT_NAME.
project(hello LANGUAGES CXX) # 命名项目名称,并表明项目使用c++语言 -
add_executable. 第一个参数是生成可执行文件的名称,之后跟着所有的头文化以及cpp文件,以空格分隔.一般都是将源文件添加在这个命令中,但是clion将所有头文件也添加在其中.
-
CMAKE_BINARY_DIR.指的是cmake生成文件的目录.在哪运行cmake命令那么该变量的值就是那个目录.
- 原地生成. 直接在源代码的目录cmake.不推荐.
- 源码外生成.一般建立build文件夹.在build中使用相对路径执行cmake命令.
-
mingw32-make.exe. windows下没有make命令.装了MinGW之后可以使用该命令.
-
一些预置的目录变量.
- CMAKE_SOURCE_DIR. 项目的根目录.也就是cmake执行时,首次所使用的cmakelists所在的目录(最顶层).
- CMAKE_BINARY_DIR. 上边已经介绍.是cmake构建处理的文件的目录.同样是最顶层的build目录.
- CMAKE_CURRENT_SOURCE_DIR.在有子项目的时候,也就是多级cmakelists,那么该变量就是cmake当前执行的层级目录.
- PROJECT_SOURCE_DIR. 我的理解上同上一个一致.
- CMAKE_CURRENT_BINARY_DIR.当前层级的构建目录.
- PROJECT_BINARY_DIR.同上.
- PROJECT_NAME.project命令指定的.
- name_SOURCE_DIR/name_BINARY_DIR.
-
set(SOURCES src/h.cpp). 使用变量的形式去添加源文件.modern cmake让避免这么使用.
-
file(GLOB SOURCES "src/*.cpp"). 使用匹配的方式添加.官方文档建议不要使用。
-
target_include_directories(target PRIVATE ${PROJECT_SOURCE_DIR}/indclude). 引入需要被包含的文件,应该指的是头文件. 即使用此命令指定了一个目录后,那么在代码中就可以使用这个目录下的头文件。
- PRIVATE. 目录只被添加到指定target的包含目录.
- INTERFACE.所有连接这个库的target,都会包含这个目录.但是库本身不包含.
- public. 库本身也包含.对于公共的头文件.最好能在其外出包一个文件夹,起到命名空间的作用.
-
target_link_libraries( hello_binary PRIVATE hello_library). 将库连接到可执行文件.并且将具有public和interface的包含目录也传播到可执行文件.
-
add_library(target STATIC src/Helo.cpp).相对于add_executable,创建一个静态的链接库.
-
add_library(hello_library SHARED src/Hello.cpp). SHARED表示创建动态链接库.
-
add_library(hello::library ALIAS hello_library).alias target 作用是给连接库起一个别名,在连接的时候可以使用别名.
-
cmake .. -DCMAKE_INSTALL_PREFIX=/install/location. 指定程序的安装目录.
-
make install.作用是将编译后的文件:可执行文件/库文件/头文件/其他的任意文件.移动到指定的目录.起到安装的作用.
# Binaries
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)
# Library
# Note: may not work on windows
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)
# Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
# Config
install (FILES cmake-examples.conf
DESTINATION etc)
-
cmake .. -DCMAKE_BUILD_TYPE=Release. 设置cmake的打包类型, 例如debug/releas/RelWithDebInfo 等.
-
默认情况下,cmake不会是定任何用于优化的选项.
-
CMAKE_MODULE_PATH.在使用find_package时cmake会在该变量列出来的路径上去找FindXXX.cmake.
-
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system).表示寻找boost且版本大于1.46.1,required表示该库时必须的,没有找到就报错,components库中需要包括的模块.具体库叫什么,这些都是和库本身的FindXXX.cmake相关.一般找到后,会有XXX_FOUND的变量.同时也会导出一些变量,例如Boost_INCLUDE_DIRS.
-
add_subdirectory(sublibrary1).引入包含cmakelists的子目录.
使用场景
cmake与构建系统
什么是构建系统?例如:Unix Makefile、Ninja、Visual Studio等等就是构建系统。前两者是命令行的构建工具,而后者是集成开发环境。
什么是cmake?cmake就是构建系统的生成器,通过对cmakelists的执行,能够生成各种构建系统的文件。
include_directories vs target_include_directories
include_directories: 会让其后声明的所有子模块中都包含其引入的包含路径。
target_include_directories:只会在当前的target上引入。
另外set_target_properties中利用PUBLIC_HEADER也可以达到设置包含路径的目的。
理解 private public interface
cmake-test/ 工程主目录,main.c 调用 libhello-world.so
├── CMakeLists.txt
├── hello-world 生成 libhello-world.so,调用 libhello.so 和 libworld.so
│ ├── CMakeLists.txt
│ ├── hello 生成 libhello.so
│ │ ├── CMakeLists.txt
│ │ ├── hello.c
│ │ └── hello.h libhello.so 对外的头文件
│ ├── hello_world.c
│ ├── hello_world.h libhello-world.so 对外的头文件
│ └── world 生成 libworld.so
│ ├── CMakeLists.txt
│ ├── world.c
│ └── world.h libworld.so 对外的头文件
└── main.c
PRIVATE:私有的。生成 libhello-world.so时,只在 hello_world.c 中包含了 hello.h,libhello-world.so 对外的头文件——hello_world.h 中不包含 hello.h。而且 main.c 不会调用 hello.c 中的函数,或者说 main.c 不知道 hello.c 的存在,那么在 hello-world/CMakeLists.txt 中应该写入:
target_link_libraries(hello-world PRIVATE hello)
target_include_directories(hello-world PRIVATE hello)
INTERFACE:接口。生成 libhello-world.so 时,只在libhello-world.so 对外的头文件——hello_world.h 中包含 了 hello.h, hello_world.c 中不包含 hello.h,即 libhello-world.so 不使用 libhello.so 提供的功能,只使用 hello.h 中的某些信息,比如结构体。但是 main.c 需要使用 libhello.so 中的功能。那么在 hello-world/CMakeLists.txt 中应该写入:
target_link_libraries(hello-world INTERFACE hello)
target_include_directories(hello-world INTERFACE hello)
PUBLIC:公开的。PUBLIC = PRIVATE + INTERFACE。生成 libhello-world.so 时,在 hello_world.c 和 hello_world.h 中都包含了 hello.h。并且 main.c 中也需要使用 libhello.so 提供的功能。那么在 hello-world/CMakeLists.txt 中应该写入:
target_link_libraries(hello-world PUBLIC hello)
target_include_directories(hello-world PUBLIC hello)
需不需要将头文件加入到 add_library/add_executable
Why add header files into ADD_LIBRARY/ADD_EXECUTABLE command in CMake
如果不加也可以正常运行,但是生成基于IDE的项目时,头文件不会再IDE中显示。
add_library操作/生成不同类型的库
add_library 的第二个参数表示要生成或者操作库的类型。其取值有:STATIC/SHARED/OBJECT/MODULE以及IMPORETED/INTERFACE/ALIAS。前四种是会生成的库,而后三种则不会在构建系统中产出。
OBJECT:表示add_liabray中的源码不生成静态或者动态库,而是生成中间态的东西,可以用它去继续生成静态后者动态库,对于同时生成静态和动态库很有用。
$<TARGET_OBJECTS:message-objs> 为生成器表达式语法。
add_library(message-shared
SHARED
$<TARGET_OBJECTS:message-objs>
)
# 使用set_target_properties设置输出的名称
set_target_properties(message-shared
PROPERTIES
OUTPUT_NAME "message"
)
add_library(message-static
STATIC
$<TARGET_OBJECTS:message-objs>
)
set_target_properties(message-static
PROPERTIES
OUTPUT_NAME "message"
)