当前位置: 首页 > news >正文

C++之 CMake、CMakeLists.txt、Makefile

这两者的关系其实非常好理解,我们可以用一个**“盖房子”**的例子来打比方。

简单来说:CMake 是“设计师”,Makefile 是“施工图纸”,Make 是“施工队”。

🏠 直白的大白话解释

想象你要盖一栋房子(编译一个 C++ 项目):

  1. CMakeLists.txt(你的需求)
    这是你写给设计师的需求文档。你在上面写:“我要一个 3 室 2 厅的房子,要有落地窗,风格要现代。”(这对应你的项目配置:我要用 C++17,我有 main.cpp 和 utils.cpp 这些文件,我要链接 OpenGL 库)。

  2. CMake(设计师/翻译官)
    CMake 读取你的需求文档(CMakeLists.txt),然后根据你的环境(你是住在 Linux 还是 Windows?)画出了一套详细的施工图纸Makefile)。

    • 如果你在 Linux,它会画出适合 Linux 的图纸。
    • 如果你在 Windows,它会画出适合 Windows 的图纸(比如 Visual Studio 的项目文件)。
  3. Makefile(施工图纸/说明书)
    这是一份非常详细的操作指南。上面写着:“第一步,先倒水泥;第二步,砌墙;第三步,刷漆。”(这对应具体的编译命令:先用 g++ 编译 main.cpp 生成 main.o,再链接…)。注意:Makefile 自己不会干活,它只是被阅读的。

  4. Make(施工队/工头)
    Make 是一个工具,它拿着Makefile(施工图纸),指挥具体的工人(编译器 g++)去干活。它会检查:“墙是不是已经砌好了?没砌好就赶紧砌,砌好了就不用管了。”


🔗 它们的具体关系

  • CMake 生成 Makefile
    CMake 的工作就是Makefile。当你运行cmake .时,它就在帮你生成这个文件。
  • Make 执行 Makefile
    Make 的工作是Makefile。当你运行make时,它按照 Makefile 里的指令去调用编译器。

🆚 为什么要用 CMake,直接写 Makefile 不行吗?

行,但是太累了。

  • 手写 Makefile
    就像你自己画施工图纸。如果房子只有 10 平米(几个文件),你自己画很快。但如果要盖摩天大楼(几千个文件,复杂的依赖),或者你要在不同的地方盖(Linux、Windows、Mac),手写图纸会累死人,而且容易出错。
  • 用 CMake
    你只需要写一份需求文档(CMakeLists.txt)。不管你要盖什么房子,不管在哪里盖,CMake 都能自动帮你生成对应的图纸。

📌 总结

  • CMake:是跨平台的构建生成器。它负责把“人话”(配置)翻译成“机器话”(Makefile)。
  • Makefile:是构建脚本。它记录了具体的编译步骤。
  • Make:是执行工具。它负责执行 Makefile 里的命令。

你的工作流程通常是:
CMakeLists.txt-> 运行cmake生成Makefile-> 运行make编译代码。

# 指定 CMake 的最低版本要求cmake_minimum_required(VERSION3.10)# 定义项目名称和版本project(main VERSION1.0)# 设置 C++ 标准为 C++17,并要求编译器必须支持set(CMAKE_CXX_STANDARD17)set(CMAKE_CXX_STANDARD_REQUIRED ON)# 导出编译命令数据库,方便 VSCode 的 C/C++ 插件进行代码分析set(CMAKE_EXPORT_COMPILE_COMMANDS ON)# 添加头文件搜索路径include_directories(${PROJECT_SOURCE_DIR}/include)# 收集 src 目录下的所有 .cpp 源文件file(GLOB SOURCES"${PROJECT_SOURCE_DIR}/src/*.cpp")# 定义要生成的可执行文件及其源文件add_executable(${PROJECT_NAME}${SOURCES})# 设置输出路径set_target_properties(${PROJECT_NAME}PROPERTIES RUNTIME_OUTPUT_DIRECTORY${PROJECT_SOURCE_DIR}/bin)

