跟我一起写Makefile细节总结学习笔记

本文详细介绍了Makefile的基础知识,包括显式规则、隐式规则、变量使用、通配符、文件搜寻、伪目标、多目标和静态模式的运用,以及如何利用C/C++编译器自动生成依赖性,帮助读者理解和编写高效Makefile。
摘要由CSDN通过智能技术生成

跟我一起写Makefile细节总结学习笔记

CSDN下载

第一,二章

此篇仅为方便查阅记忆,详细的请看seisman/how-to-write-makefile: 跟我一起写Makefile重制版 (github.com)

Makefile介绍

,,Tab键,使用变量,-减号,

规则

target ... : prerequisites ...
	recipe
	...
	...

原始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

稍微简化后的

objects = main.o kbd.o command.o display.o \
	insert.o search.o files.o utils.o
edit : $(objects)
	cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
.PHONY : clean
clean :
	-rm edit $(objects)

注意

命令的Tab键位不可用空个代替。

在我们的 makefile 中以 $(objects) 的方式来使用这个变量

反斜杠(\ )是换行符的意思。

.PHONY 表示 clean 是一个“伪目标”。

一个小减号的意思就是,也 许某些文件出现问题,但不要管,继续做后面的事

不成文的规矩是——“clean 从来都是放在文件的最 后”。

Makefile 里主要包含了五个东西:

显式规则、隐式规则、变量定义、指令和注释。

  1. 显式规则。显式规则说明了如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出要 生成的文件、文件的依赖文件和生成的命令。
  2. 隐式规则。由于我们的 make 有自动推导的功能,所以隐式规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。 8 Chapter 2. makefile 介绍 , 发行版本 1.0
  3. 变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像你 C 语 言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
  4. 指令。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样; 还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
  5. 注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用 # 字符,这个就像 C/C++ 中的 // 一样。如果你要在你的 Makefile 中使用 # 字符,可以用反斜杠进行转义,如:# 。 最后,还值得一提的是,在 Makefile 中的命令,必须要以 Tab 键开始。

书写规则

在规则中使用通配符

另给一个变量使用通配符的例子:

  1. 列出一确定文件夹中的所有 .c 文件。

    objects := $(wildcard *.c) 
    
  2. 列出 (1) 中所有文件对应的 .o 文件,在(3)中我们可以看到它是由 make 自动编译出的:

     $(patsubst %.c,%.o,$(wildcard *.c)) 
    
  3. 由 (1)(2) 两步,可写出编译并链接所有 .c 和 .o 文件

    objects := $(patsubst %.c,%.o,$(wildcard *.c)) 
    foo : $(objects) 
    	cc -o foo $(objects)文件搜寻
        
    

文件搜寻

vpath <pattern> <directories>

​ 为符合模式<pattern>的文件指定搜索目录<directories>

vpath <pattern>

​ 清除符合模式 <pattern> 的文件的搜索目录。

vpath

​ 清除所有已被设置好了的文件搜索目录。

vpath 使用方法中的 <pattern> 需要包含 % 字符。% 的意思是匹配零或若干字符,(需引用 % ,使 用 \ )例如,%.h 表示所有以 .h 结尾的文件。<pattern>指定了要搜索的文件集,而<directories> 则 指定了 < pattern> 的文件集的搜索的目录。例如:

vpath %.h ../headers

伪目标

当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明 一个目标是“伪目标”,向 make 说明,不管是否有这个文件,这个目标就是“伪目标”。 .PHONY : clean 只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。 于是整个过程可以这样写:

.PHONY : clean
clean :
		rm *.o temp

多目标(自动变量)

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

等价于

bigoutput : text.g
	generate text.g -big > bigoutput
littleoutput : text.g
	generate text.g -little > littleoutput

静态模式

objects = foo.o bar.o
	all: $(objects)
$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

上面的例子中,指明了我们的目标从 $object 中获取,%.o 表明要所有以 .o 结尾的目标,也就是 foo.o bar.o ,也就是变量 $object 集合的模式,而依赖模式 %.c 则取模式 %.o 的 % ,也就是 foo bar ,并为其加下 .c 的后缀,于是,我们的依赖目标就是 foo.c bar.c 。而命令中的 $< 和 @ 则是自动化变量, @ 则是自动化 变量, @则是自动化变量,< 表示第一个依赖文件,$@ 表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价 于下面的规则:

