当前位置:   article > 正文

makefile的基础规则与命名方式_makefile给targe取个名字

makefile给targe取个名字

1.Makefile的基础命名规则

  编写 main.c 文件,在本次实验中将用简单的 hello world! 程序来验证 Makefile 的基本规则。

#include <stdio.h>

int main(void)
{
    printf("hello world!\n");
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

因为 Makefile 是为了自动管理编译、链接流程而存在的,因此 Makefile 的书写需要遵照一定的书写规则。

TARGET... : PREREQUISITES...
COMMAND
  • 1
  • 2
  • TARGET:规则目标,可以是一个 object file (目标文件),也可以是一个执行文件,还可以是一个标签(label),使用方式是:make TARGET
  • PREREQUISITES:要生成那个 target 所需要的文件或是目标,即规则依赖。
  • COMMAND:也就是 make 需要执行的命令,必须以 [TAB] 开始,由 shell 执行。

编写一个简单的 Makefile 文件用来管理 main.c 文件的编译。Makefile 文件的内容如下:

main: main.o
    gcc -o main main.o

main.o: main.c
    gcc -c main.c
  • 1
  • 2
  • 3
  • 4
  • 5

现在在 Terminal 输入命令:

make main.o
  • 1

Terminal 的输出结果如图所示:
在这里插入图片描述
说明 shell 执行了命令 gcc -c main.c。接下来输入以下命令:

make main
  • 1

执行生成的main文件,Terminal 中的输出结果如图所示:
在这里插入图片描述
说明程序得到了正确的执行。

在进行自动化编译之前,我们将生成的多余文件进行删除。

rm main.o main
  • 1

由于我们的最终的目标是 main 文件,实际上我们并不关心中间目标文件 main.o。现在尝试只运行一次 make 编译出我们需要的最终目标。

make main
  • 1

Terminal 的输出内容如图:
在这里插入图片描述
可以看出 make 还是先生成 makefile 中 main 的依赖文件 main.o,再链接到 main.o生成 main 文件。接下来我们让 make 自动寻找目标,即在 make 命令后不添加任何参数直接运行。首先删除之前产生的 main 和 main.o 文件。

rm main main.o
  • 1

然后在 Terminal 中输入命令:

make
  • 1

Terminal 的输出内容跟之前的输出内容相同:

这是因为默认情况下,make 会以第一条规则作为其终极目标。

现在我们尝试修改 makefile,在目标 main 之前再增加一条规则:

dft_test : middle_file
    mv middle_file dft_test
middle_file :
    touch middle_file
  • 1
  • 2
  • 3
  • 4

注意:在将这段代码复制到 WebIDE 中时需要观察一下此时 tab 的默认格式是 space:4 表示使用 4 个空格代替 制表符

在这里插入图片描述
这样的话在执行 make 命令会出现以下错误:

在这里插入图片描述
解决办法是依次点击 Space:4->Indent Using Tabs->4 Configured Tab Size 然后删除 Command 那一行的缩进,重新使用 tab 缩进,保存之后重新执行 make 命令,问题将得以解决。

执行命令:

make
  • 1

Terminal 输出结果如下:
在这里插入图片描述
说明规则得到了正确的执行,同时在当前文件夹下会产生一个新的文件 dft_test。

2.Makefile 之时间戳

make 命令在执行时会自动检测依赖文件的时间戳,具体规则如下:

  • 若依赖文件不存在或者依赖文件的时间戳比目标文件新,则执行依赖文件对应的命令。
  • 若依赖文件的时间戳比目标文件老,则忽略依赖文件对应的命令。

接下来对 makefile 时间戳规则进行验证,修改 makefile 文件内容:

#this is a makefile example

main:main.o testa testb
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

清除可能存在的中间文件:

rm main.o testa testb
  • 1

执行 make 命令

make
  • 1

Terminal 输出内容如下:
在这里插入图片描述
make 命令执行后分别生成 main.otestatestb 这三个中间文件。这验证了时间戳规则中的第一条。

现在删除 testb 文件,再观察 make 会如何执行。

make
  • 1

Terminal 输出结果如图:
在这里插入图片描述

可见 make 分别执行了 testbmain 两条规则,main.otesta 规则对应的命令没有被执行。这验证了 makefile 时间戳规则中的第二条。

3.Makefile依赖执行顺序

make 目标文件的依赖文件是按照从左到右的顺序生成的。 它对应规则 main。

main:main.o testa testb
    gcc -o main main.o
  • 1
  • 2

make 按照顺序分别执行 main.o、testa、testb 所对应的规则。 现在我们调换 main.o、testa、testb 的顺序。 修改 makefile 文件的 main 规则的依赖顺序:

main: testb testa main.o
  • 1

清除上次编译过程中产生的中间文件:

rm main.o testa testb
  • 1

执行 make 命令。

make
  • 1

Termianl 输出结果如图:
在这里插入图片描述

可见 make 的确是按照从左到右的规则分别执行依赖文件对应的命令。

4.Makefile中的变量、[.PHONY]与[-]

4.1 变量

  makefile 也可以使用变量,它类似于 C 语言中的宏定义。 变量可以直接使用「vari=string」的写法来定义,并以「$(vari)」格式来使用。 我们用变量来定义目标的依赖项,使 makefile 保持良好的扩展性。
在 makefile 中定义并使用变量,将 makefile 还原至以下内容:

#this is a makefile example

depen=main.o testa testb

main:main.o testa testb
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

修改 main 的依赖声明。

main:$(depen)
  • 1

执行 make 命令,并观察输出结果。
Terminal 输出结果如图:
在这里插入图片描述

可以看出 makefile 依然能够正常执行。 就算之后 main 目标的依赖项有变化时,也只需修改 depen 变量的值即可。

为 makefile 添加 clean 规则,因为每次测试 makefile 的时候我们都要清除中间文件,为了使得编译工程更加自动化,我们在 makefile 中添加规则让其自动清除。

在 makefile 中修改 depen 变量,增加 clean 依赖:

depen=clean main.o testa testb
  • 1

增加 clean 规则及其命令。

clean:
    rm main.o testa testb
  • 1
  • 2

此时 makefile 的内容如下:

#this is a makefile example

depen=main.o testa testb clean

main:$(depen)
    gcc -o main main.o

main.o:main.c
    gcc -c main.c

testa:
    touch testa

testb:
    touch testb

clean:
    rm testa testb main.o
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

执行 make 命令并观察,执行结果。
在这里插入图片描述
说明现在 make 会先清除掉上次编译的中间文件并重建新的对应的文件。

在 clean 规则中也使用 depen 变量。

clean:
    rm $(depen)
  • 1
  • 2

然而当我们执行了 make 命令之后,发现问题产生了。
在这里插入图片描述
原来是因为 depen 变量指明 clean 为依赖项,因此执行 rm 命令时也会试图删除 clean 文件,这时就会出现错误。 而 make 在执行命令行过程中出现错误后会退出执行。

4.2 「-」的使用

  因为在大部分情况下我们不会将删除一个不存在文件时所产生的错误作为真正的错误来看待,为了让 rm 命令在执行过程中即使出现了错误,makefile 也能够继续执行不退出,我们需要用到「-」符号。 而「-」的作用是让 make 忽略该指令的错误。

现在修改 makefile 中的 clean 规则:

clean:
    -rm $(depen)
  • 1
  • 2

执行 make 命令并观察输出结果:
在这里插入图片描述
从输出结果来看,虽然 rm 指令报出错误,make 却依然可以生成 main 文件。

4.3 伪目标的使用

前面提到 makefile 依赖文件的时间戳若比目标文件旧,则对应规则的命令不会执行。 我们现在定义了一个 clean 规则,但如果文件夹下正好有一个 clean 文件会发生什么样的冲突呢? 我们先在当前目录下先新建一个 clean 文件:

touch clean

执行 make 命令,并观察输出结果。
在这里插入图片描述
发现 clean 规则没有的到执行,因为 clean 文件已经存在。然而 clean 实际上是一个伪目标,我们并不期望它会与真正 clean 文件有任何关联。 因此需要使用 .PHONY 来声明伪目标。

接下来修改 makefile 在变量 depen 之前加入一条伪目标声明。

.PHONY: clean
  • 1

执行 make 命令并观察输出结果。
在这里插入图片描述
可以看到 makefile 又能得到正常执行了,并且所有流程都符合我们的预期。

现在删除掉 main 依赖项 testa 和 testb 因为在生成 main 文件过程中并不需要用到这两个文件。 修改 makefile 的 depen 变量:

depen=clean main.o
  • 1

执行 make 命令并观察输出结果。
在这里插入图片描述

学到这里,我们就已经可以随心所欲的定制 main 的依赖规则了。

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/640943
推荐阅读
相关标签
  

闽ICP备14008679号