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

【Linux系统编程】自动化构建-make/Makefile

【Linux系统编程】自动化构建-make/Makefile

  • 1. 为什么要用make?
  • 2. Makefile的基本结构
  • 3. Makefile中头文件依赖问题
  • 4. Makefile进阶用法与技巧

1. 为什么要用make?

想象一下你正在开发一个C/C++项目,它由以下几个文件组成:

main.c
test.c
process.c
process.h(被所有的.c文件引用)

要生成最终的可执行文件code,你需要执行以下步骤:

gcc -c main.c -o main.o
gcc -c test.c -o test.o
gcc -c process.c -o process.o
gcc main.o test.o process.o -o code

每次修改一个文件,你都要重新执行所有命令。对于大项目,这非常耗时。

make的诞生就是为了解决这个问题:

  • 自动化: 只需要一个命令make,自动完成所有构建步骤。
  • 增量构建/只能编译:make非常聪明,它能根据文件的修改时间来判断哪些文件需要重新编译。比如:在上面的例子中,如果你只修改了process.c,make只会执行:
gcc -c process.c -o process.o
gcc main.o test.o process.o -o code

它跳过了main.o和test.o的编译,因为它们对应的源文件没有变化,从而极大地加快了构建速度。

2. Makefile的基本结构

Makefile 告诉 make 要做什么。它的核心由一系列规则构成。

一个规则的典型结构如下:

target:prerequisites
<Tab>recipe
  • target(目标):规则所要生成的文件名(例如main.o)或是一个动作的名称(例如clean,这个下面讲到伪目标就懂了)。
  • prerequisites(先决条件):生成 target 所需要的文件或其他目标(例如main.c,process.h)。这些是 target 的依赖。
  • recipe(配方):由先决条件到目标所需要的命令(例如gcc -c main.c -o main.o)。注意:每行命令前必须要按一个Tab键,而不是空格。

一个简单的例子

将我们开头的编译命令写成 Makefile

# 最终目标
code:main.o test.o process.ogcc main.o test.o process.o -o code# 各个中间目标
main.o:main.c process.hgcc -c main.c -o main.otest.o:test.c process.hgcc -c test.c -o test.oprocess.o:process.c process.hgcc -c process.c -o process.o

工作原理

  1. 当你在终端输入 make 时,make 会默认寻找当前目录下的 Makefile 文件,并执行文件中的第一个目标(在这里是code)。
  2. 为了构建 code,它发现 code 依赖于 main.o, test.o, process.o。
  3. 接着它会检查这些 .o 文件是否存在,以及它们的依赖项(.c 和 .h 文件)的修改时间是否比 .o 文件更新
  4. 如果某个依赖项比目标文件新(比如你修改了 test.c,那么 test.c 就比 test.o 新),或者目标文件不存在,make 就会执行该目标下的配方来重新生成它。
  5. 一旦所有依赖项都是最新的了,make 最后执行生成 code 的配方。

伪目标(Phony Targets)

有些目标并不是要生成一个实际的文件,而是代表一个动作,比如清理构建文件。

clean:rm -f main.o test.o process.o code

如果你的目录下恰好有一个名为 clean 的文件,再执行 make clean 时,make 会发现 clean 文件已经存在,并且没有依赖,于是会认为它是最新的,从而不执行 rm 命令。

为了解决这个问题,我们需要将其声明为伪目标

.PHONY:clean
clean:rm -f main.o test.o process.o code

这样,每次执行 make clean,make 都会无条件地执行其配方。

下面我们实际去测试一下上面的主要流程

// main.c
#include "process.h"int main()
{int ret1 = add(10, 20);int ret2 = mul(10, 20);printf("add:%d\n", ret1);printf("mul:%d\n", ret2);                                                            return 0;
}// test.c
#include "process.h"    int add(int a, int b)    
{    return a + b;    
} // process.c
#include "process.h"    int mul(int a, int b)    
{    return a * b;    
} // process.h
#pragma once    
#include <stdio.h>    int add(int a, int b);    
int mul(int a, int b); 
// Makefile
# 最终目标
code:main.o test.o process.ogcc main.o test.o process.o -o code# 各个中间目标
main.o:main.c process.hgcc -c main.c -o main.otest.o:test.c process.h                                                                                                                                                           gcc -c test.c -o test.oprocess.o:process.c process.hgcc -c process.c -o process.o.PHONY:clean
clean:rm -f main.o test.o process.o code

在这里插入图片描述

3. Makefile中头文件依赖问题

// Makefile
# 最终目标
code:main.o test.o process.ogcc main.o test.o process.o -o code# 各个中间目标
main.o:main.c process.hgcc -c main.c -o main.otest.o:test.c process.h                                                                                                                                                           gcc -c test.c -o test.oprocess.o:process.c process.hgcc -c process.c -o process.o.PHONY:clean
clean:rm -f main.o test.o process.o code

该Makefile中的头文件依赖可以不写吗?为什么?

这是一个非常好的问题,涉及到 Makefile 依赖关系的核心细节。

简短回答:
可以,但不推荐。不写 process.h 在很多简单情况下程序依然能编译成功,但这破坏了 make 的正确依赖关系,可能导致难以发现的构建错误。

详细解释

1. 不写 process.h 会发生什么?

