Heja Heja
首页
  • 本科相关(软院)
  • 硕士相关(计院&国卓院)
  • 嵌入式
  • 大模型
  • 网站搭建
首页
  • 本科相关(软院)
  • 硕士相关(计院&国卓院)
  • 嵌入式
  • 大模型
  • 网站搭建
  • 大模型

  • 嵌入式

    • makefile入门
      • makefile的基本规则
      • makefile工作原理
      • makefile中的变量
      • makefile自动推导
      • makefileの潜规则
      • makefileの组成
      • makefile环境变量与引用
      • makefile工作方式
      • makefile的通配符
      • makefile文件搜索
      • makefile中的伪目标
      • makefile多目标与静态规则
      • makefile的基本规则
    • 32标准库说明
    • xv6笔记
    • stm32配置高速时钟
  • 计算机
  • 嵌入式
2025-10-30
目录

makefile入门

# 初识makefile

makefile是程序员们在构建大型项目时必不可少的工具,它能够帮助理清工程项目间的依赖关系。在项目的某些文件更新时,就不至于重新编译链接整个工程,而是只需要更新某些依赖项,大大提高了构建效率。

# makefile的基本规则

target: prerequisites
    command
1
2
  • target是要构建的目标文件
  • prerequisites是目标文件所需要的依赖文件
  • command是构建命令,注意命令前一定是个tab制表键。

依赖文件发生改动时,make会自动执行后面的命令以重新构造目标文件。

一个makefile文件往往由多组这样的命令组成,下面是陈皓老师教程中的实例:

    edit : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit main.o kbd.o command.o display.o /
               insert.o search.o files.o utils.o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
								<kbd>代码 1-1 makefile文件实例</kbd>

“/”是换行符的意思。这是由3个头文件和8个.c源文件构建的工程,输入命令make就可以生成可执行文件edit。输入命令make clean就可以删除所列文件。

注意这里的clean不是一个文件,而是一个动作名字(lable),可以看到它后面什么也没有,没有依赖文件也就不会自动执行下面的命令,如果需要执行,就需要在输入make命令时指出这个lable的名字。这在打包或者备份程序时很有用。

# makefile工作原理

makefile文件中的第一个目标文件作为最终的目标文件。当输入make命令时,make会在当前目录下寻找名为makefile的文件,并寻找第一个目标文件,如果依赖项的时间戳比它新或者目标文件不存在,则执行后面的命令;如果依赖项不存在则报错。之后则是按上述过程依次寻找依赖项,直到能够构成最终目标文件。

如果我们修改某一个源文件如files.c则它对应的目标文件file.o就会被更新,则最终的目标文件也会重新链接。但其余编译过的.o文件无需重新编译,节约时间。

如果我们修改了command.h,则kbd.o,command.o,files.o都会被重新编译。

# makefile中的变量

可以看到最终目标文件的依赖项有一大堆,如果我们需要添加或者删除某个依赖项,则需要在依赖项,命令处更改两次(实际应用中可能更多),所以需要用一个变量来定义这组文件,后面的更改只需要在变量定义处声明一次就好了。下面是应用变量后的makefile文件

