Makefile 入门

来源:互联网 发布:avscanner是什么软件 编辑:程序博客网 时间:2024/04/29 15:58

原文链接:http://harttle.com/2014/01/01/makefile.html

make是软件开发中常用的工具程序(Utility software),常被用来构建C程序。make通过读取叫做“makefile”的文件,来自动化建构软件。

虽然make常被用来构建C程序,但它可用于绝大多数的文件处理过程。例如,更新一批图片的缩略图: http://harttle.github.io/2013/10/26/auto-thumb/

它是一种转化文件形式的工具,转换的目标称为“target”;
与此同时,它也检查文件的依赖关系,如果需要的话,它会调用一些外部软件来完成任务。
它的依赖关系检查系统非常简单,主要根据依赖文件的修改时间进行判断。
大多数情况下,它被用来编译源代码,生成结果代码,然后把结果代码连接起来生成可执行文件或者库文件。
它使用叫做Makefile的文件来确定一个target文件的依赖关系,然后把生成这个target的相关命令传给shell去执行。

中文Tutorial

基本知识

编译

对于C语言,产生可执行程序包括这样的步骤:
1. 预处理源文件(.c
* 替换预处理命令(如 #define
* 展开头文件(.h,包括静态链接库的头文件)到引用的源文件
2. 依次编译处理过的源文件,然后进行汇编,生成对应的目标文件(.o
3. 链接(静态链接)目标文件和静态链接库(静态链接库的源文件生成的目标文件,.a),生成可执行的二进制文件。

gcc 不会自动链接到静态链接库(libstdio.so除外),需要以参数的形式指定。g++ 会自动解析并进行链接。动态链接库(.so)则是运行时由操作系统解析的。

示例

target: require1 require2    shell command

make 命令会寻找当前目录下的 makefile,寻找其中的第一条规则,然后执行 shell command 来生成 target。如果发现 requireN 同时也依赖于其他项,则会自动调用其对应的 shell command 并生成它。另外,在整个过程中,make 会比较 targetrequireN 的时间戳,以判断是否需要重新生成。

变量

变量的定义与引用:

# 递归扩展变量,在调用时展开objects1 = a.o b.o# 简单扩展变量,在赋值时展开objects2 = $(objects) c.omain.o: $(objects)    gcc -o main.o $(objects2)
  • 如果要在makefile中真实的 $,需要用 $$ 来表示。

  • 注意变量赋值时不能使用通配符。但是在规则中,通配符是可以使用的:

    print: *.c    some command

自动化变量

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

隐含规则

make 会通过隐含规则自动推导依赖关系,可以帮助我们简化 makefile。例如:

foo : foo.o bar.o     cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS) 

并没有指明如何生成 .o 文件,这时 make 会生成:

foo.o : foo.c     cc –c foo.c $(CFLAGS) bar.o : bar.c     cc –c bar.c $(CFLAGS)

隐含规则中的编译器与上一级依赖中的相同,因此产生 foo 的规则中,cc 命令是不可省略的。

使用函数

可以使用 make 内建函数来完成某些功能。语法如下:

$(<function> <arguments>) 

如:

sources := $(shell ls *.c)

make 中的函数包括:字符串处理,文件名操作,流程控制,call函数,origin函数,shell函数。

进阶技巧

伪目标

伪目标不是一个文件,而只是一个标签,使得依赖关系的书写更加灵活。.PHONY 用来声明伪目标(但不是必须的),这时可以避免 make 去检查同名的文件。例如:

.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 

静态模式

静态模式可以更加容易地定义多目标的规则,语法如下:

<targets ...>: <target-pattern>: <prereq-patterns ...>     <commands> 

例如,下面的makefile将对所有的 .o 文件分别生成一条依赖关系。

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

总控 makefile

在makefile中,可以执行子文件夹的makefile:

subsystem:     $(MAKE) -C subdir

这里的$(MAKE)是为了方便维护make的参数。总控makefile的变量可以传递到下级:

export variable = value# or use the followingvariable = value export variable 

自动生成依赖

对于每个 .c 文件,我们一般会需要如下的依赖关系:

main.o : main.c defs.h

然而,有时候存在大量的 .c 文件,我们需要得到每个 .c 对应的 .h。借助于 gcc,可以自动探测这些依赖:

sources = main.c stack.c maze.c-include $(sources:.c=.d)%.d: %.c    @set -e; rm -f $@; \    $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \    rm -f $@.$$$$

如上的makefile定义了 .c 的列表变量,然后载入对应的 .d 文件,这时会有文件不存在的警告产生,此时 make 会采用下面的模式生成 .d

  • 设置shell,发生错误立即退出
  • 得到依赖关系(如 main.o main.c defs.h),存为 .d.XXXXXXXX为当前进程号)
  • sed 替换(例如将 main.o : main.c defs.h 转成 main.o main.d : main.c defs.h),使得 .d 也能得到更新。
  • 删除临时文件
0 0
原创粉丝点击