我知道引号不应该在Makefile
中使用,但出于好奇,为什么make
与make foobar
和make
的行为不同。请参阅下面的详细代码。
生成文件:
TARGET = 'foobar'
$(TARGET): foobar.cpp
g++ -g $^ -o $@
clean:
rm foobar
输出:
$ make
g++ -g foobar.cpp -o 'foobar' <-- correct
$ make clean
rm foobar
$ make foobar
g++ foobar.cpp -o foobar <-- incorrect but works. Why?
$ make clean
rm foobar
$ make baz <-- doesn't work, which is normal
make: *** No rule to make target 'baz'. Stop.
$
答案 0 :(得分:1)
这是因为make在找不到构建目标的特定规则时会使用默认规则。
即使没有空program
,也可以从program.cpp
汇总Makefile
。尝试
make -f /dev/null foobar
默认规则由POSIX指定,您的make实现可能有一些。
尝试构建baz失败,因为没有一个默认规则知道如何构建baz.c
或baz.cpp
或任何其他可用于构建{{1}的内置源文件}}
答案 1 :(得分:1)
这只是“有效”,因为shell正在从你的第一个例子中删除单引号。
引号在$(TARGET)
make变量的值中字面上。 make不会取消TARGET = 'foobar'
作业的右侧。
您可以在makefile中使用$(info $(TARGET))
来查看此内容。
所以你的目标行:
$(TARGET): foobar.cpp
正在创建一个名称为'foobar'
而不是foobar
的目标。
这就是运行make
执行“正确”操作而make foobar
执行其他操作的原因。
make foobar
正在为%: %.cpp
运行make built in规则。
您的默认'foobar'
目标用于创建foobar
这一事实是因为 shell 会看到单引号并将其删除。
您会注意到,如果您make; make
制作'foobar'
目标两次,但make foobar; make foobar
会告诉您没有任何事情要做第二次。那是因为第一个目标创建的文件与<期望不同。
如果您在食谱线中引用$@
,您会看到不同的行为。
$(TARGET): foobar.cpp
g++ -g $^ -o '$@'
例如,会生成g++ -g foobar.cpp -o ''foobar''
并在
foobar
文件
$(TARGET): foobar.cpp
g++ -g $^ -o "$@"
会运行g++ -g foobar.cpp -o "'foobar'"
并生成'foobar'
文件(这会导致make; make
报告第二次make
运行无法执行任何操作。
您希望配方行中的引号不在此变量中。
TARGET = foobar
$(TARGET): foobar.cpp
g++ -g $^ -o '$@'
clean:
rm foobar
这就是说,因为你不能在make目标名中有空格(至少不可靠),这些单引号(或任何引用)的需求会减少,因为如果文件名包含shell元字符,你只需要它。