Makefile学习笔记一

入职之前,在大学里的编程还从来没有接触过Makefile,都是用已经集成好的软件开发工具进行开发,只需要进行一些通过界面进行的配置,方能够完成整个工程的编译链接的过程,工作以后,发现需要根据Makefile来修改相关的设置,将整个编译链接的过程变成可控的,所以慢慢学习了相关的知识,在这里做些笔记和总结。
  我学习Makefile是参考电子工业出版社出版的《专业嵌入式软件开发-全面走向高质高效编程》一书中的Makefile一章,我觉得对我这种小白来讲挺好的。不过这本书已经停止出版了,可以上作者李云前辈的博客来找相关的内容,有需要的还可以评论中留言,我可以发给一下电子版的。
  1. 在Makefile中,.PHONY:目标,所构建的是假目标,make不会再将其作为一个文件来进行处理。在Makefile中定义变量时,其右值可以为空,引用变量需要采用 ( ) (变量名)或者 {变量名}。
2. 在Makefile中,“$”具有特殊的意思,想要用echo输出“$”,则必须使用两个连着的“$”,同时“$@”对bash shell也有特殊的意思,所以需要在“$$@”之前再加一个脱字符“\”。在Makefile中,存在几个自动变量,$@用于表示规则中的目标,当一个规则中有多个目标时,$@所指的是其中任何造成规则命令被运行的目标。$^表示的是规则中的所有先决条件,$<表示规则中的第一个先决条件。(由于在后面的工作中,发现这个经常会遇到,但是对目标和先决条件概念不是很清楚,所以这里再作一下介绍)
例如:
all:test
@echo “hello world”
test:
@echo “just for test!”
在这里,我们所构建的就是all目标,但是all目标依赖于test目标,这个依赖目标又被成为all目标的先决条件。make后面不加任何目标的时候,默认执行第一个目标,所以在顺序安排上,需要稍加注意。目标和先决条件之间表达的就是依赖关系,这种依赖关系指明在构建目标之前,必须保证先决条件先满足,也就是说先决条件要先被构建。所以这里会先打印 just for test!然后才会打印hello world!
3. 在Makefile中,有两个特殊变量,一个是MAKE,一个是MAKECMDGOALS,一个代表当前Makefile的命令名是什么,$(MAKE)的值就是”make”,这个在Makefile中需要运行别的Makefile时会用到,另一个是表示当前构建的目标名。比如make时,该值为空,make all时为all,make all test 时,值为all test。
4. 变量的类别有递归扩展变量和简单扩展变量。只用一个”=”符号定义的变量称为递归扩展变量。就是在Makefile中,直接用=号的话,可能会给人一种后面的程序在前面的程序之前执行的感觉。简单扩展变量是用”:=”来定义的,但是对于这种变量,make只对其进行一次展开。?=表示条件赋值,当变量没有被定义时就定义它,并且将右边的值赋给它,若变量已经被定义了,则不改变其原值。+=实现追加赋值。
5. 在Makefile中还可以实现条件赋值:当变量没有被定义时就定义它,并且将右边的值赋值给它;如果变量已经定义了,则不改变其原值。条件赋值可用于为变量赋默认值。用
?=来实现。另外还可以利用+=来实现追加赋值。
6. 在Makefile中定义的变量,有可能会被覆盖,因此可以使用override指令进行预防,格式为: override foo = x,然后后面就没有办法将foo进行覆盖了。
7. 在Makefile中可以使用相应的函数来进行相应的操作。
(1) $(abspath _names)中的abspath函数用于将_names中的各路径转换为绝对路径,并将转换后的结果返回。
(2) $(addprefix _prefix, _names)中的addprefix函数被用于给名字列表_names中的每一个名字增加前缀_prefix,并将增加了前缀的名字列表返回。
(3) $(addsuffix _suffix,_names)中的addsuffix函数被用于给名字列表_names中的每一个名字增加后缀_suffix,并将增加了后缀_suffix的名字列表返回。
(4) $(eval _text)中的eval使得Makefile具有动态语言的特征,eval使得make将再一次解析_text语句。
(5) $(filter _pattern,_text)函数被用于从一个名字列表_text中根据模式_pattern得到满足需要的名字列表并返回。
(6) $(filter-out _pattern,_text)中的filter-out被用于从名字列表_text中根据模式_pattern滤除一部分名字,并将滤除后的列表返回。
(7) $(notdir _names)中的notdir被用来从路径_names中抽取文件名,并将文件名返回。
(8) $(patsubst _pattern,_replacement,_text)中的patsubst函数被用来将名字列表_text中符合_pattern模式的名字替换为_replacement,并将替换后的名字列表返回。
(9) $(realpath _names)函数被用于获取_names所对应的真实路径名。
(10) $(strip _string)如果希望清除名字列表中的多余空格,strip函数就是最终选择。strip函数将_string中的多余空格去除后返回。
(11) $(wildcard _pattern)中的wildcard是通配符函数,通过它可以得到当前工作目录中满足_pattern模式的文件或着目录名列表。
8. 编写Makefile的第一步,不是一个猛子扎进去试着写一个规则并对之调试(一个规则是由目标、先决条件以及命令组成的),而应先采用面向依赖关系的思考方法勾勒出Makefile要表达怎样的依赖关系,这一点至关重要。
9. gcc -c test.c将生成test.o的目标文件
gcc -o app test.c将生成可执行程序app
gcc -c a.c -o a.o表示把源文件a.c编译成指定文件名为a.o的中间目标文件(其实在这里,你把-o a.o省掉,效果是一样的,因为中间文件默认与源文件同名,只是后缀变化)。其实通过最后一行的命令,不过是更改了生成的.o文件的名称而已。
10. Makefile中的
foo = a.c b.c c.c
bar := $(foo:.c=.o)在赋值的同时就可以完成文件名的后缀替换。是把所有的.c文件替换为.o,注意这里的bar只是存储的字符,并没有对文件的任何操作。

猜你喜欢

转载自blog.csdn.net/yunmao2882/article/details/84778290