Skip to content

LV060-文件搜索

本文主要是makefile——文件搜索相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

一、文件准备

1. 目录结构

各文件所在目录的结构如下:

c
.
├── main.c
├── Makefile
├── test1.c
├── test1.h
├── test2.c
└── test2.h

0 directories, 6 files

2. 源码

2.1 main.c

c
#include <stdio.h>
#include "test1.h"
#include "test2.h"

int main(int argc, const char *argv[])
{
	printf("This is main file!\n");
	test1Fun();
	test2Fun();
	return 0;
}

2.2 test1.c

c
#include <stdio.h>

void test1Fun()
{
    printf("This is test1.c file\n");
}

2.3 test2.c

c
#include <stdio.h>

void test2Fun()
{
    printf("This is test2.c file\n");
}

2.4 test1.h

c
#ifndef __TEST1_H__
#define __TEST1_H__

void test1Fun();

#endif

2.5 test2.h

c
#ifndef __TEST2_H__
#define __TEST2_H__

void test2Fun();

#endif

二、源文件搜索

一般来说,一个大的工程下有大量的源文件,我们通常会把源文件分类,并存放在不同的目录中,便于查找和区分。所以,当 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 就会在当前目录找不到的时候,到所指定的目录中去找寻文件了。一般使用格式如下:

makefile
# 1.单个路径写法
VPATH := src 

# 2.多个路径写法
VPATH := src1 ../src2
# 或者
VPATH := src1 : ../src2

上边多个路径的写法指明了两个目录, src1 和 ../src2 。

【注意】

(1)当前目录永远是最高优先搜索的地方。如果当前目录下有我们要使用的文件,那么 make 就会使用我们当前目录下的文件。

(2)多个路径之间要使用空格或者是冒号隔开,表示在多个路径下搜索文件,搜索的顺序为我们书写时的顺序。

1.2 使用实例

我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:

shell
mkdir test1 test2
mv test1.c test1
mv test2.c test2

所以现在的目录结构为:

shell
.
├── main.c
├── Makefile
├── test1
   └── test1.c
├── test1.h
├── test2
   └── test2.c
└── test2.h

2 directories, 6 files
1.2.1 不使用 VPATH 的 Makefile
makefile
OBJ := main.o test1.o test2.o

main: $(OBJ)
	gcc $(OBJ) -o main

%.o: %.c
	gcc -c $< -o $@

.PHONY: clean
clean:
	rm -rf *.o main

此时不出意外的话,我们会得到一条这样的报错信息:

shell
gcc -c main.c -o main.o
make: *** No rule to make target 'test1.o', needed by 'main'。 停止。
1.2.2 使用 VPATH 的 Makefile
makefile
OBJ := main.o test1.o test2.o
VPATH := test1 test2
main: $(OBJ)
	gcc $(OBJ) -o main

%.o: %.c
	gcc -c $< -o $@

.PHONY: clean
clean:
	rm -rf *.o main

此时我们再执行 make 命令,会得到如下的信息提示:

shell
gcc -c test1/test1.c -o test1.o
gcc -c test2/test2.c -o test2.o
gcc main.o test1.o test2.o -o main

可以发现,我们正常编译了所有文件,总的来说当 .c 源文件都位于 test1 和 test2 目录下的时候, VPATH 就成了必要了。

2. vpath

2.1 使用格式

vpath 关键字它可以指定不同的文件在不同的搜索目录中。它有三种使用方法:

2.1.1 设置搜索路径
makefile
# 1.单个路径
vpath <pattern> <dir>

# 2.多个路径
vpath <pattern> <dir1> <dir2>
# 或者
vpath <pattern> <dir1> : <dir2>

为符合模式 <pattern> 的文件指定搜索目录 <dir> 。例如:

shell
vpath test.c src # 在 src 路径下搜索文件 test.c

【说明】

(1) vapth 使用方法中的可以包含 % 字符。 % 的意思是匹配零或若干字符,例如, %.h 表示所有以 .h 结尾的文件。

