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

Make 与 CMake:从手动编译到自动构建

视频学习资源

构建

在软件开发中,构建是指将源码文件和资源文件转换成可以运行的应用程序的过程

image-20260531204647660

构建通常会包括编译、链接、打包和部署等步骤。当只有一个源文件的时候我们可以直接使用一些编译器的指令,来手动完成构建的过程

比如可以使用gcc来编译一个C语言的源文件

$ gcc hello.c -o hello

或者使用javac来编译一个Java的源文件

$ javac hello.java

但项目庞大且复杂时,源文件、头文件和库文件有成百上千个时,手动编译就不现实了。这个时候就可以借助一些自动化的构建工具,来完成整个构建过程。

image-20260531204524918

不同平台会使用不同的构建工具,比如Make、CMake和Maven等等

下面介绍C语言项目中最常用的构建工具Make和CMake的基本用法

我们从一个最简单的场景说起:当你只有两个源文件 main.chello.c 时,一条 gcc main.c hello.c -o hello 就足够了。但当源文件变成几十上百个,并且分散在不同目录,还要链接不同的库,直接用 gcc 命令就会变得极其痛苦。

于是,自动化构建工具出现了。

1. Make 是什么?

Make 是一个经典的构建工具,它通过读取一个叫做 Makefile 的文件来确定:

  • 哪些文件需要先编译
  • 哪些文件需要重新编译
  • 如何执行编译链接命令

核心思想就是依赖管理增量构建:只有当源文件比目标文件“更新”时,才重新构建,避免每次都全量编译。

1.1 Makefile 的基本语法

Makefile 由一系列 规则(rule) 组成:

目标(target): 依赖(prerequisites)命令(recipe)

总的就是说两件事:

  • 第一行:文件的依赖是什么
  • 第二行:如何生成这个文件

注意:命令前必须是 Tab 键,不能用空格替代。

例如,一个极简的 Makefile:

hello: main.o hello.ogcc main.o hello.o -o hellomain.o: main.cgcc -c main.chello.o: hello.cgcc -c hello.cclean:rm -f hello *.o
  • hello 是最终要生成的可执行文件名字,它依赖于 main.ohello.o

  • main.o 依赖于 main.c,命令 gcc -c main.c 负责生成它

  • clean 是一个伪目标,用于清理生成的文件

    关于伪目标的理解:

    有的时候我们可能会需要执行一些并不生成文件的操作,比如清理临时文件,生成文档,打包等等,这个时候就是使用伪目标来定义这些规则。伪目标就是一个不生成文件的目标。他只是个标签,用来执行这些操作

    那在后续执行的时候在make后面带赛clean就会执行。这样就会删除所有.o文件

    make clean
    

    需要注意的地方:如果我们本地目录下有文件的文件名是clean,那么make clean的命令就会失效,因为这是make把clean当成文件名处理了。这种情况下我们在第一行显示的告诉Make这个clean是个伪目标

    .PHONY: cleanhello: main.o hello.ogcc main.o hello.o -o hello
    

    其他伪目标

    • all:但我们执行make时,Make会默认执行第一个规则,但是如果我们想要生成的目标文件不止一个的话,就可以使用all这个伪命令。示例如下,然后执行命令make all【当all是第一条规则时,如本例,可以直接make,不用带all】即可自己也会显示我们的提示信息“all done”

      .PHONY clean allall: hello worldecho "all done"hello: main.o hello.ogcc main.o hello.o -o helloworld: main.o hello.ogcc main.o hello.o -o hellomain.o: main.cgcc -c main.chello.o: hello.cgcc -c hello.cclean:rm -f hello *.o
      

执行 make 时,默认会找到第一个目标 hello,并根据依赖关系逐层构建。如果我们只改了 main.cmake 只会重新编译 main.o 并重新链接 hello

理解

大家应该知道这样写也是可以的,但是这看似省事,但并不在工程中引用

hello: main.c hello.cgcc main.c hello.c -o hello

因为如果这样写的话无论哪个文件有更新,都要重新编译这两个文件,这是因为我们省区了生成中间文件【.o文件】的步骤。实际中,更加规范和标准的做法是将编译和链接分开来写。也就是上面示例的写法。

1.2 使用变量和自动推导

重复写文件名和命令很容易出错,我们可以用变量自动变量简化:

