一.前言

前文讲到Linux的基本指令和权限,但是在我们常见的项目编译中肯定会有很多代码文件,指挥使用指令是不够的,所以本篇章着重来讲解一下如何使用Make/Makefile来实现项目的自动化构建

在Linux中编译C语言代码,a.out是从

  • test.c经过预编译test.i
  • test.i经过编译test.s
  • test.s经过汇编test.o
  • test.o经过链接a.out

我们平常做做练习还可以接受,但是到了大型工程,可是有上千条上万条代码,若是一次编译完成之后又修改了源代码,接着又想进行编译,此时便需要重新敲入指令那会使得工作量变得很大。可是在VS中,我们可以无限地修改自己的代码,然后随时编译运行,不需要考虑这些复杂的原理

Linux中有没有这样的一站式操作呢,那就是【make/Makefile】

二.make/makefile介绍

🥝Makefile是干什么的?

  • Makefile 是一个文件。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
  • Makefile 带来的好处就是——“自动化编译"。一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率🚀
  • target(目标文件):文件1 文件2(依赖文件列表)		//依赖关系
     
    <Tab>gcc -o 欲建立的执行文件 目标文件1 目标文件2		///依赖方法
    	 command
    	 ...
    	 ...
  • target就是我们想要建立的信息,一般称作目标文件。而后面的依赖文件列表就是具有相关性的 object files,也就是目标文件所依赖的文件(可以是一个或多个,也可以没有)
目标:你想要生成的文件名(比如最终的可执行文件,或者中间的 .o 目标文件)。也可以是一个执行动作(如 clean)。

依赖:生成这个目标所需要的原材料(源文件或其他中间文件)。

命令:如何将“依赖”变成“目标”的具体操作(通常是 gcc/g++ 命令)。

⚠️ 致命易错点:命令前面必须是一个纯正的 Tab 键缩进,绝对不能是用空格代替,否则 make 会报错!

三.makefile操作

假设我们有一个简单的项目,包含三个文件:

main.c (主函数)

math.c (数学功能实现)

math.h (头文件)

传统编译方式: gcc main.c math.c -o myapp

使用 makefile 的方式 在源码同级目录下创建一个名为 Makefilemakefile 的文件,内容如下:

# 最终目标 myapp 依赖于 main.o 和 math.o
myapp : main.o math.o
	gcc main.o math.o -o myapp

# main.o 依赖于 main.c
main.o : main.c
	gcc -c main.c -o main.o

# math.o 依赖于 math.c
math.o : math.c
	gcc -c math.c -o math.o

工作原理(依赖推导树): 当你输入 make 回车时:

  • make 会在当前目录找 makefile,并默认把找到的第一个目标(也就是 myapp)作为最终目标。

  • 它发现要生成 myapp 依赖 main.omath.o

  • 如果当前目录下没有这两个 .o 文件,它会挂起当前任务,继续向下寻找生成 main.omath.o 的规则。

  • 找到底层的 .c 生成 .o 的规则后,按从下往上的顺序,先执行 gcc -c 生成目标文件,最后再执行链接生成可执行程序 myapp。这就是所谓的自动推导

四.进阶操作

上面的写法有太多重复的内容(比如文件名被写了好多次),我们可以使用变量来简化它。

常用自动化变量:

  • $@:表示规则中的目标文件

  • $^:表示规则中的所有依赖文件(以空格分隔)。

  • $<:表示规则中的第一个依赖文件

# 定义基础变量
CC = gcc
TARGET = myapp
OBJS = main.o math.o

# 链接生成最终可执行文件
$(TARGET) : $(OBJS)
	$(CC) $^ -o $@   # 等价于 gcc main.o math.o -o myapp

# 编译生成中间目标文件
# % 是通配符,表示所有的 .o 文件都由对应的 .c 文件生成
%.o : %.c
	$(CC) -c $< -o $@

五.项目清理:.PHONY伪目标

编译过程中会产生很多中间文件(如 .o),当你想清理工作区,准备重新全量编译或打包源码时,需要删除它们。我们通常会在 makefile 底部加上清理命令:

.PHONY:clean
clean:
        rm-f $(OBJS) $(TARGET)

为什么要有.PHONY关键字

假设你的当前目录刚好有一个名为clean的实体文件,当你执行 make clean时,make发现目标文件clean已经存在,并且它没有任何以来,make就会认为它是最新的,从而提示make:‘clean' is up to date,拒绝执行下面的rm命令。 .PHONY的作用就是告诉make,clean是一个伪目标,不代表具体的文件,无论当前目录有没有叫clean的文件,每次执行 make clean时无条件执行它下面的命令

六.核心优势:增量编译

这也是 makefile 最大的价值所在:只编译修改过的文件

如果你的项目有100个  .c文件,你修改其中一个。当你再次输入make时,make工具会对比源文件(.c)和目标文件(.o)的最后修改时间。

如果发现 xxx.c 的修改时间比 xxx.o 晚,它就知道源文件被改动过了,于是只重新编译这一个文件,然后重新链接。大大节省了大型项目的编译时间!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