我的目录结构如下:
tests\
test1.c
test2.c
test3.c
build\
test1
test2
test3
具体而言,我想构建test1.c
,test2.c
和test3.c
并在tests\build
中输出可执行文件。
为了实现这一点,我有以下Makefile片段:
TSTS = $(wildcard $(TEST_DIR)/*.c)
EXE = $(patsubst $(TEST_DIR)/%.c,$(TEST_BUILD)/%, $(TSTS))
TEST_DIR = tests
TEST_BUILD = tests/build
$(EXE): $(TSTS)
$(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)
这给了我类似的东西:
gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test1 -lsalmalloc
gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test2 -lsalmalloc
gcc -L/home/projects/loc/build -Iinclude tests/test1.c -o tests/build/test3 -lsalmalloc
输出路径是正确的,但源文件都是tests/test1.c
!
忽略include
和其他lib
相关文件,因为我删除了标记以使其变得简单。实质上,make
正在从单个文件构建测试用例,也就是说,对于单个源文件test1.c
,使用不同的名称生成三个构建,而不是每个测试都有自己的构建。我查看了here,here,here和here,但找不到问题。
我该如何解决这个问题?
答案 0 :(得分:2)
你的目标
$(EXE): $(TSTS)
扩展为
tests/build/test1 tests/build/test2 tests/build/test3: tests/test1.c tests/test2.c tests/test3.c
,阅读有关Multiple Targets in a Rule,
的手册具有多个目标的规则相当于编写许多规则,每个规则都有一个目标,除此之外都是相同的。相同的配方适用于所有目标,但其效果可能会有所不同,因为您可以使用'$ @'将实际目标名称替换为配方。该规则也为所有目标提供了相同的先决条件。
类似的食谱适用于所有目标。配方不需要完全相同,因为自动变量'$ @'可用于替换要重新映射到命令中的特定目标(请参阅自动变量)。例如:
bigoutput littleoutput : text.g generate text.g -$(subst output,,$@) > $@
相当于
bigoutput : text.g generate text.g -big > bigoutput littleoutput : text.g generate text.g -little > littleoutput
与
相同tests/build/test1: tests/test1.c tests/test2.c tests/test3.c
tests/build/test2: tests/test1.c tests/test2.c tests/test3.c
tests/build/test3: tests/test1.c tests/test2.c tests/test3.c
因此,当您在食谱中使用$<
时,您始终会获得tests/test1.c
。
您想要的是pattern rule。
因此,形式的规则
%.o : %.c ; recipe…
指定如何创建n.o文件,如果n.c存在或可以制作,则使用另一个文件n.c作为先决条件。
所以你想要
TSTS = $(wildcard $(TEST_DIR)/*.c)
EXES = $(patsubst $(TEST_DIR)/%.c,$(TEST_BUILD)/%, $(TSTS))
all: $(EXES)
$(TEST_BUILD)/%: $(TEST_DIR)/%.c
$(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)
答案 1 :(得分:1)
这根本不是multiple targets的工作方式。当你有:
test1 test2 test3 : test1.c test2.c test3.c
$(CC) $< ...
这扩展到:
test1 : test1.c test2.c test3.c
$(CC) $< ...
test2 : test1.c test2.c test3.c
$(CC) $< ...
test3 : test1.c test2.c test3.c
$(CC) $< ...
由于$<
抓住了第一个先决条件,这就是你到处看到test1.c
的原因。您想要做的是static pattern:
$(EXE) : $(TEST_BUILD)/% : $(TEST_DIR)/%.c
$(CC) $< ...
答案 2 :(得分:1)
您的规则相当于
tests/build/test1 tests/build/test2 tests/build/test3: \
tests/test1.cc tests/test2.cc tests/test3.cc
$(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)
$<
表示第一个先决条件,因此在这种情况下tests/test1.cc
。您可能意味着$^
,所有先决条件的名称,但这对您没有帮助,因为那样您将尝试将所有.cc
文件一起编译为一个目标文件,三次。
您可能想要的是一种模式规则:
$(TEST_BUILD)/%: $(TEST_DIR)/%.cc
$(CC) $< $(CFLAGS_OUT) $@ (CFLAGS_LIBS_FLAG)$(LIB_NAME)
您可能还需要添加虚拟目标
all: $(EXE)
取决于你在makefile中的其他内容。