cmake之旅(1)

张开发
2026/5/29 12:46:32 15 分钟阅读
cmake之旅(1)
cmake之旅11 构建的过程2 手动构建2.1 环境2.2 开始编译3 使用 Makefile 简化构建3.1 环境3.2 编写Makefile4 使用cmake构建4.1 环境4.2 编写CMakeLists.txt同系列文章cmake之旅(1):构建的过程cmake之旅(2):CMakeLists.txt 核心语法cmake之旅(3):多目录项目管理cmake之旅(4):静态库与动态库cmake之旅5):函数、宏与 .cmake 模块cmake之旅6查找和使用第三方库cmake之旅7编译选项与条件编译cmake之旅8Modern CMake 与 target 思维1 构建的过程我们先写一个简单的的程序#includeiostreamintmain(){std::coutHello Cmakestd::endl;return0;}上面程序会在控制台中输出Hello Cmake那么如何运行上面的代码呢你可能会说在vs或者其他的IDE中创建一个项目创建一个main.cpp把上面的代码复制进行然后点击运行就好了呀。是的没错那么我们思考一下我们点击运行按钮到控制台输出结果vs在这个过程中,帮我们“偷偷的”的做了哪些事情vs大概帮助我们做了以下内容预处理、编译、优化、汇编、链接、生成可执行文件、 加载与调试、运行程序、退出与清理不得不感叹这些IDE的方便性只要点击一个按钮就做了那么多步骤。但是我们现在就是要“化简为繁”手动的做这些事情。亲自感受一下这个过程这有利于我们后面对cmake的理解。上面的内容可以分为两个过程构建过程、运行过程。我们只讲一下构建的过程预处理宏替换所有使用 #define 定义的宏在代码中被替换为它们对应的值或代码片段。文件包含#include 指令包含的头文件会被直接插入到代码中。这意味着编译器会将这些头文件的内容复制到使用 #include 指令的地方。条件编译处理 #ifdef、#ifndef、#if 等条件编译指令。这些指令允许根据某些条件编译或忽略代码块。去注释预处理器会删除所有的注释因为它们在编译阶段是不需要的。编译词法分析编译器将预处理后的代码转换为一个个“记号”token。每个记号表示代码中的基本元素如关键字、标识符、运算符、数字和符号。语法分析编译器检查代码的语法结构确保它符合语言的语法规则。语法分析器生成一个抽象语法树AST这是源代码结构的层次化表示。语义分析编译器进一步检查代码的语义正确性例如类型检查、变量和函数的作用域解析、函数参数匹配等。中间代码生成编译器将语法树转换为中间代码这通常是一种接近机器语言但仍然与具体机器无关的代码形式如三地址码或简单的指令集。优化中间代码可以被优化例如移除多余的计算、循环展开、常量折叠、消除冗余代码等。这一步可以在中间代码层进行也可以在生成机器代码后进行。汇编汇编代码生成Assembly Code Generation编译器将中间代码转换为汇编代码这是一种特定于目标处理器的低级别代码。汇编代码仍然是人类可读的但每条指令直接对应于机器指令。机器代码生成Machine Code Generation汇编器将汇编代码转换为二进制的机器代码这些代码是计算机直接可以执行的指令。这些机器代码通常存储在目标文件.obj 或 .o 文件中。链接符号解析Symbol Resolution链接器处理所有的外部符号引用将每个函数调用和变量引用与其实际定义关联起来。比如一个文件中调用的函数可能在另一个文件中定义链接器负责将这些调用和定义匹配。重定位Relocation链接器调整每个目标文件中的地址和指针使得它们在最终的可执行文件中是正确的。这一步包括调整代码和数据的内存地址使得程序可以正确地在运行时访问它们。库链接Library Linking如果你的程序依赖于静态库或动态库链接器会将这些库的代码合并到最终的可执行文件中。对于静态库库的代码被直接包含在可执行文件中对于动态库只会在运行时加载库的代码。生成可执行文件最终链接器将所有的目标文件和库文件组合在一起生成一个完整的可执行文件如 .exe 文件这个文件包含了所有必要的代码和数据。2 手动构建2.1 环境系统Ubuntu编译器gcc/g2.2 开始编译创建文件touch main.cpp将上述代码复制到其中并保存预处理g -E main.cpp -o main.i-E 选项告诉编译器只进行预处理不进行后续的编译、汇编和链接步骤。-o main.i 指定了预处理后的输出文件名为 main.i。如果不使用 -o 选项预处理结果会输出到标准输出通常是终端根据前面的讲解我们在代码中加点内容加一个宏和注释来验证上面的说法#includeiostream#defineNUM12intmain(){//注释std::coutHello Cmakestd::endl;std::coutNUMstd::endl;return0;}此时重新运行上面的命令你可以再文件夹下面看到一个main.i文件可以打开mian.i下拉到文件底部里面生成了那些东西。你会看到头文件被加载了进来宏被替换了注释被去掉了编译:g -S main.i -o main.s-S 选项表示将源代码编译为汇编代码。生成的 main.s 文件是汇编语言表示的代码可以查看其中的低级指令汇编g -c main.s -o main.o-c 选项表示将汇编代码编译为目标文件而不进行链接。生成的 main.o 是二进制的机器代码包含了程序的指令但还没有链接成可执行文件。链接g main.o -o main链接阶段将目标文件与标准库链接生成最终的可执行文件。运行./main经过上面的步骤应该就可以成功的生成可执行文件并运行起来。你可能已经发现了这样很麻烦而且现在只是一个main.cpp文件就要那么多步骤如果文件很多呢比如增加add.h、add.cpp、de.hde.cpp文件结构如下├──add│ ├── add.cpp │ └── add.h ├── de │ ├── de.cpp │ └── de.h ├── main.cpp └── Makefileadd.h:#ifndef_HEAD_ADD_#define_HEAD_ADD_intadd(inta,intb);#endifadd.cpp#includeadd.hintadd(inta,intb){returnab;}de.h#ifndef_HEAD_DE_#define_HEAD_DE_intde(inta,intb);#endifde.cpp#includede.hintde(inta,intb){returnb-a;}main.cpp#includeiostream#includeadd.h#includede.h#defineNUM12intmain(){//注释std::coutHello Cmakestd::endl;std::coutNUMstd::endl;std::coutadd(10,2) de(2,10)std::endl;return0;}构建过程g-cadd/add.cpp-oadd/add.o g-cde/de.cpp-ode/de.o g-cmain.cpp-Iadd-Ide-omain.o g main.o add/add.o de/de.o-omain ./main随着文件增多会越来越麻烦而且容易出错。3 使用 Makefile 简化构建3.1 环境系统Ubuntu编译器gcc/g构建工具make3.2 编写Makefile使用makefile构建首先要在自己的电脑上安装make网上有很多方法不再赘述然后编写Makefile文件。编写Makefile文件的过程和上面手动构建的过程类似具体内容有详细注释增加Makefile文件├──add│ ├── add.cpp │ └── add.h ├── de │ ├── de.cpp │ └── de.h ├── main.cpp └── MakefileMakefile文件# 定义编译器CXXg# 定义编译选项CXXFLAGS-Wall-g# 定义目标文件名TARGETmain# 自动寻找当前目录及子目录下的所有.cpp文件SRCS$(wildcard */*.cpp)$(wildcard *.cpp)# 自动生成对应的.o文件OBJS$(SRCS:.cpp.o)# 包含的头文件目录INCLUDES-Iadd-Ide# 默认目标生成可执行文件$(TARGET):$(OBJS)$(CXX)$(CXXFLAGS)$(INCLUDES)-o$(TARGET)$(OBJS)# 生成对象文件的规则%.o: %.cpp$(CXX)$(CXXFLAGS)$(INCLUDES)-c$-o$# 清理目标clean:rm-f$(OBJS)$(TARGET)直接make就可以生成对应的文件了而且比之前更加的通用一点。相信你通过这个一步一步走下来肯定发现了它的不足如果项目不断的增大每个源文件的依赖不同使用makefile管理这些依赖就变得很困难后期维护的困难大大的增加每次都要理清这里面的依赖关系不能跨平台比如此时想将上面的代码在win上运行使用makefile很困难命令和工具差异Makefile 中使用的 g、rm 等命令通常在类 Unix 系统如 Linux 或 macOS上可用而 Windows 上的命令行工具有所不同。rm 是 Linux 下的命令用于删除文件但在 Windows 上并不存在。Windows 使用 del 或 erase 来删除文件。路径分隔符Makefile 中使用的路径分隔符是正斜杠 /而在 Windows 上路径分隔符通常是反斜杠 \。虽然某些工具如 g在 Windows 上也支持正斜杠但这并不是通用的标准。构建工具make 是 GNU 工具链的一部分默认在 Windows 上不可用。虽然你可以通过安装 MinGW、Cygwin 或 MSYS2 等工具在 Windows 上使用 make但这依然需要额外的配置环境变量Windows 上的环境变量设置和类 Unix 系统不同可能需要调整编译器路径、库路径等。有没有一个更好方法既不用繁琐的写着构建过程还可以自动处理依赖关系自动寻找第三方的库4 使用cmake构建CMake 是一个跨平台的构建系统生成器它可以根据简单的配置文件CMakeLists.txt自动生成适用于多种构建系统的文件比如 Unix 系统上的 MakefileWindows 上的 Visual Studio 项目文件等。优势自动处理依赖关系CMake 自动管理源文件之间的依赖关系只重新编译发生变化的部分。跨平台支持CMake 可以生成适用于不同操作系统的构建文件从而实现真正的跨平台构建。轻松集成第三方库CMake 可以帮助你自动查找和集成第三方库而不需要手动配置路径和编译选项。社区资源丰富有很丰富的社区和学习资料4.1 环境Ubuntu安装sudo apt-get install cmakewinhttps://cmake.org/download/自行百度如何安装。4.2 编写CMakeLists.txt# 设定最低版本要求cmake_minimum_required(VERSION3.10)# 定义项目名称project(HelloCMake)# 设置编译选项set(CMAKE_CXX_STANDARD11)set(CMAKE_CXX_STANDARD_REQUIRED True)# 添加源文件set(SOURCES main.cpp add/add.cpp de/de.cpp)# 包含头文件目录include_directories(add de)# 生成可执行文件add_executable(main${SOURCES})执行以下命令就可以生成可执行文件了mkdirbuildcdbuild cmake..make非常的简洁明了不用我们手动管理依赖也可以实现跨平台。通过上面的内容应该对cmake有了基本了解。

更多文章