学习自狄泰软件学院唐佐临老师Makefile课程,文章中图片取自老师的PPT,仅用于个人笔记。
实验1 VPATH 和 vpath 同时指定搜索路径
实验2:当使用vpath 对.c文件指定多个文件夹时
实验3 使用GPATH 特殊变量指定目标文件夹


VPATH变量和vpath关键字同时指定搜索路径。
实验1 VPATH 和 vpath 同时指定搜索路径
mhr@ubuntu:~/work/makefile1/18$ tree
.
├── inc
│ └── func.h
├── main.c
├── makefile
├── src1
│ └── func.c
└── src2
└── func.c
makefile
VPATH := src1
CFLAGS := -I inc
vpath %.c src2
vpath %.h inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c func.h
@gcc $(CFLAGS) -o $@ -c $<
main.c
#include <stdio.h>
#include "func.h"
int main()
{
foo();
return 0;
}
src1/func.c
#include <stdio.h>
#include "func.h"
void foo()
{
printf("void foo() : %s\n", "This file is from src1 ...");
}
src2/func.c
#include <stdio.h>
#include "func.h"
void foo()
{
printf("void foo() : %s\n", "This file is from src2 ...");
}
inc/func.h
#ifndef FUNC_H
#define FUNC_H
void foo();
#endif
mhr@ubuntu:~/work/makefile1/18$ make
Target File ==> app.out
mhr@ubuntu:~/work/makefile1/18$ ./app.out
void foo() : This file is from src2 ...
mhr@ubuntu:~/work/makefile1/18$
结果表明 当VPATH 和 vpath 同时指定搜索路径,优先选择 vpath 指定的所搜路径
改1:
将 src/func.c 改为 src/func.cpp 会发生什么?
.
├── inc
│ └── func.h
├── main.c
├── makefile
├── src1
│ └── func.cpp
└── src2
└── func.c
mhr@ubuntu:~/work/makefile1/18$ make
Target File ==> app.out
mhr@ubuntu:~/work/makefile1/18$
mhr@ubuntu:~/work/makefile1/18$ ./app.out
void foo() : This file is from src2 ...
mhr@ubuntu:~/work/makefile1/18$

改2
├── inc
│ └── func.h
├── main.c
├── makefile
├── makefile.1
├── makefile.2
├── makefile.3
├── src1
│ └── func.cpp
└── src2
└── func.cpp
mhr@ubuntu:~/work/makefile1/18$
mhr@ubuntu:~/work/makefile1/18$ make
g++ -c -o func.o src1/func.cpp
src1/func.cpp:2:18: fatal error: func.h: No such file or directory
#include "func.h"
^
compilation terminated.
<builtin>: recipe for target 'func.o' failed
make: *** [func.o] Error 1
mhr@ubuntu:~/work/makefile1/18$
说明; 从 g++ 可以看出 ,make解释器启用了隐式规则,make 的行为如下:
但是,在当前目录下没有发现 .c文件,于是首先去vpath关键字指定的 src2中查找依赖文件,并没有找到,make继续到变量VPATH指定的文件夹中查找依赖文件,也没有找到需要的.c文件,至此应该报错了。但是make解释器并没有报错,因为他发现隐式规则中有一条规则可以 通过.cpp文件生成.o文件,于是make 开始查找func.cpp ,同样在当前目录下没有,于是首先去 关键字vpath指定的文件夹下搜索,但是make解释器发现vpath关键字没有指定 cpp 文件去哪儿找,所以make解释器又退而求其次的去 VPATH变量指定的文件夹下搜索 func.cpp文件,于是在 src1目录下找到了 func.cpp文件。于是开始通过g++编译器开始编译。但是在隐式规则中,并没有告诉g++命令到哪一个目录去寻找 .h 头文件,所以编译报错。


