博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
makefile(07)_路径搜索
阅读量:7014 次
发布时间:2019-06-28

本文共 4745 字,大约阅读时间需要 15 分钟。

17.Make中的路径搜索_上

17.0.实验素材

源文件位于: src目录下

源文件:main.c

#include 
#include "func.h"int main(){ foo(); return 0;}

源文件:func.c

#include 
#include "func.h"void foo(){ printf("void foo() : %s\n", "Hello, D.T.Software ...");}

头文件位于: inc目录下

头文件func.c

#ifndef FUNC_H#define FUNC_Hvoid foo();#endif

17.1. 工程源码组织方式

问题:实际的工程项目中,所有的源文件和头文件都放在一个文件夹吗?

实际的工程中,源码和头文件都是按照模块划分的,举例如下:
makefile(07)_路径搜索
项目中的makefile必须能够正确的定位源文件和依赖文件,最终编译产生可执行程序。
实验1:
当源码组织目录如下时,下面的makefile能够编译成功吗?
makefile(07)_路径搜索

OBJS := func.o main.ohello.out : $(OBJS)    @gcc -o $@ $^    @echo "Target File ==> $@"$(OBJS) : %.o : %.c func.h    @gcc  -o $@ -c $<

编译结果:

makefile(07)_路径搜索
由于make默认只会在makefile所在的文件家去查找源文件和头文件,所以自然会导致编译报错。

17.2. 预定义变量VPATH

VPATH变量的值用于指示make如何查找文件,不同文件夹可以作为VPATH的值同时出现,可以使用空格,冒号,分号这样的分隔符进行分隔,如VPATH := src inc

实验2:源码目录如下(注意这里存在两个同名的C文件),下面的makefile编译结果如何?
makefile(07)_路径搜索

OBJS := func.o main.oINC := incSRC := srcVPATH := $(INC) $(SRC)hello.out : $(OBJS)    @gcc -o $@ $^    @echo "Target File ==> $@"$(OBJS) : %.o : %.c func.h    @gcc  -o $@ -c $<

编译结果:

makefile(07)_路径搜索
原因:VPATH只能决定make的搜索路径,无法决定命令的搜索路径,对特定编译命令(gcc),需要独立指定编译搜索路径。
makefile(07)_路径搜索
修改makefile 内容如下,再进行实验:

OBJS := func.o main.oINC := incSRC := srcVPATH := $(INC) $(SRC)CFLAGS := -I $(INC)hello.out : $(OBJS)    @gcc -o $@ $^    @echo "Target File ==> $@"$(OBJS) : %.o : %.c func.h    @gcc $(CFLAGS) -o $@ -c $<

编译和运行结果:

makefile(07)_路径搜索
此时,我们看到编译结果正确,但运行后发现被编译的时inc目录下的func.c文件,这可能不是我们预期的。
原因:当make在当前文件夹找不到需要的文件时,VPATH会被使用,make会在VPATH指定的文件夹中依次进行搜索文件,当多个文件夹存在同名文件时,选择第一次搜索到的文件。
实验3:
此时,我们讲源文件中的.c文件更名为.cpp文件,进行上面的实验

当inc文件夹意外出现文件(c/cpp文件),那么可能产生编译错误。

17.3. vpath关键字

为了解决上面的问题,我们使用vpath关键字,为不同类型的文件指定不同的搜索路径

语法:eg : vpath %.h inc或者 vpath %.h src
取消搜索路径:
取消已经设置的某个所搜规则:vpath patten,
eg: vpath %.h inc # 在inc中搜索.h文件
vpath %.h # 不再inc中搜索.h文件
取消所有已经设置的规则
vpath

OBJS := func.o main.oINC := incSRC := srcCFLAGS := -I $(INC)vpath %.h $(INC)vpath %.c $(SRC)hello.out : $(OBJS)    @gcc -o $@ $^    @echo "Target File ==> $@"# vpath %.h$(OBJS) : %.o : %.c func.h    @gcc $(CFLAGS) -o $@ -c $<

17.4. 总结:

VPATH变量用于指示make如何查找文件,make会在VPATH指定的文件夹中依次搜索文件

vpath 关键字可以为不同类型的文件指定不同的搜索路径,比VPATH更灵活易用,可动态设置取消搜索路径。

18.Make中的路径搜索_下

18.1.VPATH和vpath同时使用

问题一:VPATH和vpath同时出现时,make会如何处理?

makefile(07)_路径搜索

VPATH := src1CFLAGS := -I incvpath %.c src2vpath %.h incapp.out : func.o main.o    @gcc -o $@ $^    @echo "Target File ==> $@"%.o : %.c func.h    @gcc $(CFLAGS) -o $@ -c $<

实验结果:

makefile(07)_路径搜索
实验结论:
make首先在当前文件夹搜索需要的文件,如果失败:
Make优先在vpath指定的文件夹中搜索目标文件
当vpath搜索失败时,转而搜索VPATH指定的文件夹

18.2.vpath对同一个patten指定多个文件夹

问题2:当vpath对同一个patten指定多个文件夹时,make会如何处理?

makefile(07)_路径搜索

CFLAGS := -I incvpath %.c src1vpath %.c src2vpath %.h incapp.out : func.o main.o    @gcc -o $@ $^    @echo "Target File ==> $@"%.o : %.c func.h    @gcc $(CFLAGS) -o $@ -c $<

