转自 http://blog.csdn.net/todd911/article/details/42750233shell
当你有一长串文件要制定时,为了简化此过程,make提供了通配符(wildcard),此功能也被称为文件名模式匹配。makewindows
的通配符如同Bourne shell的~、*、?、[...]和[^...]。举例来讲,*.*会被扩展成文件名中包含点号的全部文件,一个问号表明布局
任何单一字符,而[...]表明一个字符集。若要取得字符集的补集,则可使用[^...]。测试
此外,“~”符号能够用来表明当前用户的主目录,一个“~”符号以后若跟着用户的名称则表明该用户的主目录。this
以工做目标充当标签来表明命令脚本,一般会有些用处。任何不表明文件的工做目标就叫作假想工做目标(phony target)。spa
另外一个标准的假想工做目标称为clean:.net
clean:blog
rm -f *.o get
一般,make老是会执行假想工做目标,由于对应于该规则的命令并不会建立以该工做目标为名称的文件。io
切记,make没法区分文件形式的工做目标和假想工做目标,若是当前目录中恰好出现于假想工做目标同名的文件,make
将会在它的相依图中创建该文件与假想工做目标的关系。例如,运行make clean时,工做目录中恰好存在clean这个文件,
那么将会产生使人困惑的信息:
make clean
make:‘clean’ is up to date.
由于大多数的假想工做目标并未指定必要条件,clean工做目标老是被视为已经更新,全部相应的命令不会被执行。
为了不这个问题,GNU make提供了一个特殊的工做目标-----.PHONY,用来告诉make,该工做目标不是一个真正的
文件。当你要声明假想工做目标时,只要将该工做目标指定成.PHONY的一个必要条件便可:
.PHONY:clean
clean:
rm -f *.o
如今,即便当前目录中存在名为clean的文件,make仍是会执行对应于clean的命令。
许多makefile多少都会包含一组标准的假想工做目标,下面列出了这些标准的假想工做目标。
工做目标 功能
all 执行编译应用程序的全部工做。
install 从已编译的二进制文件进行应用程序的安装
clean 将产生自源代码的二进制文件删除
distclean 删除编译过程当中所产生的任何文件。
TAGS 创建可供编辑其使用的标记表。
info 从Texinfo源代码来建立GNU info文件。
check 执行与应用程序相关的任何测试。
最简答的变量具备以下的语法:
${variale-name}
这表明咱们想要扩展名为variable-name的变量。任何文字均可以包含在变量之中,并且大多数字符均可以用在变量名称
上。通常来讲,必须$()或${}将变量名称括住,这样make才会认得。
一般makefile文件都会定义许多变量,不过其中有许多特殊变量是make自动定义的。这些变量中若干可控制make
的行为,其他变量则是供make用来跟用户的makefile文件沟通。
当规则相符时,make会设定自动变量。经过它们,你能够取用工做目标以及必要条件中的元素,因此你没必要指明任何文件
名称。要避免重复,自动变量就至关有用,它们也是定义较通常模式规则中不可少的项目。
下面是7个核心的自动变量:
$@ 工做目标的文件名。 //针对每个目标都适用
$% 档案文件成员结构中的文件名元素。
$< 第一个必要条件的文件名。
$? 时间戳在工做目标(时间戳)以后的全部必要条件,并以空格隔开这些必要条件。
$^ 全部必要条件的文件名,并以空格隔开这些文件名。这份列表已经删除重复的文件名,由于对大多数的应用而言,好比
编译、复制等,并不会用到重复的文件名。
$+ 如同$^,表明全部必要条件的文件名,并以空格隔开这些文件,它包含重复的文件名。此变量会在特殊的情况下被建立,
好比将自动变量传递给链接器时重复的值是有意义的。
$* 工做目标的主文件名。一个文件名称是由两个部分组成:主文件名和扩展名。请不要在模式规则之外使用此变量。
以前的makefile文件:
main:main.o myutil.o
gcc main.o myutil.o -o main
main.o:main.c myutil.h
gcc -c main.c myutil.h
myutil.o:myutil.c myutil.h
gcc -c myutil.c
替换成适当的自动变量后:
main:main.o myutil.o
gcc $^ -o $@
main.o:main.c myutil.h
gcc -c $^
myutil.o:myutil.c myutil.h
gcc -c $^
到目前为止的例子都很简单:makefile与全部的源文件都存放在同一目录下。真实的项目中可能会比较复杂。按源代码
树的布局惯例,头文件会被放到include目录中,而源文件会被放到src目录里,并把makefile放到它们的上层目录,布局
以下:
根目录
|---makefile
|----|include|
| |___myutil.h
|___|src|
|----myutil.c
|__main.c
各文件内容以下:
main.c:
#include <stdio.h>
#include "myutil.h"
int main(void) {
myprint();
return 0;
}
myutil.h:
void myprint();
myutil.c:
#include <stdio.h>
void myprint(void) {
printf("this is myprint function.\n");
}
makefile:
main:main.o myutil.o
gcc $^ -o $@
main.o:main.c myutil.h
gcc -c $^
myutil.o:myutil.c myutil.h
gcc -c $^
执行make的结果以下:
make: *** No rule to make target `main.c', needed by `main.o'. Stop.
由于main.c不在当前目录,因此make找不到这个源文件,咱们可使用VPATH和vpath来告诉make到不一样的目录去查找
源文件,能够再makefile文件中对VPATH进行以下赋值动做:
VPATH=src include
执行make,依然不行:
gcc -c src/main.c include/myutil.h
src/main.c:2:20: fatal error: myutil.h: No such file or directory
compilation terminated.
make: *** [main.o] Error 1
由于gcc没法找到引入文件,咱们只要使用正确的-I选项来自定义隐含编译规则就能够解决这个问题了:
VPATH=src include
CPPFLAGS=-I include
main:main.o myutil.o
gcc $(CPPFLAGS) $^ -o $@
main.o:main.c myutil.h
gcc $(CPPFLAGS) -c $^
myutil.o:myutil.c myutil.h
gcc $(CPPFLAGS) -c $^
执行make:
gcc -I include -c src/main.c include/myutil.h
gcc -I include -c src/myutil.c
gcc -I include main.o myutil.o -o main
成功编译。
VPATH变量的内容是一份目录列表,可供make搜索其所须要的文件。这份目录列表可用来搜索工做目标以及必要条件,
但不包含脚本中说起的文件。这份目录列表的分割符在Unix上能够是空格或冒号,在windows上可使空格或分号。
虽然VPATH变脸能够解决以上的搜索问题,可是也有限制。make将会为它所须要的任何文件搜索VPATH列表中的每一个目录,
若是多个目录出现同名的文件,则make只会获取第一个被找到的文件,这可能会形成问题。
此时可使用vpath指令,这个指令的语法以下:
vpath pattern directory-list
全部以前的VPATH变量能够改写成:
vpath %.c src
vpath %.h include
如今咱们告诉了make应该在src目录中搜索.c文件,在include目录中搜索.h文件。