我有一个名为 test 的目录,make 文件应该在哪里。我有一个名为 sub1、sub2、sub3 的子目录。
测试/生成文件
测试/子1
测试/子2
测试/sub3
我想通过编译sub1来创建exe1,通过从sub3编译sub2和exe3来创建exe2。
我可以在 vpath 中添加多个目录吗?或任何其他解决方案
您可以简单地在目录中有一个非常简单的 makefile test
,只需进入子目录并在其中调用 makefile。子目录具有正常构建的生成文件,但只需将可执行文件放在父目录中。
首先:是的,您可以在 vpath 中添加多个目录。每个条目用冒号“:”分隔
vpath %.c test/sub1:test/sub2:test/sub3
但是,一旦您在两个目录中拥有相同的文件名(具有不同的内容),您就会遇到麻烦。考虑:
test/Makefile
test/sub1/main.c
test/sub1/foo.c
test/sub1/bar.c
...
test/sub2/main.c
test/sub2/blish.c
test/sub3/blash.c
...
test/sub3/main.c
test/sub3/okEnoughForNow.c
你的makefile包含:
vpath %.c sub1:sub2:sub3
exe1.exe : main.c foo.c bar.c
gcc -o $@ $^
exe2.exe : main.c blish.c blash.c
gcc -o $@ $^
exe3.exe : main.c okEnoughForNow.c
gcc -o $@ $^
结果将是:
gcc -o exe1.exe sub1/main.c sub1/foo.c sub1/bar.c
gcc -o exe2.exe sub1/main.c sub2/blish.c sub2/blash.c
gcc -o exe3.exe sub1/main.c sub3/okEnoughForNow.c
如您所见,所有 exe 都包含sub1/main.c
,因为这是首先找到的 main.c;它的路径首先出现在 vpath 上。
Joachim 的方法是明确的一种简单且非常常见的解决方案。如果您的子文件夹中的程序完全不相关,我也会选择它:您可以在每个目录中都有一个包含以下内容的 makefile:
SRC := $(wildcard *.c)
%.exe : $(SRC)
gcc -o $@ $^
假设您的每个子 * 中的所有 .c 文件都应成为您程序的一部分,并且您的子文件中没有子文件夹。否则,您将需要一种不同的方法来扫描您的 .c 文件,或者单独指定它们。
在您的主 makefile 中,您可以使用这些 makefile 为每个子文件夹运行一个新的 make 实例。这为您提供了一个主要的 Makefile,例如:
# Get all subfolders name without trailing slash
PROGS := $(patsubst %/,%,$(wildcard */))
# Each subfolder can be made by calling make in
# that folder. A file prog.exe is created.
.PHONY : $(PROGS)
$(PROGS) :
$(MAKE) -C $@ prog.exe
# Now every .exe depends on its subfolder, calls
# Make there - see rule above and copies the
# prog.exe from there into the root, with the name
# of the subfolder. (Alternatively you could use
# mv instead of cp)
%.exe : %
cp $</prog.exe $@
假设您的 .exe 名称与目录名称相同,并且所有子文件夹都包含程序。
但是,一旦子文件夹的生成文件之间存在任何依赖关系,从正在运行的 make 实例(递归 make)调用 make 可能会引起真正的头痛。
不使用递归生成的另一种方法是动态创建规则。在这种情况下,您的主 Makefile 可能如下所示。(我再次假设所有子文件夹都包含程序,所有子文件夹都是平面的,并且这些子文件夹中的所有 .c 文件都是您程序的一部分)这样做的好处是您只需维护一个 makefile,并且可以有不同程序之间的任何依赖关系。但它仍然有一个缺点,即您不能单独管理不同的程序。
这是完整的makefile:
%.exe :
gcc -o $@ $^
PROGS := $(patsubst %/,%,$(wildcard */))
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(wildcard $(P)/*.c)))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
.PHONY : all
all : $(addsuffix .exe,$(PROGS)
我们从编译规则开始:任何 .exe 都是通过调用 gcc 生成的,所有先决条件都是源文件。
%.exe :
gcc -o $@ $^
然后,下一步是通过扫描所有子文件夹并剥离尾部斜杠来获取所有“程序”
PROGS := $(patsubst %/,%,$(wildcard */))
下一步是为每个程序创建一个包含所有源的变量。请注意,eval 函数会展开,并将所有内容传递给 make,因为它已写入 Makefile。
$(foreach P,$(PROGS),$(eval SRC_$(P) := $(wildcard $(P)/*.c)))
因此,上面的行与您的sub1
,sub2
和sub3
将变为:
SRC_sub1 := $(wildcard sub1/*.c)
SRC_sub2 := $(wildcard sub2/*.c)
SRC_sub3 := $(wildcard sub3/*.c)
eval 函数甚至可以用来创建规则:
$(foreach P,$(PROGS),$(eval $(P).exe : $(SRC_$(P))))
所以这将扩展为(假设上面示例中的文件结构)
sub1.exe : sub1/main.c sub1/foo.c sub1/bar.c
sub2.exe : sub2/main.c sub2/blish.c sub2/blash.c
sub3.exe : sub3/main.c sub3/okEnoughForNow.c
现在我们有了三个没有配方的规则。Make 说“如果您有一个没有配方的规则,并且可以找到一个匹配的隐式规则,则此规则与从没有配方的规则添加的先决条件一起使用”因此,对于这 3 个规则,隐式规则 % .exe 以上适用。
基本上这就是诀窍。为了您的方便,您可以添加
.PHONY : all
all : $(addsuffix .exe,$(PROGS))
所以make all
使一切。
扩大:
如果您也希望能够单独制作 .o 文件,您可以添加一个更隐含的规则,例如:
%.o : %.c
gcc -c -o $@ $<
并使您的程序依赖于 .o 而不是 .c 文件:
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(patsubst %.c,%.o,$(wildcard $(P)/*.c))))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
然后,您的 .exe 将依赖于 .o,在扫描所有源后,可以通过将 .c 更改为 .o 来找到该 .o。通过隐式规则链 %.o : %.c make 会知道该做什么。