CMake
cmake的定义是 -- 高级编译配置工具
当多人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(dll,so等等)这时候就需要用到 ------ CMake
所有操作都是通过编译 CMakeLists.txt 来完成的
官方网站是 www.cmake.org
学习CMake的目的,为将来处理大型的C/C++/JAVA项目做准备
CMake安装
构建和运行
- 创建一个文件夹,里面再创建一个 src 文件夹,src文件夹中包含:main.cpp,CMakeLists.txt
main.cpp:
#include<iostream>
using namespace std;
int main()
{
cout<<"Hello World"<<endl;
return 0;
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(demo)
# add the executable
add_executable(demo main.cpp)
- 新建一个构建目录
mkdir build
- 进入该目录进行配置项目
cd build
cmake ../src
如果 cmake ../src 报错,则说明不是使用默认的Generator,应当添加 -G 选项:
cmake -G "MinGW Makefiles" ../src
- 构建
cmake --build .
- 运行,如果是上述例子(上面都是在cmd中运行)
demo.exe
说明
- cmake命令不区分大小些写,但是参数、变量区分大小写
- 参数使用空格或者分号隔开
- 使用 ${VAR} 引用变量
- 引号可加可不加,但如果字符串中有空格必须加
概念
- 目标文件(target):可执行文件(add_executable)、库文件(add_library)
- 命令(cmake-command):下面要讲的函数
- 变量(cmake-variable):以 CMAKE_ 开头的变量名
- 属性(cmake-properties):文件/文件夹都有各自的属性
命令
cmake_minimum_required
设置最低cmake版本
cmake_minimum_required(VERSION <min>)
cmake_minimum_required(VERSION 3.10)
project
设置项目名
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
# 项目名会被存储在变量 PROJECT_NAME 和 CMAKE_PROJECT_NAME 中
# PROJECT_SOURCE_DIR 等价于 <PROJECT-NAME>_SOURCE_DIR 项目的源目录的绝对路径。
# PROJECT_BINARY_DIR 等价于 <PROJECT-NAME>_BINARY_DIR 项目的二进制目录的绝对路径
# 如果定义了版本号
# 版本号被保存在 PROJECT_VERSION 和 <项目名称>_VERSION中
# 主版本号被保存在 PROJECT_VERSION_MAJOR 和 <项目名称>_VERSION_MAJOR
# 次版本号被保存在 PROJECT_VERSION_MINOR 和 <项目名称>_VERSION_MINOR
# 方式一: project(demo C CXX) 指定项目的语言为c和c++
# 方式二: project(demo VERSION 1.0 LANGUAGES CXX) 指定项目版本和语言
# set the project name
project(demo VERSION 1.0 LANGUAGES CXX)
# 打印项目名字
message(${PROJECT_NAME}) # demo
# 打印项目源目录的绝对路径
message(${PROJECT_SOURCE_DIR}) # D:/Visual Studio/repos/CMakeDemo01/src
message(${demo_SOURCE_DIR}) # D:/Visual Studio/repos/CMakeDemo01/src
# 打印项目的二进制目录的绝对路径
message(${PROJECT_BINARY_DIR}) # D:/Visual Studio/repos/CMakeDemo01/build
message(${demo_BINARY_DIR}) # D:/Visual Studio/repos/CMakeDemo01/build
# 打印版本号,主版本号,次版本号
message(${PROJECT_VERSION}) # 1.0
message(${PROJECT_VERSION_MAJOR}) # 1
message(${PROJECT_VERSION_MINOR}) # 0
add_executable
用指定的源文件为项目添加可执行文件
add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
# <name>即生成可执行文件的名字(与项目名没有关系),在一个项目中必须唯一
# 如windows系统会生成<name>.exe文件
add_executable(demo main.cpp) # 系统会生成 demo.exe
message
打印信息
message([<mode>] "message text" ...)
# STATUS 前缀为--的信息
# SEND_ERROR 产生错误,跳过生成过程
# FATAL_ERROR 产生错误,终止运行
# 例如
message(STATUS "${PROJECT_VERSION_MAJOR}") # -- 1
set
将变量设置为指定值
set(<variable> <value>)
# 例
set(A 1)
message(${A}) # 1
设置C++标准
# 使用c++11标准
set(CMAKE_CXX_STANDARD 11)
设置输出文件的位置
# 设置运行时目标文件(exe、dll)的输出位置,dll为动态库
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 设置存档目标文件(lib、a 静态库)的输出位置
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# 在有静态库之后,就可以使用第二个设置了,就会这build生成一个lib文件夹,专门用来存放静态库文件
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# 在src的CMakeLists.txt中加入这个命令之后,在配置和构建,就能在build文件下得到一个lib文件夹
|--build
|--lib
|--***
|--src
***
option
定义一个开关
option(<variable> "<help_text>" [value])
# value的值为 ON 或 OFF ,默认为 OFF
# 命令行 -D<variable>=ON/OFF
# 例如:定义是否输出版本号 option(VERSION_ENABLE "output version" ON)
configure_file
将输入文件进行替换并生成输出文件
1.
configure_file(<input> <output>)
# 输入文件中形如 @VAR 或 ${VAR} 的字符串会被替换为这些变量的当前值,如果未定义则被替换为空字符串
# 其规则见下
例1:
在src目录下创建一个config.h.in文件
# config.h.in文件
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
# 由上面可知,PROJECT_VERSION_MAJOR = 1,PROJECT_VERSION_MINOR = 0
在CMakeLists.txt中版本号下面添加
# 将config.h.in中的 @...@ 里面的值换成当前变量的值
configure_file(config.h.in config.h)
然后再cmd中配置和构建以后,会再build下生成一个config.h文件
cmake -G "MinGW Makefiles" ..\src
cmake --build .
# config.h文件中的内容
#define PROJECT_VERSION_MAJOR 1
#define PROJECT_VERSION_MINOR 0
现在我们就能够调用config.h中的内容了
在main.cpp中加入
#include<iostream>
#include"../build/config.h" //加入的内容
using namespace std;
int main()
{
cout<<"Hello World"<<endl;
//加入的内容
cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
return 0;
}
在CMakeLists.txt中加入
target_include_directories(demo PUBLIC "${PROJECT_BINARY_DIR}")
再重新配置和构建,运行可看到运行结果
cmake -G "MinGW Makefiles" ..\src
cmake --build .
bin\demo.exe
//结果显示:Hello World
// version :1.0
2.
#cmakedefine VAR ...
// 会被替换为以下两行之一,取决于VAR是否被设置
#define VAR ...
/* #undef VAR */
例2:
在CMakeLists.txt中写入
# 设置开关是否打开,ON 表示打开
option(DATE_ENABLE "output date" ON)
# 如果开关打开,则打印时间
if(DATE_ENABLE)
set(DATE "2022.12.6")
endif()
在config.h.in中加入
#cmakedefine DATE "2022.12.6"
配置,构建,之后再config.h中会出现
cmake -G "MinGW Makefiles" ..\src
cmake --build .
#define DATE "2022.12.6"
如果 CMakeLists.txt 中的 option 是 OFF
# 设置开关是否打开,OFF 表示打开
option(DATE_ENABLE "output date" ON)
在进行同样的操作(再进行同样操作之前,要将缓存清理掉,就是删除build中的文件,重新配置和构建),这 config.h 中则会出现
/* #undef DATE */
include_directories
指定所有目标的头文件路径
include_directories(dir1 [dir2 ...])
# 目录会被添加到当前文件的 INCLUDE_SIRECTORIES 属性中
# 当前文件的每一个目标文件的 INCLUDE_DIRECTORIES 属性也会添加该目录
# CMakeLists.txt
# 指定所有目标的头文件路径,如果不加这个,那么再构建的时候 main.cpp 中的 #include"config.h" 会报错
include_directories(${PROJECT_BINARY_DIR})
target_include_directories
指定(一个)目标的头文件路径
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# 目标文件有 INCLUDE_DIRECTORIES 和 INTERFACE_INCLUDE_DIRECTORIES 两个属性
# INCLUDE_DIRECTORIES 对内头文件目录
# INTERFACE_INCLUDE_DIRECTORIES 对外头文件目录
INCLUDE_DIRECTORIES | INTERFACE_INCLUDE_DIRECTORIES | |
---|---|---|
PRIVATE(自己使用) | √ | |
INTERFACE(给别人使用) | √ | |
PUBLIC(都能使用) | √ | √ |
# 指定(一个)目标的头文件路径,这样写 main.cpp 中的 #include"config.h" 也不会报错
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR})
add_subdirectory
添加源文件目录
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# binary_dir 指定编译结果存放的位置
# 在 src 的 CMakeLists.txt 中加入
# 添加一个子目录,执行该命令时,则会进入到calc中,运行calc中的CMakeLists.txt
add_subdirectory(clac)
add_library
用指定的源文件生成库
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[<source>...])
# STATIC 静态库
# SHARED 动态库
# 生成的库文件名为 lib<name>.xxx
# 在 calc 中的 CMakeLists.txt 中写
add_library(addition STATIC addition.cpp) # 创建静态库
add_library(subtract SHARED subtract.cpp) # 创建动态库
target_link_libraries
为目标链接库
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
# item 可以是 target名、绝对路径(必须保证文件存在)
# 将 calc 中生成的库,链接到demo
# 在 src 下的 CMakeLists.txt 写
# 为目标链接库,给demo链接一个addition 静态库
target_link_libraries(demo PUBLIC addition)
# 为目标链接库,给demo链接一个subtract 动态库
target_link_libraries(demo PUBLIC subtract)
# 指定目标的头文件路径
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/calc)
# 为了使 main.cpp 中的 #include"addition.h" 不报错,需要给他添加一个 头文件搜索目录,即加入${PROJECT_SOURCE_DIR}/calc
// 之后就能在main.cpp中调用add函数了
#include<iostream>
#include"config.h"
#include"addition.h" // 新加的
#include"subtract.h" // 新加的
using namespace std;
int main()
{
cout<<"Hello World"<<endl;
cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
#ifdef DATE
cout << "date " << DATE << endl;
#endif
cout<< "1 + 2 = " << add(1,2) << endl; //新加的
cout<< "3 - 1 = " << sub(3,1) << endl; //新加的
return 0;
}
进行配置和构建,构建完之后,由上面 set 设置的文件输出路径可知:
- 动态库生成在 build/bin 下面的 .dll 文件
- 静态库生成在 build/lib 下面的 .a文件
链接外部其他的库
先创建一个文件夹,将要 链接的库和所需的头文件 放入其中,如other_lib
|--build
|--bin
***
|--libdivision.dll // 如果链接的是外部动态库,还需要将外部动态库放到 build/bin 目录下
***
|--other_lib
|--libmultiply.a //外部静态库
|--multiply.h //头文件
|--libdivision.dll //外部动态库
|--division.h //头文件
|--src
在 src 的 CMakeLists.txt 添加
# 为目标链接库,给demo链接一个 外部的静态库 multiply
target_link_libraries(demo PUBLIC "D:/Visual Studio/repos/CMakeDemo01/other_lib/libmultiply.a")
# 为目标链接库,给demo链接一个 外部的动态库 division
target_link_libraries(demo PUBLIC "D:/Visual Studio/repos/CMakeDemo01/other_lib/libdivision.dll")
# 指定(一个)目标的头文件路径,并添加文件路径 ${PROJECT_SOURCE_DIR}/../other_lib
target_include_directories(demo PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/calc ${PROJECT_SOURCE_DIR}/../other_lib)
之后就能够在 main.cpp 中调用了
#include<iostream>
#include"config.h"
#include"addition.h"
#include"subtract.h"
#include"multiply.h" // 新加的
#include"division.h" // 新加的
using namespace std;
int main()
{
cout<<"Hello World"<<endl;
cout<<"version: "<< PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR <<endl;
#ifdef DATE
cout << "date " << DATE << endl;
#endif
cout<< "1 + 2 = " << add(1,2) << endl;
cout<< "3 - 1 = " << sub(3,1) << endl;
cout<< "2 * 3 = " << mult(2,3) << endl; // 新加的
cout<< "6 / 2 = " << divi(6,2) << endl; // 新加的
return 0;
}
区分
# 头文件目录
include_directories()
target_include_directories()
# 链接时库目录,不推荐使用
link_directories()
target_link_directories()
# 链接库
link_libraries()
target_link_libraries()
# 都推荐使用以 target_ 开头的函数
安装
cmake代码
在对应目录的CMakeLists.txt中使用
install(TARGETS <target> DESTINATION <dir>)
install(FILES <file> DESTINATION <dir>)
install(PROGRAMS <非目标文件的可执行程序> DESTINATION <dir>) # 如脚本
install(DIRECTORY <dir> DESTINATION <dir>) # 安装目录
在 src 的 CMakeLists.txt 中添加
# 安装目标文件,将demo可执行文件安装到bin目录下
install(TARGETS demo DESTINATION bin)
# 将外部的静态库文件安装到lib目录下
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/libmultiply.a" DESTINATION lib)
# 将外部的动态库文件安装到bin目录下
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/libdivision.dll" DESTINATION bin)
# 安装config的头文件
install(FILES "${PROJECT_BINARY_DIR}/config.h" DESTINATION include)
# 安装外部multiply的头文件
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/multiply.h" DESTINATION include)
# 安装外部division的头文件
install(FILES "D:/Visual Studio/repos/CMakeDemo01/other_lib/division.h" DESTINATION include)
在 calc 的 CMakeLists.txt 中添加
add_library(addition STATIC addition.cpp) # 创建静态库
# 新添加的部分 start
# 将addition安装到lib目录下,因为addition为静态库
install(TARGETS addition DESTINATION lib)
# 安装addition的头文件
install(FILES addition.h DESTINATION include)
# end
add_library(subtract SHARED subtract.cpp) # 创建动态库
# 新添加的部分 start
# 将subtract安装到bin目录下,因为subtract为动态库
install(TARGETS subtract DESTINATION bin)
# 安装subtract的头文件
install(FILES subtract.h DESTINATION include)
# end
命令行
cmake --install . # 安装到默认目录
CMAKE_INSTALL_PREFIX
cmake --install . --prefix <dir> # 安装到指定目录
标签:CMake,入门,--,demo,PROJECT,VERSION,cmake,include
From: https://www.cnblogs.com/sususuH/p/17441471.html