变量引用格式:$(var)

   obj = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
   
    edit : $(obj)
            cc -o $(obj)

    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit $(obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
								<kbd>代码1-2 应用变量后的makefile实例</kbd>

# makefile自动推导

尽管应用变量后看起来简洁了一些,但是每个作为依赖项和目标文件的.o文件也都需要挨个写类似的依赖项与命令。这看起来还是有点麻烦,好在make足够强大,它可以进行自动推导。

原理:make每看到一个.o文件,就会自动把与它同名的.c源文件加入到依赖项中,并且命令cc -c xxx.c也会被自动推导。

   obj = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
   
    edit : $(obj)
            cc -o $(obj)

    main.o : defs.h
    kbd.o : defs.h command.h
    command.o : defs.h command.h
    display.o : defs.h buffer.h
    insert.o : defs.h buffer.h
    search.o : defs.h buffer.h
    files.o : defs.h buffer.h command.h
    utils.o : defs.h
    clean :
            rm edit $(obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

代码1-3 应用自动推导功能后的makefile

# makefileの潜规则

每个makefile的文件在最后都最好写一个clean的动作,即清空最终目标文件和.o文件。这样有利于重新编译和整洁。这是一种修养(by陈皓)。

一般做法是:

clean
    rm edit $(obj)
1
2

更为稳健的做法是:

.PHONY:clean
clean:
    -rm edit $(obj)
1
2
3

.PHONY表明clean是个伪目标,“-”的意思是即使某些文件出了问题,也强制执行后面的命令。

# 简谈makefile规则

# makefileの组成

主要由五个部分组成

  • 显式规则:由makefile的编写者显式地指出,要生成的目标文件,目标文件的依赖文件,生成命令。
  • 隐式规则:是由make规定的,自动推导的功能,能让我们的makefile看起来更加简洁。
  • 变量:一般由字符串表示,类似于c语言中的宏定义。
  • 文件指示:在一个makefile中引用另一个makefile,类似于c语言中的#include。根据不同情况指定文件的有效部分,类似于c语言中的#if条件编译。定义一个多行命令。
  • 注释:“#”表明注释,若要打印“#”,则使用转义符反斜杠/。

makefile文件名

当输入make命令的时候,make会在当前目录依次寻找名为“GNUmakefile”,“makefile”,“Makefile”的文件,找到就开始解释文件。一般来说最好用“Makefile”,因为比较醒目。最好不要用“GUNmakefile”,因为这是GNU的make才会识别。

也可以使用其他的文件名,比如“wjy_make”,这个时候就需要指定参数,比如make -f wjy_make或者make --file wjy_make。

# makefile环境变量与引用

先来谈引用,makefile中使用include关键字来引用其他文件,这与c语言中的#include很像。被引用的文件会原封不动的放在该位置。

引用的语法是:include <filename>

include前面可以有空格,但不能有tab制表符。我们来举个例子,假设我们有a.mk, b.mk, c.mk, wjy.make和一个变量bar,变量中包含了e.mk, f.mk. 现在有以下语句:

include wjy.make *.mk $(bar)
1

它相当于:

include wjy.make a.mk b.mk c.mk e.mk f.mk
1

当make命令开始执行时,make会先看include的文件有没有指定的绝对路径或者相对路径,如果没有,则到当前目录里寻找,如果再没有,则到目录<prefix>/include(一般是/usr/local/bin或者/usr/include)中找,或者到用户用-i 或 --include-dir参数指定的目录中去寻找。

使用引用可以实现文件的共享,进一步使得工程更加简洁。

makefile的环境变量定义为MAKEFILES,和include类似,不同的是,他的目标不会起作用(?)

陈皓老师不建议使用MAKEFILES变量,原因是,一但定义它,所有的makefile文件都会受影响,可能会出现怪事。

# makefile工作方式

GNU的make执行步骤如下:

  1. 读入所有makefile文件
  2. 读入被include的其他makefile
  3. 初始化变量
  4. 推导隐晦规则,并分析所有规则
  5. 为目标文件创建依赖链
  6. 根据依赖关系决定哪些目标文件要(重新)生成
  7. 执行生成命令

变量不会立刻展开,如果使用到了才会展开,类似于程序有些模块在运行时才会装入,这样有利于资源的利用,提高速度。

# makefile的通配符

可以用三种类型的通配符来定义一系列类似的文件。make支持三种:“*”, “?”,“【…】”.其中*和%的区别是,*是应用在系统中的,而%是应用在makefile中的。%表示匹配0或多个字符,*表示任意长度的任意字符。准确说%并不是一个通配符,而是一种特殊的替换符号。

“~”波浪号字符一般用在路径中,比如“~/test”表示当前用户home目录下的test目录。“~wjy/test”则表示用户wjy的home下的test目录。

“*”例1:强制清除所有.o文件。

clean:
    rm -f *.o
1
2

“*”例2:定义所有.c文件

obj = *.c
1

注意,这里的变量obj就是*.c,如果想让通配符在变量中展开,也就是obj代指所有.c文件,则可以用以下表达

obj := $(wildcard *.c)
1

这里wildcard是make中的一个关键字,后续补充。

# makefile文件搜索

在工程中往往有多级目录,也可能涉及到不同目录下的重名文件,所以有时候需要指定文件搜索目录。

下面介绍特殊变量VPATH和关键字vpath。

VPATH的作用是,在当前目录找不到目标文件和依赖文件时,就会到VPATH变量里的目录去找。

VPATH = src: ../hardware
1

这个就是表明,如果当前目录找不到目标文件或依赖文件,则到src目录下去找,若也没找到,则到../hardware目录下去找。注意顺序为:“当前目录”->“src”->“../hardware”

vpath关键字的使用更加灵活,它有三种使用方法:

  • vpath <pattern> <catalogue>

为符合模式pattern的文件指定搜索目录catalogue,如

vpath %.c ../hardware
1

这句就是表明,如果在当前目录没有找到某个.c文件的话,则到hardware目录下去找那个.c文件。

  • vpath <pattern>

清除所有符合pattern模式的搜索目录

  • vpath

清除所有已经设置好的搜索目录

vpath也可以连续地使用。如:

vpath %.c cata1:cata2
vpath %    cata3
vpath %.c cata4 
1
2
3

这几句的意思就是先到cata1找,再到cata2找,再到cata3找,最后到cata4找。

# makefile中的伪目标

上文(1.5节)中提到一种更稳健的写clean动作的方法

.PHONY: clean
clean:
    rm -f *.c
1
2
3

在这里.PHONY标志就表明clean是个伪目标。这样的好处是,由于可能存在重名的clean目标文件,但是在我们用.PHONY指明clean是个伪目标后,make clean指令就一定能够执行想要的动作。

一般伪目标不会有依赖文件,但是也可以为它添加依赖文件,同时它也可以作为终极目标文件,比如想一口气生成多个可执行文件,可以这样写:

.PHONY: all
all: exe1 exe2 exe3

exe1: a.o
    cc -o a.c

exe2: b.o
    cc -o b.c

exe3: c.o
    cc -o c.c
1
2
3
4
5
6
7
8
9
10
11

这样我们只需敲入make即可生成三个可执行文件。

同样,伪目标也可作为依赖项,如:

.PHONY: E1 E2 E3
E1:E2 E3
    rm program
E2:
    rm *.o
E3:
    rm *.c
1
2
3
4
5
6
7

make E1:删除所有文件

make E2:删除所有.o文件

make E3:删除所有.c文件

# 简谈makefile规则

# makefile多目标与静态规则

在makefile中可以生成多个目标,targets的依赖文件可能是同一个,也有可能是不同的。为了在一组命令中用不同的依赖文件生成多个目标文件,引入了一个自动化变量$@,它是目标文件的集合,再提一个$<,它是依赖文件的集合。后面会见到。下面看一个生成多目标的实例:

bigoutput littleoutput:text.g
    generate text.g -$(subst output, , $@)>$@
1
2

它等价于

bigoutput:text.g
    generate text.g big>bigoutput
littleoutput:text.g
    generate text.g little>littleoutput
1
2
3
4

了解了多目标再来看静态规则,它帮助我们更加灵活的定义多目标的规则。下面是静态规则的语法

targets:targets-parttern:prerep-pattern
    command
1
2

targets是目标集合,targets-parttern是目标的模式,prerep-pattern是依赖项的模式。下面举个例子:

obj=a.o b.o c.o
$(obj):%.o:%.c
    $(CC) -c $(CFLAGS) %< -o %@
1
2
3

第一行是定义了obj变量,第二行规定目标为obj,指定每一个与.o重名的.c文件都是其依赖文件,在这里%.o就是目标项的模式,%.c就是依赖项的模式。第三行是命令,$(CC)规定使用哪种编译器,-c表示只生成中间文件

# 初识makefile

makefile是程序员们在构建大型项目时必不可少的工具,它能够帮助理清工程项目间的依赖关系。在项目的某些文件更新时,就不至于重新编译链接整个工程,而是只需要更新某些依赖项,大大提高了构建效率。

# makefile的基本规则

target: prerequisites
    command
1
2
  • target是要构建的目标文件
  • prerequisites是目标文件所需要的依赖文件
  • command是构建命令,注意命令前一定是个tab制表键。

依赖文件发生改动时,make会自动执行后面的命令以重新构造目标文件。

一个makefile文件往往由多组这样的命令组成,下面是陈 皓老师教程中的实例:

上次更新: 2025/11/2 06:53:08
Transformer
32标准库说明

← Transformer 32标准库说明→

最近更新
01
Transformer
11-21
02
PINN
11-07
03
GPT
11-03
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Heja
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式