Cmake教程
参考网站:https://subingwen.cn/cmake/CMake-primer/
https://subingwen.cn/cmake/CMake-advanced/
$Cmake -G “MinGW Makefiles” …
$make
$rm -rf *
VScode与Git联合进行代码管理。
cmake_minimum_required(VERSION 3.0)
project(CALC)
add_executable(app add.c div.c main.c mult.c sub.c)
//定义变量SRC——LIST
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app ${SRC_LIST})
//指定C++的使用标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
//指定输出路径
set(HOME /D:/test)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)//若目录不存在会自动创建目录。
include_directories(${PROJECT_SOURCE_DIR}/include)//包含的头文件目录地址。
//将src目录下的源文件(.cpp文件)包含在 SRC_LIST变量中。
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
add_executable(app ${SRC_LIST})
GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中
//搜索当前目录的src目录下所有的.cpp源文件,并存储到变量MAIN_SRC中
file(GLOB MAIN_SRC ${CMAKE_SURRENT_SOURCE_DIR}/src/*.cpp)
fie(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) */*/
file(GLOB MAIN_SRC "${CMAKE_SURRENT_SOURCE_DIR}/src/*.cpp")
包含头文件目录
$ tree
.
├── build
├── CMakeLists.txt
├── include
│ └── head.h
└── src
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp
3 directories, 7 files
cmake_minimum_required(VERSION 3.0)
project(CALC)
set(CMAKE_CXX_STANDARD 11)
set(HOME /home/robin/Linux/calc)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin/)
//包含头文件目录。
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(app ${SRC_LIST})
动态库与静态库
制作静态库
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
add_library(calc SHARED ${SRC_LIST)
最终生成对应的静态库文件libcalc.a
动态库文件 libcalc.so
设置动态库生成路径
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(calc SHARED ${SRC_LIST})
由于在Linux下生成的静态库默认不具有可执行权限,所以在指定静态库生成的路径的时候就不能使用EXECUTABLE_OUTPUT_PATH宏了,而应该使用LIBRARY_OUTPUT_PATH,这个宏对应静态库文件和动态库文件都适用。
链接静态库
link_directories(${PROJECT_SOURCE_DIR}/lib)
link_librarys(calc)
add_executable(app ${SRC_LIST})
链接动态库
# 指定源文件或者动态库对应的头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
#指定要链接的动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_executable(app ${SRC_LIST})
#指定要链接的动态库
target_link_library(app calc)
变量操作
变量追加
优势项目的源文件在多个目录中。如果我们通过file命令对各个目录下的源文件进行搜索,最后还需要做一个字符串拼接的操作
file(CLOB SRC_1 "${PROJECT_SOURCE_DIR}/src1/*.cpp")
file(CLOB SRC_2 "${PROJECT_SOURCE_DIR}/src2/*.cpp")
//对变量进行拼接
set(SRC_1 ${SRC_1} ${SRC_2})
//使用list进行拼接
list(APPEND SRC_1 ${SRC_1} ${SRC_2})
message(STATUS "message:${SRC_1")
字符串移除
我们在通过file搜索某个目录就得到了该目录下所有的源文件,但是其中有些源文件并不是我们所需要的
# 移除 main.cpp
list(REMOVE_ITEM SRC_1 ${PROJECT_SOURCE_DIR}/main.cpp)
关于list还有其他功能,但不常用。
宏定义
#include <stdio.h>
#define NUMBER 3
int main()
{
int a = 10;
#ifdef DEBUG
printf("我是一个程序猿, 我不会爬树...\n");
#endif
for(int i=0; i<NUMBER; ++i)
{
printf("hello, GCC!!!\n");
}
return 0;
}
cmake_minimum_required(VERSION 3.0)
project(TEST)
# 自定义 DEBUG 宏。这时在编译上面的代码时。则在代码中定义了DEBUG
add_definitions(-DDEBUG)
add_executable(app ./test.c)
打印出:是一个程序猿, 我不会爬树。
1 Cmake 概述
Cmake是一个项目构建工具,还有makefile,但是编写makefile工作量大。Cmake会自动生成makefile文件。
g++与gcc的区别:g++编译之后自带C++库文件。而gcc要显示添加。-lstdc++
下图为编译流程:1.预处理。2.编译 3.汇编 4.链接。
g++ -E main.cpp -o main.i //预处理
g++ -S main.i -o main.s //编译
g++ -c main.s -o main.o //汇编
g++ main.o -o main //链接
2. Cmake使用
2.1 注释
# 行注释
#[[块注释]]
2.2 执行Cmake命令
通常到当前文件夹新建文件夹build,在此文件夹下执行命令$ cmake …之后然后在执行make命令。这是生成的中间文件就在build文件夹中。
VSCode中使用Cmake
参考资料:
https://subingwen.cn/vscode/cpp-windows/?highlight=cmake
嵌套的CMake
如果项目很大,或者项目中有很多的源码目录。在通过CMake管理项目的时候如果只使用一个CMakeLists.txt。那么这个文件相对会比较复杂。这时我们可以给每个源码目录都添加一个CMakeLists.txt。这样每个文件都不会太复杂。而且更灵活。更容易维护。
# 添加子目录
add_subdirectory(calc)
目录架构。
- 根节点CMakeLists.txt中的变量全局有效。
- 父节点CMakeLists.txt中的变量可以在子节点中使用。
- 子节点CMakeLists.txt中的变量只能在当前节点中使用。
根目录的文件
cmake_minimum_required(VERSION 3.0)
project(root)
set(LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(EXEC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(HEAD_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(CALC_LIB calc)
set(SORT_LIB sort)
set(APP_NAME_1 test1)
set(APP_NAME_2 test2)
#添加子目录中的CMakeLists.txt文件。
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)
子目录的文件
calc中的文件
制作静态库文件
cmake_minimum_required(VERSION 3.0)
project(CALCLIB)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
set(LIBRARY_OUTPUT_PATH ${LIB_PATH})
add_library(${CALC_LIB} STATIC ${SRC})
test1的文件
链接静态库生成可执行文件
cmake_minimum_required(VERSION 3.0)
project(CALCTEST)
aux_source_directory(./ SRC)
include_directories(${HEAD_PATH})
link_directories(${LIB_PATH})
link_libraries(${CALC_LIB})
set(EXECUTABLE_OUTPUT_PATH ${EXEC_PATH})
add_executable(${APP_NAME_1} ${SRC})
现代Cmake
1基础
变量名 CMAKE_GENERATOR
变量值:MinGW Makei
在自己的build文件夹中输入终端命令
cmake -G “MinGW Makefiles” … //…表示上一文件夹。这里是CMakeLists.txt所在文件路径
cmake_minimum_required(VERSION 3.10)
project(Tutorial VERSION 2.11)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#在源文件中包含自己的项目名
configure_file(TutorialConfig.h.in TutorialConfig.h)
a
add_executable(Tutorial tutorial.cxx)
//输出自己先输出的内容
message(STATUS "Hello World form cmake")输出一个字符串
message(STATUS "${Tutorial_VERSION_MAJOR}")//输出项目版本号小数点之前
message(STATUS "${Tutorial_VERSION_MINOR}")//小数点之后
message(STATUS "${PROJECT_BINARY_DIR}")//项目构建目录,这里是自己的build目录
cmakedefine与define的区别
//#cmakedefine 与define的区别
//1.非0值,效果相同。当为0是camkedefien不会定义
//2.对于bool值也是一样的 。为真时,都会定义。为假时cmakedefine不会定义
//3.对于在CmakeLists.txt中为定义的变量define会
config.h.in
#define Tutorial_VERSION_MAJOR ${Tutorial_VERSION_MAJOR}
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#define STR_TEST "@STR_TEST@"
#cmakedefine USE_MATH ${USE_MATH}
CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(Tutorial VERSION 2.11)
#set的位置需要放在目标位置的前面
set(STR_TEST "Hello world")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#在源文件中能够读取CmakeLists.txt中的变量。
configure_file(TutorialConfig.h.in TutorialConfig.h)
#option为可选变量 ON/OFF TRUE/FALSE
option(USE_MATH "use my libmcalcu.a?" ON)
message(STATUS USE_MATH=${USE_MATH})
#添加Cmake子文件夹
if(USE_MATH)
add_subdirectory(MathFunctions)
#list里面的变量相当于字符串数组。
list(APPEND EXTRA_LIBS mycalcu)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
#生成可执行文件
add_executable(Tutorial mian.cpp)
#给目标链接库文件
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
# 目标的include文件夹 PROJECT_BINARY_DIR表示自己的build文件夹。
#PROJECT_SOURCE_DIR 表示自己的源文件目录,在两端加上双引号的目的是防止路径中空格的出现
target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES}
)
message(STATUS out-- "Hello World form cmake")
message(STATUS "${Tutorial_VERSION_MAJOR}")
message(STATUS "${Tutorial_VERSION_MINOR}")
main.cpp
#include<iostream>
#include"TutorialConfig.h"
#ifdef USE_MATH
#include"mycalcu.h"
#endif
int main(){
std::cout<<"Tutorial_VERSION_MAJOR:"<<Tutorial_VERSION_MAJOR<<std::endl;
std::cout<<"Tutorial_VERSION_MINOR:"<<Tutorial_VERSION_MINOR<<std::endl;
std::cout<<"STR:"<<STR_TEST<<std::endl;
#ifdef USE_MATH
std::cout<<"5*6="<<Multi(5,6)<<std::endl;
#endif
// char ch;
//std::cin>>ch;
return 0;
}