main.o: main.c process.hgcc -c main.c -o main.o

当前行为(有 process.h):如果你修改了 process.h 文件,make 会发现 process.h 的修改时间比 main.o 新,于是重新执行 gcc -c main.c -o main.o,重新编译 main.o。这是正确的。

如果去掉 header.h:

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

现在,make 只关心 main.c。如果你只修改了 process.h,make 会认为 main.o 是最新的(因为它的依赖 main.c 没变),从而不会重新编译 main.o。

2. 什么时候可以不写?

在极其简单的情况下,比如:

头文件只包含函数声明,没有定义。

你确定头文件的修改不会影响二进制目标文件(.o)的生成。

或者你每次都会执行 make clean && make 来强制全部重新编译。

但作为一种最佳实践,你应该总是列出所有依赖。

4. Makefile进阶用法与技巧

基本的 Makefile 已经能工作了,但我们可以让它更强大、更简洁。

使用变量可以让 Makefile 更易于维护和修改。

# 定义变量    
BIN=code    
SRC=$(wildcard *.c)    
OBJ=$(SRC:.c=.o)    
CC=gcc    $(BIN):$(OBJ)    $(CC) $^ -o $@    
%.o:%.c                                                                                       $(CC) -c $<            .PHONY:clean    
clean:    rm -f $(OBJ) $(BIN)   

在这里插入图片描述

下面对每句代码进行解释

BIN=code

定义变量 BIN,值为 code,这个变量代表最终生成的可执行文件的名称,如果要改变程序名,只需要修改这里。

SRC=$(wildcard *.c)

$(变量名)是获取变量中的值;使用 wildcard 函数自动获取所有 .c 文件;
wildcard 是 Makefile 的内置函数; * .c 是通配符模式,匹配所有 .c 文件;
优点:自动发现源文件,添加新 .c 文件时无需修改 Makefile

OBJ=$(SRC:.c=.o)

将源文件名列表转换为目标文件名列表;
将 SRC 变量中所有的 .c 替换为 .o;
用途:生成编译过程中需要的中间目标文件列表

CC=gcc

定义使用的 C 编译器

$(BIN):$(OBJ)    $(CC) $^ -o $@ 

最终目标规则:
目标:$ (BIN) 即 code
依赖:$ (OBJ) 即所有的 .o 文件
命令:$ (CC) $^ -o $@
$(CC) 展开为 gcc
$^ 是自动变量,代表所有依赖文件(所有的 .o 文件)
-o $@ 中 $@ 是自动变量,代表目标文件名(code)
作用:将所有的 .o 文件链接成最终的可执行文件

%.o:%.c$(CC) -c $<

模式规则:
模式:%.o:%.c
% 是通配符,匹配任意文件名
命令:$(CC) -c $<
$< 是自动变量,代表第一个依赖文件(即 .c 文件)
作用:将每个 .c 源文件编译成对应的 .o 目标文件

.PHONY:clean    
clean:    rm -f $(OBJ) $(BIN)   

清理规则:
rm -f 强制删除文件,不提示错误
$(OBJ) 展开为所有 .o 文件
$(BIN) 展开为可执行文件 code
作用:清理所有编译生成的文件

自动变量总结
$@:规则的目标文件名。
$<:第一个依赖文件的名称。
$^:所有依赖文件的列表,以空格分隔。

http://www.dtcms.com/a/545199.html

相关文章:

  • php网站打开慢青海高端网站建设
  • 仓颉TreeMap红黑树结构深度解析
  • React中Suspense的分包实践
  • 垃圾收集器
  • CSharp UI更新及跨线程更新总结
  • 两个域名同一个网站做优化淘宝优惠网站怎么做
  • 深入仓颉UI:事件处理的声明式哲学与高阶实践
  • Actix Web 入门与实战
  • 外贸soho建站云南省建设厅网站二建
  • 20251029在AIO-3576Q38开发板的Android14下使用iperf3测试WIFI模块AP6256的网速【87.8 Mbits/sec】
  • 怎么用dede建设网站网站建设开放的端口
  • 基本select语句
  • linux命令-系统信息与监控-2
  • 【Ubuntu】安装amd驱动及ROCM后,系统起不来的问题分析及解决方案
  • 外国网站后台设计iis网页提示网站建设中
  • 镇江网站建设多少钱北京seo网站优化公司
  • 【第一章】金融数据的获取——金融量化学习入门笔记
  • MoonBit Pearls Vol.13:使用 MoonBit 开发一个 HTTP 文件服务器
  • 网站建设如何描述htm网站制作
  • SAP PP模块中流程制造
  • 网站攻击企业做营销型网站
  • SpringBoot项目集成easy-es框架
  • MySQL | 对数据库及数据库表格进行操作(实例)
  • 安装 ElasticSearch、Logstash、Kibana、Kafka 和 Filebeat
  • 从数据采集到智能诊断:阿尔泰科技实时高精度远距离管道状态监测全流程
  • MLGO微算法科技 LOP算法:实现多用户无线传感系统中边缘协同AI推理的智能优化路径
  • 签约快讯 | 当换科技携手体验家,重构二手3C全旅程体验
  • 2017网站开发新技术网站排名方法
  • flash打开网站源码网站开发亿玛酷出名5
  • ic电子网站建设网络营销策划推广方案