实验2:当使用vpath 对.c文件指定多个文件夹时
.
├── inc
│ └── func.h
├── main.c
├── makefile
├── src1
│ └── func.c
└── src2
└── func.c
makefile
CFLAGS := -I inc
vpath %.c src1
vpath %.c src2
vpath %.h inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c func.h
@gcc $(CFLAGS) -o $@ -c $<
mhr@ubuntu:~/work/makefile1/18$ make
Target File ==> app.out
mhr@ubuntu:~/work/makefile1/18$ ./app.out
void foo() : This file is from src1 ...
mhr@ubuntu:~/work/makefile1/18$
改1
├── inc
│ └── func.h
├── main.c
├── makefile
├── src1
│ └── func.cpp
└── src2
└── func.c
makefile
CFLAGS := -I inc
vpath %.c src1
vpath %.c src2
vpath %.h inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c func.h
@gcc $(CFLAGS) -o $@ -c $<
mhr@ubuntu:~/work/makefile1/18$
mhr@ubuntu:~/work/makefile1/18$ make
Target File ==> app.out
mhr@ubuntu:~/work/makefile1/18$ ./app.out
void foo() : This file is from src2 ...
mhr@ubuntu:~/work/makefile1/18$
先搜索src1,没有搜索到。再去搜索src2。
改2
├── inc
│ └── func.h
├── main.c
├── makefile
├── src1
│ └── func.cpp
└── src2
└── func.cpp
makefile
CFLAGS := -I inc
vpath %.c src1
vpath %.c src2
vpath %.h inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c func.h
@gcc $(CFLAGS) -o $@ -c $<
mhr@ubuntu:~/work/makefile1/18$ make
make: *** No rule to make target 'func.o', needed by 'app.out'. Stop.
mhr@ubuntu:~/work/makefile1/18$
因为 make 在当前路径,src1,src2中都找不到 func.c, 于是make 又发现因事规则中可以通过cpp文件生成.o文件,但是在makefile中 没有找到 哪个vpath关键字指明了有cpp文件,所以找不到文件报错。



实验3 VPATH变量提示去他指定的文件夹中搜索 在当前目录找不到的文件
├── inc
│ └── func.h
├── main.c
├── makefile
└── src
└── func.c
makefile
VPATH := src
CFLAGS := -I inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c inc/func.h
@gcc $(CFLAGS) -o $@ -c $<
mhr@ubuntu:~/work/makefile1/18$ make
Target File ==> app.out
mhr@ubuntu:~/work/makefile1/18$
然后将生成的 app.out 拖到 src 下,这时候 根目录就没有 app.out了。此时make ,很多人会以为会在根目录重新生成一个 app.out ,可是实际效果如下:
mhr@ubuntu:~/work/makefile1/18$ make
make: 'app.out' is up to date.
mhr@ubuntu:~/work/makefile1/18$
因为此时make的编译决策是这样的:
make 之后,make解释器就会执行规则:
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
于是 make 就开始对比 目标文件app.out 与 依赖文件之间的新旧关系,于是开始在当目录寻找app.out,但是没有找到,但是make可以去 VPATH变量指定的文件夹中搜索,于是在src 中找到了目标文件,对比 他与依赖的的时间戳,于是认为 不需要更新app.out。
改1
此时如果我们改动 src/func.c, 则一定会生成新的app.out, 但是make 并没有将生成的 app.out 放在 src 中去替换 他下面的app.out。而是放在的根目录!!!!



实验3 使用GPATH 特殊变量指定目标文件夹
GPATH := src
VPATH := src
CFLAGS := -I inc
app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@"
%.o : %.c inc/func.h
@gcc $(CFLAGS) -o $@ -c $<

本文深入探讨了Makefile中VPATH、vpath及GPATH变量的使用,通过实验展示不同路径配置对源文件搜索的影响,以及如何正确设置以避免编译错误。
&spm=1001.2101.3001.5002&articleId=105701306&d=1&t=3&u=af4f7346794a4bedb9730d92f74a44f9)
3898

被折叠的 条评论
为什么被折叠?