这份CMakeLists.txt写得非常规范且现代,比上一版更健壮。特别是你使用了set_target_properties来指定输出路径,这是比旧版EXECUTABLE_OUTPUT_PATH更推荐的做法。

下面我为你逐行拆解每一行代码、关键字的含义,并结合你E:/C++11这个项目给出它们实际对应的值。


核心配置部分

cmake_minimum_required(VERSION 3.10)
  • 含义:声明运行此 CMake 脚本所需的最低版本。如果用户的 CMake 版本低于 3.10,CMake 会报错并停止运行。
  • 作用:确保脚本中使用的语法特性在当前环境中受支持。
  • 当前状态:你的电脑上安装的 CMake 版本必须 ≥ 3.10。
project(main VERSION 1.0)
  • 含义:定义项目名称和版本号。这是 CMake 脚本中最重要的指令之一,它会初始化一系列变量。
  • 关键字
    • main:这是你给项目起的名字。
    • VERSION 1.0:项目的版本号。
  • 生成的变量
    • PROJECT_NAME:值为"main"
    • PROJECT_VERSION:值为"1.0"
    • PROJECT_SOURCE_DIR:值为"E:/C++11"(即包含此文件的根目录)。
set(CMAKE_CXX_STANDARD 17)
  • 含义:告诉 CMake 使用 C++17 标准来编译代码。
  • 作用:相当于在 g++ 编译器后面加了-std=c++17参数。这让你可以使用现代 C++ 的特性(如autofilesystem等)。
set(CMAKE_CXX_STANDARD_REQUIRED ON)
  • 含义:强制要求编译器支持 C++17。
  • 作用:如果编译器太老(不支持 C++17),CMake 会直接报错,而不是悄悄降级使用旧标准(如 C++98),避免莫名其妙的编译错误。
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
  • 含义:生成compile_commands.json文件。
  • 作用:这个文件包含完整的编译命令。VSCode 的 C/C++ 插件读取它,就能精准地知道头文件在哪里、宏定义是什么,从而提供完美的代码跳转和补全功能。

源文件与路径配置

include_directories(${PROJECT_SOURCE_DIR}/include)
  • 含义:添加头文件搜索路径。
  • 关键字
    • include_directories:指令,用于指定头文件目录。
    • ${PROJECT_SOURCE_DIR}:变量引用,取值为"E:/C++11"
  • 实际路径E:/C++11/include
  • 作用:当你在代码中写#include <myheader.h>时,编译器会去这个目录下查找。
file(GLOB SOURCES "${PROJECT_SOURCE_DIR}/src/*.cpp")
  • 含义:使用通配符查找文件。
  • 关键字
    • file(GLOB ...):文件操作指令,用于匹配文件路径。
    • SOURCES:你自定义的一个变量名,用来存放找到的文件列表。
    • "${PROJECT_SOURCE_DIR}/src/*.cpp":匹配规则。
  • 实际值:假设你src文件夹里有main.cpptest.cpp,那么SOURCES变量的值就是"E:/C++11/src/main.cpp;E:/C++11/src/test.cpp"
  • 注意:这种方式会自动把src下所有.cpp加入编译,不用每次新增文件都改 CMake 文件,很方便。
add_executable(${PROJECT_NAME} ${SOURCES})
  • 含义:定义一个可执行文件目标。
  • 关键字
    • add_executable:指令,生成.exe(Windows)或无后缀可执行文件(Linux)。
    • ${PROJECT_NAME}:值为"main",这是生成的程序的名字。
    • ${SOURCES}:值为上面file(GLOB ...)找到的所有.cpp文件。
  • 作用:告诉 CMake:“请把SOURCES里的这些代码编译成一个叫main的程序”。

输出路径配置(关键点)