CC = gcc
CFLAGS = -Wall -g
TARGET = hello
OBJS = main.o hello.o$(TARGET): $(OBJS)$(CC) $^ -o $@main.o: main.c$(CC) $(CFLAGS) -c $<hello.o: hello.c$(CC) $(CFLAGS) -c $<clean:rm -f $(TARGET) *.o
  • $@ 代表目标文件(hello
  • $^ 代表所有依赖文件(main.o hello.o
  • $< 代表第一个依赖文件(main.chello.c

更激进地,Make 还能用模式规则(利用通配符)自动推导 .c.o 的编译命令,最终简化为:

CC = gcc
CFLAGS = -Wall -g
TARGET = hello
OBJS = main.o hello.o$(TARGET): $(OBJS)$(CC) $^ -o $@%.o: %.c$(CC) $(CFLAGS) -c $<clean:rm -f $(TARGET) *.o

到这里,你已经能看懂绝大多数手写的 Makefile 了。


2. 为什么还需要 CMake?

手写 Makefile 有两个痛点:

  1. 跨平台困难。Make 的语法在 Windows 下需要 NMake 或 MinGW,命令和路径处理各不相同。
  2. 项目规模一大,依赖关系、子目录、库查找、安装等会让 Makefile 变得极其臃肿。

CMake 应运而生:它不直接构建项目,而是生成构建文件(例如 Unix 下的 Makefile,Windows 下的 Visual Studio 工程,或者 Ninja 文件)。也就是说,CMake 是一层更高阶的抽象,我们写 CMakeLists.txt,CMake 帮我们生成平台相关的构建配置。

3. CMake 的核心概念

3.1 一个最小的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(Hello)add_executable(hello main.c hello.c)

三行代码就能构建一个可执行文件,比手写 Makefile 简单得多。这里做的事情:

  • 声明 CMake 最低版本要求
  • 定义项目名称
  • 添加一个名为 hello 的可执行文件,由 main.chello.c 编译生成

3.2 构建流程

通常使用 外部构建(out-of-source build),让生成的临时文件与源码分离:

mkdir build
cd build
cmake ..
make

cmake .. 会读取上层目录的 CMakeLists.txt,并在 build 目录下生成 Makefile,之后 make 完成编译。如果需要用其他生成器,可以指定:
cmake -G "Visual Studio 17 2022" ..

3.3 常用的 CMake 命令与变量

以下示例涵盖了实际项目中常见的操作:包含目录、添加库、链接库等。

cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0.0 LANGUAGES CXX)# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 添加子目录(通常用于管理多个模块)
add_subdirectory(src)# 收集源文件(更灵活的方式)
file(GLOB_RECURSE SOURCES src/*.cpp src/*.h)# 生成可执行文件
add_executable(myapp ${SOURCES})# 将头文件目录提供给编译器
target_include_directories(myapp PRIVATE include)# 添加一个库(STATIC/SHARED)
add_library(mylib STATIC lib/mylib.cpp)# 将库链接到可执行文件
target_link_libraries(myapp PRIVATE mylib)

常用变量:

变量 含义
CMAKE_SOURCE_DIR 顶层 CMakeLists.txt 所在目录
CMAKE_BINARY_DIR 执行 cmake 的 build 目录
PROJECT_NAME 当前项目名称
CMAKE_CXX_STANDARD 使用的 C++ 标准

作用域关键字 PUBLICPRIVATEINTERFACE 用于精确控制头文件/库的传播范围,是与现代 CMake 紧密相关的重点,后面进阶学习时会经常遇到。

3.4 查找外部库

用 CMake 查找系统中的库非常方便:

find_package(OpenCV REQUIRED)
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS})
target_include_directories(myapp PRIVATE ${OpenCV_INCLUDE_DIRS})

通过 find_package,CMake 会自动根据模块或配置文件寻找库的位置并设置好对应的变量。

4. 对比总结

特性 Make CMake
语言 Makefile(自己的语法) CMakeLists.txt(高层 DSL)
跨平台 依赖 Make 实现 (GNU/nmake) 生成不同平台的构建文件
增量构建 支持 继承底层构建工具(如 Make)
依赖管理 手动指定 内置查找模块、包管理(FetchContent等)
可读性 小项目清晰,大项目繁杂 结构清晰,模块化程度高

一句话理解:Make 直接告诉编译器该怎么做,CMake 先帮你生成“该怎么做”的说明书,然后再交给 Make 或其他工具去执行。

5. 实战小抄:从读懂到会用

看懂 Makefile 的检查点

  • 寻找第一个目标(默认构建目标)
  • 关注变量定义和 $(...) 引用
  • 理解 $@, $^, $< 的含义
  • 看到 %.o: %.c 就是模式规则,自动处理同类型文件

看懂 CMakeLists.txt 的检查点

  • add_executableadd_library 是构建核心
  • target_link_librariestarget_include_directories 决定编译和链接的依赖关系
  • find_package 负责查找外部依赖
  • set(...) 用于设置变量和选项
  • 注意 if(), else(), endif() 的逻辑分支以及循环

当你能够顺畅阅读这两种代码时,就已经拿到了理解大型 C/C++ 项目构建体系的第一把钥匙。后续无论是自己写库还是接手遗留项目,都能从构建脚本中快速摸清脉络。

http://www.rkmt.cn/news/1440186.html

相关文章:

  • OpencvSharp 算子学习教案之 - Cv2.SetNumThreads
  • Oracle EBS 的资产模块(Fixed Assets, FA)本质上是一个“基于策略驱动、账簿隔离、全生命周期可追溯”的财务引擎
  • XZ3621宽输入电压范围:4V至30V 3A 130kHz电流输出同步降压稳压器
  • 2026年 江苏厂房降温/车间降温设备推荐榜单:冷风机/工业冷风机/移动式冷风机/负压风机/镀锌板厂房风机/玻璃钢负压风机/永磁负压风机品质之选 - 品牌企业推荐师(官方)
  • Ava Studio 技术架构与短视频广告批量生成原理解析
  • attention 的mask 的简单实现
  • ChatGPT核心原理、高阶应用与提示词实战指南
  • 变更管理在软考中级系统集成项目管理工程师考试中占多少分 - 众智商学院官方
  • 【Gemini推送通知优化实战指南】:20年专家亲授5大性能瓶颈与98%送达率提升方案
  • 2026沃尔玛购物卡回收避坑|别再低价贱卖!4大平台实测,差距太大了 - 资讯快报
  • 长沙二手手表回收攻略,实地走访多家门店,教你选对靠谱渠道 - 合扬奢侈品交易中心
  • 抖音视频如何保存到相册:全场景操作方法与保存失败原因解决方案 - 科技热点发布
  • Web应用技术第二次作业
  • GetQzonehistory专业实践:掌握高效QQ空间说说备份与数据归档技巧
  • 留学生无实习经验求职指南:结构性困境与系统化破局
  • go swagger转html
  • 烟威地区废旧设备拆除回收:合规服务助力工业设备更新处置 - 人间发现
  • 欧盟AI法案深度解析:风险分级监管、合规挑战与企业应对策略
  • 告别重复检测!DINO的对比去噪训练,如何让模型学会‘精准排雷’?
  • ppt里面有时候输入法无法输入中文,只能输入英文,采用切换按键也不行——只有关闭ppt重新打开才可以解决问题,这是什么原因?
  • CFD几何建模软件
  • 手把手调试:在QEMU+KVM虚拟化环境中验证SWIOTLB的工作机制与触发条件
  • go精华gitee.com/gowebframe3/webframe
  • YOLO26野生动物识别检测系统(项目源码+数据集+模型权重+UI界面+python+深度学习+远程环境部署)
  • IOTA 学习笔记(五):对象模型是理解 IOTA 的关键
  • 2026真空热压炉、碳化炉、熔炼炉五大厂家推荐 - 资讯速览
  • TranslucentTB启动失败?5步修复Microsoft.UI.Xaml框架缺失问题
  • 2026年 果蔬深加工前处理设备/饮料杀菌及实罐杀菌设备/脱水蔬菜前处理设备实力制造商:智能高效与锁鲜工艺解析 - 品牌企业推荐师(官方)
  • 2026年 果蔬深加工设备/饮料杀菌实罐杀菌设备/脱水蔬菜前处理设备十大品牌推荐:高效节能与卫生安全的行业标杆之选 - 品牌企业推荐师(官方)
  • 终极指南:AlwaysOnTop - 3分钟解决Windows多窗口遮挡难题