简介
官网 : https://cmake.org/cmake/help/v3.15/
CMake是跨平台的 免费和开源软件,用于使用独立于编译器的方法构建自动化、测试、打包和安装软件。CMake 本身并不是一个构建系统;它生成另一个系统的构建文件。它支持目录层次结构和依赖于多个库的应用程序。它与原生构建环境结合使用,例如Make、Qt Creator、Ninja、Android Studio、Apple 的Xcode和Microsoft Visual Studio。(摘自Wiki)
CMakeLists.txt
常用命令
-
cmake要求最低版本(选择性添加)
cmake_minimum_required(VERSION 3.0.0)
-
编译工程名
project(xxx) //会自动创建两个变量,PROJECT_SOURCE_DIR和PROJECT_NAME //${PROJECT_SOURCE_DIR}:本CMakeLists.txt所在的文件夹路径 //${PROJECT_NAME}:本CMakeLists.txt的project名称
-
给部分文件或路径组合起别名, 通过${变量}获取变量内容
set(变量 文件名/路径/...)
-
设置c / c++ 编译编译参数
set (CMAKE_C_FLAGS -Wall -O2) set (CMAKE_CXX_FLAGS -Wall -std=C++11) add_compile_options( -Wall ) //该命令译选项是针对所有编译器的(包括c和c++编译器)
-
为当前路径以及子目录的源文件加入由-D引入的define flag
add_definitions(-DFOO -DDEBUG ...)
-
对子文件夹进行cmake编译
add_subdirectory(子文件夹名)
-
打印信息
message() //直接添加打印的内容和变量即可,不需要双引号 message("PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}")
-
帮助信息
1. 查看cmake默认变量 cmake --help-variable-list
判断语句
用法:根据某个宏确定编译内容。比较字符串,相同返回true
if (CPU_PLATFORM_BIT STREQUAL "64")
add_library(mylib generic_64bit.c)
else()
add_library(mylib generic_32bit.c)
endif()
编译目标
二进制文件
add_executable(目标文件名字xxx 源文件)
//example: add_executable(${PROJECT_NAME} example_person.cpp)
动态 / 静态库
将指定的源文件生成链接文件,然后添加到工程中去
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...])
//<name>表示库文件的名字,该库文件会根据命令里列出的源文件来创建。生成的库自动补全,如libxxx.so
//STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被 动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数 。默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。
//source1 source2分别表示各个源文件
链接/路径
头文件路径
添加头文件的查找路径, 相当于命令行的 -l 参数
include_directories(../thirdparty/comm/include)
链接库路径
添加需要链接的库文件目录, 相当于命令行 -L 参数
link_directories("/home/server/third/lib")
链接库
将目标文件与库文件进行链接
target_link_libraries(<target> [item1] [item2] [...] [[debug|optimized|general] <item>] ...)
//<target>是指通过add_executable()和add_library()指令生成已经创建的目标文件
//[item]表示库文件没有后缀的名字。默认情况下,库依赖项是传递的。当这个目标链接到另一个目标时,链接到这个目标的库也会出现在另一个目标的连接线上。这个传递的接口存储在interface_link_libraries的目标属性中,可以通过设置该属性直接重写传递接口。
安装(Install)
- 详情参考:https://cmake.org/cmake/help/v3.22/command/install.html
- 作用:用于定义安装规则,安装内容包括可执行文件,静态库,动态库以及文件,目录,脚本等
- 使用方法:make install
- 目标安装路径:${CMAKE_INSTALL_PREFIX}指定,默认/usr/local
目标文件安装
目标文件指的是我们通过 add_executable / add_library 得到的二进制文件或者库,只有这些文件才可以通过该命令装载到相应的位置
- 可执行文件:RUNTIME
- 动态库:LIBRARY
- 静态库:ARCHIVE
install(TARGETS targets... [EXPORT <export-name>]
[RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]
[INCLUDES DESTINATION [<dir> ...]]
)
// example:
install(TARGETS mybin mystaiclib mydynamiclib
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
普通文件安装
普通文件即需要导出的头文件、依赖的三方库等等,该命令同时可以指定导出文件的权限(默认644)
install(<FILES|PROGRAMS> files...
TYPE <type> | DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
// example
install(FILES mylib.h DESTINATION include)
目录安装
参数介绍:
- DIRECTORY:后面连接的是所在Source目录的相对路径(结尾是否是"/"对拷贝结果有一定影响)
- PATTERN:使用正则表达式进行过滤
- PERMISSIONS:指定PATTERN过滤后的文件权限。
install(DIRECTORY dirs...
TYPE <type> | DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
// example
install(DIRECTORY src/ DESTINATION include/myproj FILES_MATCHING PATTERN "*.h")
Q&A
-
Q: 编译参数添加了-lpthread 参数, 但是还是报undefined reference to `pthread_create’
A : 需要使用target_link_libraries( target thread) 在这里链接thread库
-
Q: 如果在多级的目录下编译, 始终找不到问题报 undefine的问题 ?
A : 看一下是不是链接的库或目标文件格式不同, 一个c 一个c++ , 这样就会导致找不到符号错误
-
Q: undefined reference to `typeinfo for xxxBase_class’ ?
A: 基类的构造和析构函数需要加{ }; 否则就会报这个问题
Makefile
通配符
通配符 | 使用说明 |
---|---|
* | 匹配0个或者是任意个字符 |
? | 匹配任意一个字符 |
[] | 我们可以指定匹配的字符放在 “[]” 中 |
% | 匹配任意个字符 |
自动化变量
自动化变量 | 说明 |
---|---|
$@ | 表示规则的目标文件名。如果目标是一个文档文件(Linux 中,一般成 .a 文件为文档文件,也成为静态的库文件), 那么它代表这个文档的文件名。在多目标模式规则中,它代表的是触发规则被执行的文件名。 |
$% | 当目标文件是一个静态库文件时,代表静态库的一个成员名。 |
$< | 规则的第一个依赖的文件名。如果是一个目标文件使用隐含的规则来重建,则它代表由隐含规则加入的第一个依赖文件。 |
$? | 所有比目标文件更新的依赖文件列表,空格分隔。如果目标文件时静态库文件,代表的是库文件(.o 文件)。 |
$^ | 代表的是所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有的库成员(.o 文件)名。 一个文件可重复的出现在目标的依赖中,变量“ ”只记录它的第一次引用的情况。就是说变量“ ”只记录它的第一次引用的情况。就是说变量“ ”只记录它的第一次引用的情况。就是说变量“”会去掉重复的依赖文件。 |
$+ | 类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。 |
$* | 在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分(当文件名中存在目录时, “茎”也包含目录部分)。 |
特殊函数
添加前缀
- 函数名:addprefix( )
- 语法:$(addprefix PREFIX/,${NAME…})
- 函数功能:为“NAMES…”中的每一个文件名添加前缀“PREFIX”。参数“NAMES…”是空格分割的文件名序列,将“PREFIX”添加到此序列的每一个文件名之前。
- 返回值:以单空格分割的添加了前缀“PREFIX”的文件名序列。
$(addprefix src/,foo bar)
//返回值为“src/foo src/bar”
过滤器
- 函数名:filter( )
- 语法:$(filter SUFFIX…,$(SOURCES))
- 作用:保留字串 " $(SOURCES)" 中所有符合模式 “ SUFFIX ” 的单词
sources := main.c AT.txt
foo : $(sources)
cc $(filter %.c,%.s,$(sources)) -o foo
打印
用于Makefile的Debug,打印分为三个等级:info、warning、error
$(info SRC = $(SRC))
$(warning INC = $(INC))
//注意:执行到error会直接stop退出
$(error INC = $(INC))
Linux相关更多内容请关注 yanglieee.com,讲持续发布!