set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
  • 含义:设置特定目标的属性。这里专门设置“运行时输出目录”。
  • 关键字
    • set_target_properties:指令,用于精细化控制目标的属性。
    • ${PROJECT_NAME}:目标名,即"main"
    • PROPERTIES:关键字,后面跟属性名和值。
    • RUNTIME_OUTPUT_DIRECTORY:属性名,专门控制可执行文件(.exe)的输出位置。
    • ${PROJECT_SOURCE_DIR}/bin:属性值,即"E:/C++11/bin"
  • 为什么比旧版好?
    • 旧版(EXECUTABLE_OUTPUT_PATH)是全局变量,会影响项目里所有的可执行文件。
    • 新版(你用的这个):只针对名为main的这个程序生效。如果你的项目将来变大了,包含多个程序,你可以分别为它们设置不同的输出目录,互不干扰。

总结

你的这份 CMake 脚本逻辑非常清晰:

  1. 定标准:要求 CMake 3.10+,使用 C++17。
  2. 找文件:自动扫描src下的代码,指定include目录。
  3. 生程序:编译生成名为main的程序。
  4. 定位置:把生成的程序扔进E:/C++11/bin文件夹里。

这套配置在 Windows 和 Linux 下通用,直接运行CMake: Build即可。

http://www.jsqmd.com/news/706386/

相关文章:

  • 1985-2025.12最新亿量级裁判文书全量数据
  • 医疗AI多智能体系统:架构、实现与安全实践
  • 土地抵押数据库2000-2021年
  • MCP AI推理配置终极检查清单(含CUDA版本兼容矩阵+TensorRT 8.6适配表)
  • Qianfan-OCR代码实例:Python调用API实现批量PDF图像文字提取
  • 终极指南:ComfyUI-Manager依赖安装的完整解决方案与性能优化
  • Venera漫画阅读器:从入门到精通的完整使用手册
  • BabyAGI 架构详解
  • 手把手教你完成OpenClaw飞书绑定(含最新版安装包)
  • 导航参数的精细化管理
  • 机器学习中类别特征编码的3种核心方法与选择策略
  • 多智能体强化学习论文资源导航:从入门到精通的学术地图
  • OpenEuler文件被锁定的解决方法|网卡修改不生效的解决办法
  • 2.9 会话、窗口站、桌面和窗口消息:图形界面背后的“分层舞台”
  • MCP 2026适配不是选型问题,而是生存问题:2026Q2起未达标设备将被禁止接入省级工业互联网平台
  • Kubernetes v1.24 高可用集群安装教程(基于 containerd + Flannel)
  • C语言进阶篇(文件操作)
  • 基于多模态大模型与智能体协作的像素艺术生成技术实践
  • 设备检测库device-detector:从UA解析到精细化运营的实战指南
  • 2026年人力资源数据分析的技术价值与应用前景
  • 第五章-05-练习案例:升级版自动查核酸
  • 2015-2025年地级市公共安全基建省内横向压力
  • 2026专业户外路灯TOP5推荐:LED路灯、乡村路灯、农村太阳能路灯、太阳能路灯安装、太阳能路灯工厂、太阳能路灯批发选择指南 - 优质品牌商家
  • WebCanvas:可视化AI工作流引擎的设计与实现
  • Windows更改远程桌面3389端口
  • 基于Node.js与Vue 3的轻量级服务器监控仪表盘实战
  • 安装OpenCV-Python 3.4.1.15和opencv-contrib-python 3.4.1.15,并将anaconda prompt创建的python3.6虚拟环境加到pycharm中
  • AI应用开发实战指南:从架构设计到生产部署的完整路径
  • 2026义乌正规诉讼律师机构名录:义乌离婚诉讼咨询、义乌诉讼律师公司、义乌刑事离婚律师、义乌律师公司、义乌离婚律师公司选择指南 - 优质品牌商家
  • 【SSD202 开发实战 18】JPEG 编解码与图片处理