三年前整理过Makefile常用模板 ,一直写手写Makefile,近来不得不用到cmake,实践了一下感觉真香!功能强大!还是那句话 自己总结方便查阅,要是能帮到别人那是极好的~
cmake命令依赖CMakeList.txt文件,解析成makefile文件,然后make编译。
先给出常见模块方便使用,后面有语法简介,详细语法查阅cmake官网。
常用模板
cmake_minimum_required(VERSION 3.10) # 必须
set(CMAKE_CXX_STANDARD 14) # C++14
project(HelloWorld) #工程名
include_directories("/usr/local/include/") # 头文件目录
link_directories("/usr/local/lib/") # 链接库目录
aux_source_directory(. SRCS) # 源文件
aux_source_directory(./abc SRCS)
set(CMAKE_C_FLAGS "-O1") # 设置C工程的 CFLAGS
set(CMAKE_CXX_FLAGS "-O0 -Werror") # 设置C++ 工程的 CXX_FLAGS
add_executable(${PROJECT_NAME} ${SRCS}) # 生成可执行文件,这里程序名即为功能名
target_link_libraries(${PROJECT_NAME} pthread) # 链接库
# 下面使用install作为项目打包使用
set(CMAKE_INSTALL_PREFIX ./dist) # 自定义安装目录,打包使用
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) # 打包二进制文件
set(CONFIGS ${PROJECT_SOURCE_DIR}/hello.cf)
install(FILES ${CONFIGS} DESTINATION config) # 打包配置文件
cmake 使用提示
cmake工程一般都不在源码目录直接编译,通常新建目录进行编译,配置失败可以直接删除新目录再重新配置。
比如有个hello工程。
cd hello
mkdir build
cd build
cmake ..
make
或
cd hello
cmake -S . -B build
cd build
make
常见语法介绍
cmake版本
必选项。放在第一行,指定cmake最低版本。
cmake_minimum_required(VERSION 3.5.1)
设置工程名字
这个应该可以必选项。工程名后面可选 加 语言类型。
指定的工程名,在后面可以通过变量${PROJECT_NAME}
获取此值。
这里可以继续指定工程版本等其他信息,用到去查官方文档。
project(HelloWorld) # 一般用这个就OK
project(HelloWorld C) # 可选指明是C语言
project(HelloWorld CXX) # 可选指明是C++
project(HelloWorld C CXX) # C & C++
指定语言版本
C++语言版本
set(CMAKE_CXX_STANDARD 11)
C语言版本
set(CMAKE_C_STANDARD 11)
这里其实是用set
给默认变量CMAKE_CXX_STANDARD
& CMAKE_C_STANDARD
赋值。
指明源码文件
源码文件可以使用最基础的set()
变量赋值的方式,但是太啰嗦。
可以用aux_source_directory(目录名 变量)
来检索此目录下所有源文件。或者使用FILE()
函数检索。
aux_source_directory(. SRCS) # 当前目录
aux_source_directory(../common/ SRCS) # 上级目录
FILE(GLOB SRCS ${PROJECT_SOURCE_DIR}/*.cpp) # 匹配源码目录所有.cpp文件
FILE(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/*.cpp ) # 递归搜索匹配源码目录和其子目录下的.cpp文件
指定头文件目录
include_directories
后可以可以加SYSTEM
标志,这个标志是告诉编译器将此目录视为系统目录,跳过某些编译检查。一般不用加SYSTEM
。
include_directories("../third-party/include/")
include_directories(SYSTEM "/usr/local/include/") # 可选SYSTEM
生成可执行文件
add_executable(可执行文件名 源文件)
,源文件可以是变量形式,或者后面加了一串源文件名。
add_executable(${PROJECT_NAME} main.cpp a.h a.cpp)
add_executable(${PROJECT_NAME} ${SRCS})
生成动态库、静态库
add_library后面接TARGET名,不含lib
前缀和.a | .so
后缀。
add_library(hello ${SRCS}}
add_library(hello STATIC ${SRCS}} # 生成libhello.a
add_library(hello SHARED ${SRCS}} # 生成libhello.so
指定链接库目录
动态库或者静态目录
link_directories("/usr/local/lib/")
指定链接动/静态库
我查到了有两个函数link_libraries
和target_link_libraries
,这两者区别是 前者需放生成目标之前,后者放在生成目标之后。比如
在前
link_libraries(pthread) # 在add_executable前面
add_executable(${PROJECT_NAME} main.cpp)
在后
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} pthread) # 在add_executable后面,且第一参数为目标名。
Clion工程采用的是第一种方式。要是按照 编译-链接 的顺序,还是后者比较好理解。
make install
一般开源项目需要安装的,都有make install命令,这个命令是通过install
函数实现的。安装的时候一般都需要指定安装路径,cmake里面通过设置CMAKE_INSTALL_PREFIX
来实现的,可以在执行cmake的时候直接指定,比如cmake .. -DCMAKE_INSTALL_PREFIX=./local
,Linux环境默认是/usr/local
目录。
可以使用此命令进行工程打包发布操作。
# 安装可执行文件
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) # 安装在 /usr/local/bin目录
# 安装动态库到lib目录
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib) # 安装在 /usr/local/lib目录
install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION lib) # 多用于静态库
# 安装对外头文件
install(TARGETS ${XXXX} PUBLIC_HEADER DESTINATION include)
# 安装其他文件,比如配置文件
install(FILES ${CONFIGS} DESTINATION config)
多级目录多个工程
可以使用add_subdirectory
编译子目录中的cmake工程。
add_subdirectory(subdir)
输出方式
message函数输出,可以指定输出消息类型STATUS
WARNING
DEBUG
等。
message("hello")
message(STATUS ${PROJECT_NAME})
常见宏(默认变量)
宏 | 说明 |
---|---|
PROJECT_NAME | project()设置的工程名 |
PROJECT_SOURCE_DIR | 工程源码目录,例如 ~/Hello/ |
PROJECT_BINARY_DIR | 生成文件目录,例如 ~/Hello/build |
高级功能
下面这些高级功能用的比较少,详细查看官方文档。
检索依赖
查看依赖的头文件或者库是否存在。
find_package(Threads REQUIRED)
find_package(Protobuf CONFIG REQUIRED)
自定义命令
add_custom_command(
OUTPUT
"${生成文件}"
COMMAND
${命令}
ARGS
"命令参数"
DEPENDS
"依赖")