初识makefile

一、文件准备

  • Math.h
void sayHello();
void add(int a,int b);
  • math.c
#include<stdio.h>
#include "Math.h"

void sayHello(){
    printf("hello Linux!\n");
}

void add(int a,int b){
    printf("result=%d\n",a+b);
}
  • main.c
#include<stdio.h>
#include "Math.h"
int main(){
    sayHello();
    add(10,20);
    return 0;
}

二、文件编译链接

1.手动

1.步骤如下:

  1. 编译math.c,并生成math.o目标文件
gcc -c math.c -o math.o
  1. 编译main.c,并生成math.o
gcc -c main.c -o main.o
  1. 链接目标文件Math.omain.o生成可执行文件mylink
gcc -o mylink math.o main.o
  1. 运行可执行文件
./mylink

imagefadbe297e296f5ab.png

2.缺点

  • 链接步骤繁琐
  • 容易出错
  • 不利于维护
  • 不同平台兼容性问题
  • 可移植性差

在实际开发中,一般都会使用构建工具来自动化完成编译和链接过程,例如MakefileCMakeAutotools等。

2.makefile

1.一个显式的makefile文件

  • #的内容是注释

  • 格式

    目标文件 …:依赖…
    	命令
    
  • 上方文件的makefile

# 定义目标文件 "main"
# 该目标依赖于目标文件 "math.o" 和 "main.o"
# 通过gcc链接生成可执行文件 "main"
main: math.o main.o
	gcc -o main math.o main.o

# 定义目标文件 "math.o"
# 它依赖于源文件 "math.c" 和头文件 "Math.h"
# 通过gcc编译生成目标文件 "math.o"
math.o: math.c Math.h
	cc -c math.c

# 定义目标文件 "main.o"
# 它依赖于源文件 "main.c" 和头文件 "Math.h"
# 通过gcc编译生成目标文件 "main.o"
main.o: main.c Math.h
	cc -c main.c

# 定义伪目标 "clean"
# 用于清理生成的目标文件和可执行文件
clean:
	rm -rf math.o main.o

2.第一次执行

image8b1e59c33f8498dc.png

3.分析

Makefile 实现自动化的核心是规则(rules)和依赖关系

  • 规则(rules)描述了如何生成一个或多个目标文件,并列出了所有必需的依赖项。
  • Makefile 根据目标文件和依赖项的时间戳来判断是否需要重新生成目标文件。
    • 如果目标文件不存在,或者其任何一个依赖项的时间戳比目标文件的时间戳要新
    • 那么 make 工具就会认为该目标文件需要重新生成,于是执行规则中定义的命令来生成目标文件。

我们可以借助remake来查看makefile的详细执行过程(重定向、翻译)

remake -xi

imagec5400f3236b49326.png

  • 11这个文件的内容
Reading makefiles...
Updating goal targets....
 File 'main' does not exist.
   File 'math.o' does not exist.
  Must remake target 'math.o'.
Makefile:11: update target 'math.o' due to: math.c Math.h
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cc -c math.c
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Successfully remade target file 'math.o'.
   File 'main.o' does not exist.
  Must remake target 'main.o'.
Makefile:17: update target 'main.o' due to: main.c Math.h
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cc -c main.c
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  Successfully remade target file 'main.o'.
Must remake target 'main'.
Makefile:5: update target 'main' due to: math.o main.o
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
gcc -o main math.o main.o
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Successfully remade target file 'main'.

翻译一下

读取 makefiles 中...
正在更新目标...
文件 'main' 不存在。
文件 'math.o' 不存在。
必须重构目标 'math.o'。
Makefile:11: 因为 math.c Math.h 更新目标 'math.o'
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cc -c math.c
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
成功重构目标文件 'math.o'。
文件 'main.o' 不存在。
必须重构目标 'main.o'。
Makefile:17: 因为 main.c Math.h 更新目标 'main.o'
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cc -c main.c
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
成功重构目标文件 'main.o'。
必须重构目标 'main'。
Makefile:5: 因为 math.o main.o 更新目标 'main'
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
gcc -o main math.o main.o
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
成功重构目标文件 'main'

下面是 makefile 的执行过程:

  1. 读取 Makefile
    • make 命令在执行时,会首先读取当前目录下的 Makefile 文件。
  2. 解析 Makefile
    • make 工具会解析 Makefile 文件,找出其中的依赖关系,并确定哪些文件需要被重新编译。
    • make 工具会根据文件的时间戳等信息来进行判断,如果目标文件已经存在且没有被修改过,则不需要重新编译。
  3. 检查依赖关系
    • 当 make 工具确定了需要重新编译的文件后,它会检查这些文件所依赖的其他文件是否也需要重新编译
    • 如果需要,就会递归地进行重新编译,并更新时间戳。
  4. 执行命令
    • 当所有需要重新编译的文件都被确定后,make 工具会按照 Makefile 中定义的规则执行相应的命令,生成最终的目标文件。
  5. 更新目标文件
    • 在执行完所有必要的命令后,make 工具会将生成的目标文件和相关的依赖关系更新到系统中,以便下次执行 make 命令时进行判断。
  6. 完成构建
    • 如果所有需要构建的文件都已经被成功编译,make 工具就会输出一条构建成功的信息,并退出。

总之,Makefile 的执行过程包含了读取、解析、检查、执行、更新和完成构建等多个步骤,它能够自动化地完成程序的构建过程,从而提高开发效率。

4.更新文件

  • 如果此时我们更新文件,只需要重新执行make命令即可

假设我们修改了main.c文件

#include<stdio.h>
#include "Math.h"
int main(){
    sayHello();
    add(10,20);
    printf("\n我是添加的语句!");
    return 0;
}

此时main.c的时间是比main要新的

imagecca407ae5f47799f.png

5.分析

  • remake -xi 查看详细果
  • 这里我们保留之前留下的中间文件

imagedde56e4026288712.png

Makefile:17: update target 'main.o' due to: main.c
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
cc -c main.c
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Makefile:5: update target 'main' due to: main.o
##>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
gcc -o main math.o main.o
##<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
在第17行,目标'main.o'被更新,因为'main.c'发生了变化。

接着,在执行编译操作之前,会编译'main.c'文件,命令为“cc -c main.c”。

然后,在第5行,目标'main'被更新,因为'main.o'已经生成。

最后,在执行完整个编译过程后,生成可执行文件'main',命令为“gcc -o main math.o main.o

容易发现

  • 文件复用
    • 对于已经存在且没有修改的文件math.o并没有重新生成,并与main.o重新生成main
    • 这种文件复用的机制可以大大加快编译时间,并在一定程度上避免不必要的重复操作

6.小结

​ Makefile 是用来自动化构建程序的工具,它定义了一系列规则(rules)和依赖关系,让开发人员能够只需要指定最终目标文件,而不必手动编译和链接所有源代码文件。Makefile 的执行过程大致包含了读取、解析、检查、执行、更新和完成构建等多个步骤。

​ 简单来说,就是检查哪些文件需要更新,然后执行相应的命令以重新生成目标文件。如果某个目标文件不存在,或者它所依赖的文件已经被更新,那么Make会执行相应的规则以重新生成该文件。

​ Makefile 最重要的特性是能够让开发人员避免重复编译和链接已经生成的文件,从而提高程序构建的效率。当源代码文件或头文件发生变化时,Makefile 只会重新编译和链接受到影响的文件,并在需要时递归地编译它们所依赖的其他文件。这种复用现有文件的机制可以减少冗余操作,节省时间和资源。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值