可见性修饰符和目标
cmake中有三种可见性修饰符:PRIVATE
、PUBLIC
和INTERFACE
这些修饰符随着命令一起使用,如target_include_directories
和target_link_libraries
等
这些修饰符是在目标targets的上下文中指定的
目标targets是指在cmake中某种类型的输出:
- 可执行目标
add_executable
生成二进制可执行文件 - 库目标
add_library
生成库文件 - 自定义目标
add_custom_target
通过脚本生成任意文件
接口目标是库目标的一个特殊情况,定义如下:
add_library(my_interface_lib INTERFACE)
target_include_directories(my_interface_lib INTERFACE include/)
这里my_interface_lib
不会立即生成任何文件,但后面可能有依赖它的具体目标
INTERFACE
库可以被看作是构建依赖关系的一种便利机制
target_include_directories(test PRIVATE "${CMAKE_BINARY_DIR}")
表示目标test
将使用指定的包含目录
但若后面有其他目标链接到test
,则不会依赖于该目录
即源文件和依赖关系只传递给当前目标
target_include_directories(test PUBLIC "${CMAKE_BINARY_DIR}")
表示目标test
将使用指定的包含目录
且若后面有其他目标链接到test
,也会依赖该包含目录
即源文件和依赖关系传递给当前目标及依赖它的目标
target_include_directories(test INTERFACE "${CMAKE_BINARY_DIR}")
表示目标test
本身不需要该包含目录
但若后面有其他目标链接到test
,则会依赖于该包含目录
即源文件和依赖关系不传递给当前目标,但会传递给依赖它的目标
cmake中可以用子目录指定独立的模块及其自定义构建流程
可以由一个主cmake配置触发多个目录的构建,最后再链接到主程序
如下目录结构
test
MathFunc
mysqrt.hpp
mysqrt.cpp
MathFunc.hpp
MathFunc.cpp
CMakeLists.txt
test.cpp
CMakeLists.txt
库文件的使用
需要找到库文件和对应的头文件
- 添加库文件
target_link_libraries()
-
添加头文件的两种方法
INCLUDE_DIRECTORIES
全局性引入
target_include_directories
可以为当前目标文件指定头文件路径 -
使用更现代化的方法来包含库文件
如链接MathFunc
库的目标文件都需要包含MathFunc
目录作为头文件路径
若在MathFunc/CMakeLists.txt中添加
target_include_directories(
MathFunc
INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}
)
指定了INTERFACE
修饰,则项目的CMakeLists.txt可以不使用EXTRA_INCLUDE
变量
只要链接MathFunc库,就会自动包含库所在目录的头文件
注意:静态库被不同程序引用,内存在会存在静态库函数的多份拷贝
生成可执行文件
add_executabe()
若有多个源文件,用空格隔开,可以用${PROJECT_NAME}
引用项目名
用一个变量来表示多个源文件
set(SRC_LIST a.cpp b.cpp c.cpp)
引用变量的方式${}
添加编译时间戳
string(TIMESTAMP COMPILE_TIME %Y%m%d-%H%M%S)
在Config.h.in
中添加#define TIMESTAMP @COMPILE_TIME@
指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
在add_executable
命令之前添加,GCC6.1开始,默认为C++14
将库文件设置为可选项
- 经典方法
提供用户可选项option(USE_MATHFUNC "description" ON)
将库的构建和链接添加条件
if(USE_MATHFUNC)
add_subdirectory(MathFunc)
list(APPEND EXTRA_LIBS MathFunc)
list(APPEND EXTRA_INCLUDES ${PROJECT_SOURCE_DIR}/MathFunc)
endif()
target_link_libraries(
${PROJECT_NAME}
PUBLIC
${EXTRA_LIBS}
)
target_include_directories(
${PROJECT_NAME}
PUBLIC
${PROJECT_BINARY_DIR}
${EXTRA_INCLUDES}
)
变量EXTRA_LIBS
保存需要链接到可执行程序的可选库
变量EXTRA_INCLUDES
保存可选的头文件的搜索路径
- 现代方法
修改源代码
#ifdef USE_MATHFUNC
#include"MathFunc.hpp"
#endif
#ifdef USE_MATHFUNC
const double val= mysqrt(inputVal);
#else
const double val= std::sqrt(inputVal);
#endif
由于是引用的cmake中的变量,需要在Config.h.in
中添加
#cmakedefine USE_MATHFUNC
也可以在构建时指定变量值
cmake -DUSE_MATHFUNC=OFF ..
cmake --build .
安装规则
install(
TARGETS target1 [target2 ...]
[RUNTIME DESTINATION dir]
[LIBRARY DESTINATION dir]
[ARCHIVE DESTINATION dir]
[INCLUDES DESTINATION [dir ...]]
[PRIVATE_HEADER DESTINATION dir]
[PUBLIC_HEADER DESTINATION dir]
)
在C++项目中使用cmake中的变量
cmake通过config.h.in
提供的机制,允许在cpp文件中使用CMakeLists.txt中的变量
编写文件Config.h.in
#pragma once
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define AUTHOR_NAME "@AUTHOR_NAME@"
在CMakeLists.txt中配置
cmake_minimum_required(VERSION 3.10)
project(tuto)
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 0)
set(AUTHOR_NAME "Jith")
configure_file(Config.h.in Config.h)
add_executable(tuto tuto.cpp)
# include the dir where the generated header file is located
target_include_directories(tuto PRIVATE "${CMAKE_BINARY_DIR}")
Config.h
会自动写入到build目录
需要将该目录添加到搜索头文件的路径列表,也可以修改为写到其它目录
${CMAKE_BINARY_DIR}
表示当前工程的二进制路径,存放编译生成,即build目录
cmake会在变量占位被填充后生成头文件,这些动态生成的头文件需要被包含到项目中
示例中Config.h
文件被放置在${CMAKE_BINARY_DIR}
目录中,所以只需要指定该路径即可