foo.o : foo.c
	$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
	$(CC) -c $(CFLAGS) bar.c -o bar.o

试想,如果我们的 %.o 有几百个,那么我们只要用这种很简单的“静态模式规则”就可以写完一堆 规则,实在是太有效率了。“静态模式规则”的用法很灵活,如果用得好,那会是一个很强大的功能。再 看一个例子:

files = foo.elc bar.o lose.o
    
$(filter %.o,$(files)): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
	emacs -f batch-byte-compile $<

( f i l t e r (filter %.o, (filter(files)) 表示调用 Makefile 的 filter 函数,过滤“$files”集,只要其中模式为“%.o”的 内容。其它的内容,我就不用多说了吧。这个例子展示了 Makefile 中更大的弹性。

自动生成依赖性

在 Makefile 中,我们的依赖关系可能会需要包含一系列的头文件,比如,如果我们的 main.c 中有一 句 #include “defs.h” ,那么我们的依赖关系应该是:

main.o : main.c defs.h

但是,如果是一个比较大型的工程,你必需清楚哪些 C 文件包含了哪些头文件,并且,你在加入或 删除头文件时,也需要小心地修改 Makefile,这是一个很没有维护性的工作。为了避免这种繁重而又容 易出错的事情,我们可以使用 C/C++ 编译的一个功能。大多数的 C/C++ 编译器都支持一个“-M”的 选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例如,如果我们执行下面的命令:

cc -M main.c

其输出是:

main.o : main.c defs.h

于是由编译器自动生成的依赖关系,这样一来,你就不必再手动书写若干文件的依赖关系,而由编 译器自动生成了。需要提醒一句的是,如果你使用 GNU 的 C/C++ 编译器,你得用 -MM 参数,不然,-M 参数会把一些标准库的头文件也包含进来。

gcc -M main.c 的输出是

main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
	/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
	/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
	/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
	/usr/include/bits/sched.h /usr/include/libio.h \
	/usr/include/_G_config.h /usr/include/wchar.h \
	/usr/include/bits/wchar.h /usr/include/gconv.h \
	/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
	/usr/include/bits/stdio_lim.h

gcc -MM main.c 的输出则是:

main.o: main.c defs.h
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
什么是 makefile?或许很多 Winodws 的程序员都不知道这个东西,因为那些 Windows 的集成开 发环境(integrated development environment,IDE)都为你做了这个工作,但我觉得要作一个好的 和专业的程序员,makefile 还是要懂。这就好像现在有这么多的 HTML 编辑器,但如果你想成为一个专 业人士,你还是要了解 HTML 的标签的含义。特别在 Unix 下的软件编译,你就不能不自己 makefile 了,会不会 makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。 因为,makefile 关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、 模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需 要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚 本一样,其中也可以执行操作系统的命令。 makefile 带来的好处就是——“自动化编译”,一旦好,只需要一个 make 命令,整个工程完全 自动编译,极大的提高了软件开发的效率。make 是一个命令工具,是一个解释 makefile 中指令的命令 工具,一般来说,大多数的 IDE 都有这个命令,比如:Delphi 的 make,Visual C++ 的 nmake,Linux 下 GNU 的 make。可见,makefile 都成为了一种在工程方面的编译方法。 现在讲述如何 makefile 的文章比较少,这是我想这篇文章的原因。当然,不同产商的 make 各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对 GNU 的 make 进 行讲述,我的环境是 RedHat Linux 8.0,make 的版本是 3.80。毕竟,这个 make 是应用最为广泛的, 也是用得最多的。而且其还是最遵循于 IEEE 1003.2-1992 标准的(POSIX.2)。 在这篇文档中,将以 C/C++ 的源码作为基础,所以必然涉及一些关于 C/C++ 的编译的知识。关于 这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是 UNIX 下的 GCC 和 CC。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泷fyk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值