makefile 的一些知识

来源:互联网 发布:windows 任务计划程序 编辑:程序博客网 时间:2024/04/26 03:37

命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集,“$@”表示目标集。

$(filter %.o,$(files))表示调用 Makefile 的 filter 函数,过滤“$filter”集,只要其中模式为“%.o”的内容。


makefile中所有的自动化变量

$@  
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于  
目标中模式定义的集合。  
  
$%  
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a 
(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix
下是[.a],Windows 下是[.lib]),那么,其值为空。  
  
$<  
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将
是符合模式的一系列的文件集。注意,其是一个一个取出来的。  
  
$?  
所有比目标新的依赖目标的集合。以空格分隔。  
  
$^  
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量
会去除重复的依赖目标,只保留一份。  

$+  
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。  
  
$*  
这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的
模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比
较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的
后缀是 make 所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因
为".c"是 make 所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是 GNU make 的,很有可能不兼容于其它版本的 make,所以,你应该尽量避免使用"$*",除非是在隐含规则
或是静态模式中。如果目标中的后缀是 make 所不能识别的,那么"$*"就是空值。  
  
当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有
一个函数库文件叫"lib",其由其它几个 object 文件更新。那么把 object 文件打包的比较
有效率的 Makefile 规则是:  
  
lib : foo.o bar.o lose.o win.o  
ar r lib $?  
  
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文
件,而另三个的值是一个文件列表。这七个自动化变量还可以取得文件的目录名或是在当前
目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是 GNU make 中老版本的特性,
在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是 Directory,就
是目录,"F"的含义就是 File,就是文件。  

------------------------------------------

但是,如果是一个比较大型的工程,你必需清楚哪些 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  

---------------------------------------------------

每当命令运行完后,make 会检测每个命令的返回码,如果命令返回成功,那么 make 会
执行下一条命令,当规则中所有的命令成功返回后,这个规则就算是成功完成了。如果一个
规则中的某个命令出错了(命令退出码非零),那么 make 就会终止执行当前规则,这将有可
能终止所有规则的执行。 
有些时候,命令的出错并不表示就是错误的。例如 mkdir 命令,我们一定需要建立一个
目录,如果目录不存在,那么 mkdir 就成功执行,万事大吉,如果目录存在,那么就出错了。
我们之所以使用 mkdir 的意思就是一定要有这样的一个目录,于是我们就不希望 mkdir 出错
而终止规则的运行。  
  
为了做到这一点,忽略命令的出错,我们可以在 Makefile 的命令行前加一个减号“-”
(在 Tab 键之后),标记为不管命令出不出错都认为是成功的。如:  
clean:  
-rm -f *.o  
  
还有一个全局的办法是,给 make 加上“-i”或是“--ignore-errors”参数,那么,
Makefile 中所有命令都会忽略错误。而如果一个规则是以“.IGNORE”作为目标的,那么这
个规则中的所有命令将会忽略错误。这些是不同级别的防止命令出错的方法,你可以根据你
的不同喜欢设置。  
  
还有一个要提一下的 make 的参数的是“-k”或是“--keep-going”,这个参数的意思
是,如果某规则中的命令出错了,那么就终目该规则的执行,但继续执行其它规则。  
  

---------------------------------------------------

说明:本文是学习《跟我一起写makefile》的知识笔记。

      如果需要请搜索《跟我一起写makefile》

      这是初学makefile非常好的教材。