实验结果:makefile(07)_路径搜索

实验结论:当vpath对同一个patten指定多个文件夹时,make会依次自上而下,搜索指定的文件夹,直到找到目标。

18.3.目标文件位置

问题3:当使用VPATH指定搜索路径后,make如何确定最终目标文件的位置?

下面的项目中,将如何生成可执行程序?
makefile(07)_路径搜索
实验结论:
当app.out完全不存在,make会在当前文件夹下创建app.out
当src文件夹下存在app.out:
所有目标和依赖的新旧关系不变,make不会重新创建app.out
当依赖文件被更新,make在当前文件夹下创建app.out
问题:当依赖关系改变时,如何使得src下的app.out被更新?

18.4.GPATH变量

上面问题,我们可以使用GPATH特殊变量指定目标文件夹来解决。

GPATH := srcVPATH := srcCFLAGS := -I incapp.out : func.o main.o    @gcc -o $@ $^    @echo "Target File ==> $@"%.o : %.c inc/func.h    @gcc $(CFLAGS) -o $@ -c $<

当app.out完全不存在,make默认在当前文件夹创建app.out

当app.out存在于src,并且依赖文件被更新,make在src文件夹中创建目标文件
18.5.工程建议:
尽量使用vpath为不同文件指定搜索路径;
不要在源码文件夹中生成目标文件,为编译得到的结果创建独立文件夹
尽量避免使用VPATH如果一定要使用,考虑GPATH的使用

19.Make中的路径搜索_综合示例

19.1.需求分析

工程项目中不希望源文件夹在编译时被改动(只读文件夹)

在编译时自动创建文件夹(build)用于存放编译结果
编译过程中国能够自动搜索到需要的文件
makefile易于扩展,能够复用相同类型的项目
支持调试版本和编译选项

19.2.项目类型

makefile(07)_路径搜索

19.3.工具原料:

$(wildcard $(DIR)/ _patten) 获取$(DIR)文件夹中满足_patten的文件

$(notdir _names) 去除_names中每一个文件名的路径前缀
$(patsubst _patten, replacement, _text) 将_text中符合_patten的部分替换为replacement

19.4.关键技巧:

1.自动获取文件列表(函数调用)

SRSC := $(waidcard src/*.c)
2.根据源文件列表生成目标文件列表(变量的替换)
OBJS := $(SRC:.c=.o)
3.替换每一个目标文件的路径前缀(函数调用)
OBJS := $(patsubst src/%, build/%, $(OBJS))

19.5.编译文件的依赖

makefile(07)_路径搜索

19.6.最终方案:

.PHONY : all cleanDIR_BUILD := buildDIR_SRC := srcDIR_INC := incTYPE_INC := .hTYPE_SRC := .cTYPE_OBJ := .oCC := gccLFLAGS :=CFLAGS := -I $(DIR_INC)ifeq ($(DEBUG),true)CFLAGS += -gendifMKDIR := mkdirRM := rm -frAPP := $(DIR_BUILD)/app.outHDRS := $(wildcard $(DIR_INC)/*$(TYPE_INC))HDRS := $(notdir $(HDRS))OBJS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC))OBJS := $(OBJS:$(TYPE_SRC)=$(TYPE_OBJ))OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_BUILD)/%, $(OBJS))vpath %$(TYPE_INC) $(DIR_INC)vpath %$(TYPE_SRC) $(DIR_SRC)all : $(DIR_BUILD) $(APP)    @echo "Target File ==> $(APP)"$(DIR_BUILD) :    $(MKDIR) $@$(APP) : $(OBJS)    $(CC) $(LFLAGS) -o $@ $^$(DIR_BUILD)/%$(TYPE_OBJ) : %$(TYPE_SRC) $(HDRS)    $(CC) $(CFLAGS) -o $@ -c $

问题:

对于规模较小的项目,makefile是否也需要使用自动变量生成依赖关系的解决方案?
规模较小的项目没必要使用自动生成依赖关系的解决方案,可以直接让源文件依赖于头文件(易于维护)

19.7.总结:

工程项目中不希望源码文件夹在编译时被改动

模式规则的灵活运用使得makefile具有复用性
变量的灵活运用使得makefile具有可扩展性

转载于:https://blog.51cto.com/11134889/2108422

你可能感兴趣的文章
PHP错误级别 error_reporting() 函数详解
查看>>
jdk环境变量配置
查看>>
为网卡配置多个IP地址(windows)
查看>>
句柄的理解
查看>>
手机网络连接问题
查看>>
Go -- runtime.Gosched()的作用分析
查看>>
Java Lambda 表达式 对 Map 对象排序
查看>>
WIndows 使用VS编译 Lua5
查看>>
转 VB ListView控件各种操作详解
查看>>
查看name的状态,是属于active还是standby
查看>>
&lt;LeetCode OJ&gt; 337. House Robber III
查看>>
PSR规范
查看>>
[Javascript] this in Function Calls
查看>>
MinGW32和64位交叉编译环境的安装和使用
查看>>
laravel 增加不存在数据库的字段
查看>>
什么是“单播”“组播”和“多播”
查看>>
flex---->图表控件
查看>>
Android Developers:在命令行构建和运行
查看>>
firefox 不识别background-position-y / background-position-x
查看>>
分析函数调用关系图(call graph)的几种方法
查看>>