LV02-05-Makefile-05-文件搜索
本文主要是makefile——文件搜索相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
参考方向 | 参考原文 |
Makefile | 跟我一起写Makefile |
点击查看文件搜索相关测试文件
各文件所在目录的结构如下:
1 | . |
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
一、源文件搜索
一般来说,一个大的工程下有大量的源文件,我们通常会把源文件分类,并存放在不同的目录中,便于查找和区分。所以,当 make 需要去找寻文件的依赖关系时,我们可以把一个路径告诉 make ,让 make 自动去找。
常见的搜索的方法的主要有两种:一般搜索 VPATH 和选择搜索 vpath 。表面上两者只是大小写的区别,其实两者在本质上也是不同的。
VPATH 是变量,更具体的说是环境变量, Makefile 中的一种特殊变量,使用时需要指定文件的路径;
vpath 是关键字,按照模式搜索,也可以说成是选择搜索。搜索的时候不仅需要加上文件的路径,还需要加上相应限制的条件。
【注意】 VPATH 与 vpath 仅仅是对于 Makefile 来说搜索目标和依赖文件的路径,但是对于命令行来说是无效的,也就是说,在执行 g++ 或者 gcc 时不会自动从 VPATH 或者 vpath 中自动搜索要包含的头文件等信息文件,这个时候就需要在命令行的命令中添加 -I 参数,以便于 gcc 等编译器寻找头文件。
1. VPATH
1.1使用格式
VPATH 变量会告诉 make 去哪里寻找相应的文件,如果没有指明这个变量, make 只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么, make 就会在当前目录找不到的时候,到所指定的目录中去找寻文件了。一般使用格式如下:
1 | # 1.单个路径写法 |
上边多个路径的写法指明了两个目录, src1 和 ../src2 。
【注意】
(1)当前目录永远是最高优先搜索的地方。如果当前目录下有我们要使用的文件,那么 make 就会使用我们当前目录下的文件。
(2)多个路径之间要使用空格或者是冒号隔开,表示在多个路径下搜索文件,搜索的顺序为我们书写时的顺序。
1.2使用实例
我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:
1 | mkdir test1 test2 |
所以现在的目录结构为:
1 | . |
- 不使用 VPATH 的 Makefile
1 | OBJ := main.o test1.o test2.o |
此时不出意外的话,我们会得到一条这样的报错信息:
1 | gcc -c main.c -o main.o |
- 使用 VPATH 的 Makefile
1 | OBJ := main.o test1.o test2.o |
此时我们再执行 make 命令,会得到如下的信息提示:
1 | gcc -c test1/test1.c -o test1.o |
可以发现,我们正常编译了所有文件,总的来说当 .c 源文件都位于 test1 和 test2 目录下的时候, VPATH 就成了必要了。
2. vpath
2.1使用格式
vpath 关键字它可以指定不同的文件在不同的搜索目录中。它有三种使用方法:
2.1.1设置搜索路径
1 | # 1.单个路径 |
为符合模式
1 | vpath test.c src # 在 src 路径下搜索文件 test.c |
【说明】
(1) vapth 使用方法中的可以包含 % 字符。 % 的意思是匹配零或若干字符。例如,
1 | vpath %.h ../headers |
该语句表示,要求 make 在 ../headers 目录下搜索所有以 .h 结尾的文件。(如果某文件在当前目录没有找到的话)。
(2)可以连续地使用 vpath 语句,以指定不同搜索策略。如果连续的 vpath 语句中出现了相同的 <pattern> ,或是被重复了的 <pattern> ,那么, make 会按照 vpath 语句的先后顺序来执行搜索。例如,
1 | vpath %.c foo |
表示搜索 .c 结尾的文件,先在 foo 目录,然后是 blish ,最后是 bar 目录搜索 .c 结尾的文件。
(3)还有一种搜索的形式
1 | vpath %.c foo:bar |
表示搜索 .c 结尾的文件,先在 foo 目录,然后是 bar 目录,最后才是 blish 目录。
2.1.2清除搜索目录
- 格式一
1 | vpath <pattern> |
清除符合模式
1 | vpath test.c # 清除符合文件 test.c 的搜索目录。 |
- 格式二
1 | vpath |
清除所有已被设置好了的文件搜索目录。
2.2使用实例
我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:
1 | mkdir test1 test2 |
所以现在的目录结构为:
1 | . |
我们编写 Makefile 内容如下:
1 | OBJ = main.o test1.o test2.o |
这样,在进行编译的时候 make 就会到设置的路径下寻找源文件。
二、头文件搜索
1.使用格式
我们并不会把所有的头文件都跟 Makefile 文件放在一个目录下,当我们的头文件和调用这个头文件的源文件以及 Makefile 不在同一个目录怎么办呢,他们有可能分布在不同的好几个目录,这个时候我们设置的 VPATH 或者是 vpath 是无法查找 .h 文件的,这时候我们就要靠 gcc 的 -I 参数啦。一般格式如下:
1 | gcc filename.c -o filename -I h_dir1 -I h_dir2 -I h_dir3 ... |
- h_dir 就表示相关头文件路径,可以跟多个,用空格分开,但是每个目录都要有 -I 这个参数。
2.使用实例
我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:
1 | mkdir test1 test2 user |
所以现在的目录结构为:
1 | . |
我们编写 Makefile 内容如下:
1 | OBJ := main.o test1.o test2.o |
这样,在进行编译的时候 make 就会到设置的路径下寻找源文件,编译的时候也会到指定目录下寻找头文件,我们执行 make 命令的话,会有如下信息提示:
1 | gcc -c user/main.c -o main.o -I test1 -I test2 |
三、生成文件路径
1.指定生成文件路径
我们每次生成的一大堆的文件都是存放在当前目录下的,文件多了之后,就会看起来很乱,我们能否指定生成文件路径呢?当然是可以的啦。这里直接以实例来说明。
1.1文件准备
首先我们新建一个 obj 文件夹用于存放生成的 .o 中间文件。
1 | mkdir obj |
我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:
1 | mkdir test1 test2 user |
所以现在的目录结构为:
1 | . |
1.2两次试错
1.2.1测试1
我们编写 Makefile 内容如下:
1 | OBJ := main.o test1.o test2.o |
然后我们执行 make 命令,会发现报了下边的错误:
1 | Makefile:11: target 'main.o' doesn't match the target pattern |
我们看报错的说明,就是生成 main 的时候,找不到它所依赖的 main.o 、 test1.o 和 test2.o ,并且在模式规则的匹配中,匹配也会有问题,我们来分析一下,我们拆开上边的模式规则,并将变量进行替换,可以得到:
1 | OBJ := main.o test1.o test2.o |
我们会发现, % 匹配的时候,前边的目标文件格式与后边匹配的不太一致,并且我们生成的 .o 文件是存放在 obj 目录下的, gcc 编译的时候是找不到这几个文件的。
1.2.2测试2
我们可以修改如下:
1 | OBJ := main.o test1.o test2.o |
然后我们再执行 make 命令,会发现有如下提示:
1 | gcc -c user/main.c -o obj/main.o -I test1 -I test2 |
此时文件结构如下:
1 | . |
发现,生成的中间文件全部进入了 obj 目录。
1.3正确的格式
经过前边的试错,我们可以将 Makefile 写成如下内容:
1 | INCLUDE := -I test1 -I test2 |
这样的 Makefile 就简洁了很多了。
2.最终目标路径
上边我们已经把中间文件的路径设置过了,那还有最终生成的目标文件的,但其实也没什么必要,毕竟最终生成的文件只有一个,也不会很乱,不过这里还是记录一下吧,我们只需要在写目标文件的时候加上路径就可以了:
1 | INCLUDE := -I test1 -I test2 |
这样我们最终生成目标文件为 main ,并且,它将会被存放到 ./bin 目录下。