当源文件与 Makefile 文件的存放路径不同时,如何将源文件的路径告知Makefile文件呢?
方法有两种:一般搜索VPATH,选择搜索vpath。
两种方法本质不同:VPATH 是环境变量,是Makefile 中的一种特殊变量,使用时需要指定文件的路径;vpath 是关键字,按照模式搜索,或者说选择搜索,搜索的时候不仅需要加上文件的路径,还需要加上相应限制的条件。
使用什么样的搜索方法,主要是基于编译器的执行效率。当路径下的文件较少,或者是搜索的文件不能使用通配符表示时,使用VPATH最好。但是如果路径下的文件很多,或者可以使用通配符时建议使用vpath。因为VPATH 在搜索文件时没有附加限制条件,它会检索目录下的所有文件,每一个文件都会进行对比,速度慢,效率低;而 vpath 搜索包含搜索条件,过滤掉那些不符合条件的文件,而从规定的条件中搜索目标,查找效率高。
当执行make时,首先搜索当前目录下是否存在所需的文件,如果没有,则去VPATH这个变量的值所对应的路径寻找文件。
因此我们可以给变量VPATH进行赋值,从而指定搜索文件的路径。当存在多个路径时,需要使用空格或者是冒号隔开,执行make时,搜索的顺序是我们书写时的顺序。
比如下面的例子中,把src、car赋值给VPATH变量,执行make时,首先搜索当前目录下有没有源文件test.c,如果没有就去src目录下搜索,如果还找不到就去car目录下搜索。
此时生成的可执行文件test是在当前目录下的,当然也可以指定生成文件的路径。
VPATH := src car
#或者 VPATH := src:car
test:test.o
gcc -o $@ $^
(1)使用VPATH方式时,会搜索指定路径下所有的文件,而 vpath 更像是添加了限制条件,会过滤出一部分再去寻找,因此vpath也被称作“选择性搜索”。
(2)vpath有以下三种用法形式,PATTERN表示要寻找的文件,DIRECTORIES表示寻找路径。
【1】vpath PATTERN DIRECTORIES
vpath test.c src #在src路径下搜索文件 test.c
vpath test.c src car #在src、car路径下搜素文件test.c
vpath test.c src : car #在src、car路径下搜素文件test.cd
【2】vpath PATTERN
vpath test.c #清除符合文件test.c的搜索目录
#从搜索路径集中去掉将test.c文件所在的目录?
【3】vpath
vpath单独使用的意思是清除所有(已被设置的)文件搜索路径。
(3)在使用 vpath 的时候,搜索的条件中可以包含模式字符“%”,这个符号的作用是匹配一个或者是多个字符,例如“%.c”表示搜索路径下所有的 .c 结尾的文件。
假如有三个文件夹,分别是src文件夹(包含list1.c、list2.c、main.c 文件)、include 文件夹(包含list1.h、list2.h 文件)、Makefile文件,这三者处于同层目录中。
其中Makefile 文件内容:
main:main.o list1.o list2.o
gcc -o $@ $<
main.o:main.c
gcc -o $@ $^
list1.o:list1.c list1.h
gcc -o $@ $<
list2.o:list2.c list2.h
gcc -o $@ $<
执行make 时出现错误而编译停止,错误提示:
make:*** No rule to make target 'main.c',need by 'main.o'. stop.
重建最终目标文件 main 的时候需要 main.o 文件,然而去重建目标main.o 文件时,没有找到指定的 main.c 文件,这是错误的根本原因。所以我们可以为其添加文件搜索路径。
VPATH = ./src ./include #方法1
main:main.o list1.o list2.o
gcc -o $@ $<
main.o:main.c
gcc -o $@ $^
list1.o:list1.c list1.h
gcc -o $@ $<
list2.o:list2.c list2.h
gcc -o $@ $<
vpath %.c src #方法2 假如src中有.h文件、.c文件,这里就筛选出.c文件
vpath %.h include
main:main.o list1.o list2.o
gcc -o $@ $<
main.o:main.c
gcc -o $@ $^
list1.o:list1.c list1.h
gcc -o $@ $<
list2.o:list2.c list2.h
gcc -o $@ $<