1. CMAKE:开源、跨平台的构建工具——指导编译器完成编译工作
1.1 为什么有CMake 这个鬼东西?
大丙CMake 教程上 大丙CMake 教程下 视频网站 这些都是很好的资料
出现的原因:
如果文件很多时,仅通过命令行的方式去编译和链接整个文件,过于麻烦。所以,我们需要去指导编译器按照我们想要的方式编译文件。
什么是构建工具:
CMake 是全自动完成代码编译、链接、打包的整个过程,同时管理不同组件和第三方库。
1.2 预备知识–简单介绍如GCC等编译器工具:
GCC 编译器对程序的编译下图所示,分为 4 个阶段:预处理(预编译)、编译和优化、汇编和链接。GCC 的编译器可以将这 4 个步骤合并成一个。 先介绍一个每个步骤都分别做了写什么事儿:
编译预处理(-E):在这个阶段主要做了三件事: 展开头文件 、宏替换 、去掉注释行,这个阶段需要 GCC 调用预处理器来完成,最终得到的还是源文件,文本格式.
编译(-S):这个阶段需要 GCC 调用编译器对文件进行编译,最终得到一个汇编文件。广义的编译是指,直接生成目标代码的过程 main.exe
汇编-c:这个阶段需要 GCC 调用汇编器对文件进行汇编,最终得到一个二进制文件
链接:这个阶段需要 GCC 调用链接器对程序需要调用的库进行链接,最终得到一个可执行的二进制文件。(例如,某个项目有两个文件,其中一个文件有着某个函数的实现,当另外一个文件使用函数时,两个文件之间会存在相互链接的情况)
.i 里面就是预处理后的代码。
一条语句前的注释 => 等长的空格;
一条语句中的注释 => 一个空格;
一条语句后的注释 => 直接删除;
1.3 CMake命令介绍
1.3.1 CMakeLists.txt 中的相关命令
注释:
CMakeLists.txt 文件里的注释使用#,多行注释使用 #[[注释块]]
版本限制:
cmake_minimum_required (VERSION 3.8)
指定最低版本。(非必须项目)
定义工程名称:
# PROJECT 指令的语法是:
project(name)
本工程支持的c++版本:
在编写C++程序的时候,可能会用到C++11、C++14、C++17、C++20等新特性,那么就需要在编译的时候在编译命令中制定出要使用哪个标准:C++标准对应有一宏叫做DCMAKE_CXX_STANDARD
通过set 指令,确立c++的标准如set(CMAKE_CXX_STANDARD 17)
add_executable:定义工程会生成一个可执行程序
add_executable(可执行程序名(无需写上.exe) 源文件名称(最好打上""))
add_executable(test "test.cpp") //范例
1.4 用vs打开工程文件
根据上面的内容,我们便可以写一个CMakeLists.txt文件,我们同时写一个main.cpp文件,内容就简单的输出hello,以下是相关具体情况:
# 需求的最低的cmake程序版本
cmake_minimum_required(VERSION 3.8)
#本工程的名字
project(test)
#本工程支持的c++版本
set(CMAKE_CXX_STANDARD 17)
#本工程主程序文件 和 输出程序名称
add_executable(softRenderer "main.cpp")
这样便用vs生成了一个简单的CMake文件。同时,我们打开文件需要稍等一会儿,vs需要解析一段时间。
打开后文件夹变成了这样:
其中的out文件夹,整个工程编译链接的结果的输出文件夹,包含我们的输出程序名称,也就说如果我们用cmd,直接打开softRenderer.exe,文件便可以执行!
1.5 如果想要继续添加文件,实现多文件编译该怎么做?
我想继续加一个文件如 func.cpp文件,这并不困难,甚至编译器会帮我们完成,要是加上十几个文件?
add_executable(softRenderer "main.cpp“ ”name1“ "name2" "name3" ...)
CMake中为我们提供了搜索文件的命令,可以使用aux_source_directory命令,
aux_source_directory(< dir > < variable >)
意思是命令查找某个路径下的所有源文件,将搜索到的源文件列表存储到该变量中。
例如,我们写成这样 aux_source_directory(. SRCS)
,在当前目录下查找源文件,存储到该变量中SRCS。
这样改会带来了一个问题,就是这个地方也得改,因为我们要编译多个文件了,把add_executable(softRenderer "main.cpp")
改为 add_executable(softRenderer ${SRCS})
将列表下文件全部编译。
所以CMakeLists.txt变成这样:
# 需求的最低的cmake程序版本
cmake_minimum_required(VERSION 3.8)
#本工程的名字
project(test)
#本工程支持的c++版本
set(CMAKE_CXX_STANDARD 17)
# 搜索所有的源文件,加入SRCS变量中
aux_source_directory(. SRCS)
#本工程主程序文件 和 输出程序名称
add_executable(softRenderer ${SRCS})
main函数变为这样:
#include <iostream>
#include "func.h"
int main(){
std::cout << "hello" << std::endl;
std::cout << add(2, 4) << std::endl;
return 0;
}
func.cpp 文件为:
#include "func.h"
int add(int a, int b) {
return a + b;
}
func.h文件为:
#pragma once
int add(int a, int b);
1.6 多文件夹该怎么编译?
需求:当源文件分布在不同的文件夹下的时候,需要将其他文件夹下的cpp打包为lib库,纳入链接范围。
解决办法:
首先,每一个CMakelists.txt 文件只会管理当前文件夹的内容,如果其他文件有需要被编译的文件,我们需要再新的文件夹里建立一个新的CMakelists.txt去编译链接。
1. 新的文件CMakelists.txt 文件的书写:
file(GLOB_RECURSE 变量名 要搜索的文件路径 文件类型)
比如这样写file(GLOB_RECURSE FUNC ./ *cpp)
其中的GLOB_RECURSE
递归搜索(子目录文件也将包含) 指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。- 将列表中的文件编译为库。
add_library(name ${变量名})
add_library(库名称 源文件1 [源文件2] …) 编译为库,为后续链接可执行文件。
# 递归将本文件夹下的所有的.cpp文件放到
file(GLOB_RECURSE FUNC ./ *.cpp)
# 将FUNC中所有cpp文件编译为func这个lib库
add_library(func ${FUNC})
2. 在原来的CMakelists.txt修改:
- 第一,新的文件夹需要纳入到编译系统中来:
add_subdirectory(文件夹名字)
- 第二,编译好的动态库需要和目标代码进行链接:
target_link_libraries(softRenderer 动态库名称)
# 需求的最低的cmake程序版本
cmake_minimum_required(VERSION 3.8)
#本工程的名字
project(test)
#本工程支持的c++版本
set(CMAKE_CXX_STANDARD 17)
#func文件夹纳入到编译系统当中
add_subdirectory(func)
# 搜索所有的源文件,加入SRCS变量中
aux_source_directory(. SRCS)
#本工程主程序文件 和 输出程序名称
add_executable(softRenderer ${SRCS})
#将func.lib 链接入softRenderer
target_link_libraries(softRenderer func)
1.7 资源文件参与链接和引用:
需求:
当我们工程文件中出现资源文件(图片、模型、音频、动态链接库)需要被exe文件读取和链接。
解决办法:
首先,咱们把指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。然后,将变量中的内容都拷贝到可执行文件的目录下。(target 编译目录)
- file(GLOB name 要搜索的文件路径 文件类型) 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
- file(COPY ${name} DESTINATION $(CMAKE_BINARY_DIY)) 其中的copy是赋值的意思,destination 目标文件目录 【就全是大写,感觉很离谱,头疼】CMAKE_CURRENT_BINARY_DIR 是宏指的是 target 编译目录。
# 需求的最低的cmake程序版本
cmake_minimum_required(VERSION 3.8)
#本工程的名字
project(test)
#本工程支持的c++版本
set(CMAKE_CXX_STANDARD 17)
#func文件夹纳入到编译系统当中
add_subdirectory(func)
#把需要拷贝的路径资源生成列表
file(GLOB ASSETS "./ assets" )
#把ASSETS列表拷贝到可执行文件的目录下
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR})
# 搜索所有的源文件,加入SRCS变量中
aux_source_directory(. SRCS)
#本工程主程序文件 和 输出程序名称
add_executable(softRenderer ${SRCS})
#将func.lib 链接入softRenderer
target_link_libraries(softRenderer func)
我们不运行文件,直接将修改的CMakeLists.txt文件保存,就可以在out->build->x64-debug中看见assets文件复制过来了。
1.8 多个编译目标:
需求:项目里面有多个main文件,可以自由选择编译文件。
很简答 直接再加上一句 add_executable(main2 "main2.cpp")
在这里插入图片描述