我的目录中有一堆.c
测试源文件tests/
。现在我想分别编译和链接它们并*.out
输出tests/
.所以我写了一个makefile,但没有用。
# ...
TestDir := tests
TestSourceFile := $(shell sh -c "ls tests/*.c")
TestTargetFile := $(subst .c,.out,$(TestSourceFile))
TestFrame := testframe.o
TestNeededObjectFile := $(TestFrame) \
+ util.o \
+ tokennames.o \
+ lex.yy.o \
+ hex.o \
.PHONY: test-%
test-%: $(TestDir)/%.out
$^
.PHONY: test
test: $(TestTargetFile)
@for t in $(TestTargetFile); do \
$$t ; \
done
$(TestDir)/%.out: $(TestDir)/%.o $(TestNeededObjectFile)
gcc -o $@ $^
%.o : %.c
gcc -c $(CFLAGS) $^
clean:
rm -rf *.o lextest *.yy.? *.tab.? *.output $(TokenNameFile) \
$(TestDir)/*.out
当我运行make test-add
( add.c
is in tests/
) 时,我希望看到add.out
intests/
但出现错误:
> make test-add
make: *** No rule to make target 'tests/add.out', needed by 'test-add'. Stop.
我想知道如何正确编写这个makefile以及为什么这个makefile是错误的。
答案1
这模式规则在 GNU make 中,如果其先决条件不能直接或通过其他模式规则递归地解析为现有文件,则不会被考虑[1]:
$ make -f <(echo '%.foo: %.bar file.txt;') a.foo
make: *** No rule to make target 'a.foo'. Stop.
$ touch a.bar
$ make -f <(echo '%.foo: %.bar file.txt;') a.foo
make: *** No rule to make target 'a.foo'. Stop.
$ touch a.bar file.txt
$ make -f <(echo '%.foo: %.bar file.txt;') a.foo
make: 'a.foo' is up to date.
由于您的TestNeededObjectFile
宏包含虚假的+
s,并且您可能没有任何以这种方式命名的文件,这将违反规则$(TestDir)/%.out:
。
[1] 根据 GNU make手动的:
为了应用模式规则,其目标模式必须与所考虑的文件名匹配,并且其所有先决条件(在模式替换之后)必须命名存在或可以创建的文件。这些文件成为目标的先决条件。