makefile
vpath %.h ../headers

该语句表示,要求 make 在 ../headers 目录下搜索所有以 .h 结尾的文件。(如果某文件在当前目录没有找到的话)。

(2)可以连续地使用 vpath 语句,以指定不同搜索策略。如果连续的 vpath 语句中出现了相同的 <pattern> ,或是被重复了的 <pattern> ,那么, make 会按照 vpath 语句的先后顺序来执行搜索。例如,

makefile
vpath %.c foo
vpath %   blish
vpath %.c bar

表示搜索 .c 结尾的文件,先在 foo 目录,然后是 blish ,最后是 bar 目录搜索 .c 结尾的文件。

(3)还有一种搜索的形式

makefile
vpath %.c foo:bar
vpath % blish

表示搜索 .c 结尾的文件,先在 foo 目录,然后是 bar 目录,最后才是 blish 目录。

2.1.2 清除搜索目录
  • 格式一
makefile
vpath <pattern>

清除符合模式 <pattern> 的文件的搜索目录。例如,

makefile
vpath test.c # 清除符合文件 test.c 的搜索目录。
  • 格式二
makefile
vpath

清除所有已被设置好了的文件搜索目录。

2.2 使用实例

我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:

shell
mkdir test1 test2
mv test1.c test1
mv test2.c test2

所以现在的目录结构为:

shell
.
├── main.c
├── Makefile
├── test1
   └── test1.c
├── test1.h
├── test2
   └── test2.c
└── test2.h

2 directories, 6 files

我们编写 Makefile 内容如下:

makefile
OBJ = main.o test1.o test2.o
vpath %.c test1 test2
# 可执行程序 main
main: $(OBJ)
	gcc $(OBJ) -o main

%.o: %.c
	gcc -c $< -o $@

.PHONY: clean
clean:
	rm -rf *.o main

这样,在进行编译的时候 make 就会到设置的路径下寻找源文件。

三、头文件搜索

1. 使用格式

我们并不会把所有的头文件都跟 Makefile 文件放在一个目录下,当我们的头文件和调用这个头文件的源文件以及 Makefile 不在同一个目录怎么办呢,他们有可能分布在不同的好几个目录,这个时候我们设置的 VPATH 或者是 vpath 是无法查找 .h 文件的,这时候我们就要靠 gcc 的 -I 参数啦。一般格式如下:

shell
gcc filename.c -o filename -I h_dir1 -I h_dir2 -I h_dir3 ...
  • h_dir 就表示相关头文件路径,可以跟多个,用空格分开,但是每个目录都要有 -I 这个参数。

2. 使用实例

我们使用上边的文件搜索相关测试文件来测试,我们新建两个目录,并将两个相关文件移动到指定目录:

shell
mkdir test1 test2 user
mv test1.c test1.h test1
mv test2.c test2.h test2
mv main.c user

所以现在的目录结构为:

shell
.
├── Makefile
├── test1
   ├── test1.c
   └── test1.h
├── test2
   ├── test2.c
   └── test2.h
└── user
    └── main.c

3 directories, 6 files

我们编写 Makefile 内容如下:

makefile
OBJ     := main.o test1.o test2.o

INCLUDE := -I test1 -I test2

vpath %.c user test1 test2

# 可执行程序 main
main: $(OBJ)
	gcc $(OBJ) -o main $(INCLUDE)

%.o: %.c
	gcc -c $< -o $@ $(INCLUDE)

.PHONY: clean
clean:
	rm -rf *.o main

这样,在进行编译的时候 make 就会到设置的路径下寻找源文件,编译的时候也会到指定目录下寻找头文件,我们执行 make 命令的话,会有如下信息提示:

shell
gcc -c user/main.c -o main.o -I test1 -I test2
gcc -c test1/test1.c -o test1.o -I test1 -I test2
gcc -c test2/test2.c -o test2.o -I test1 -I test2
gcc main.o test1.o test2.o -o main -I test1 -I test2