我正在使用一个包含许多源文件的大型C项目。以下是其中一个makefile的一行:
!$(TOOLSDIRECTORY)unifdef $(UNIFDEF_ARGUMENTS) $** > $(TARGET)\$**
此行引用的Unifdef工具是开源的,可在此处获取: http://dotat.at/prog/unifdef/
在这种情况下,Unifdef的最后一个参数是要处理的文件组。据我所知,这段代码使用符号“$ **”来表示“此文件夹中的每个文件”,然后将所有输出传递给TARGET目录。
我的困惑是我不明白Unifdef如何在一个命令中接收多个文件。当makefile看到“$ **”时,是否将所有文件打包成一个文件流?我理解Unifdef如何处理它收到的输入,但是多个文件如何变成Unifdef接收的单个参数?
其他说明:此makefile正在MSVS 2010中的Windows上运行。
答案 0 :(得分:1)
Windows CMD提示将$ **扩展为对Unifdef的多个单独调用,每个调用都使用目录中的一个文件作为参数,并将输出通过管道传输到目标目录中的同名文件。因此,每次调用Unifdef只接收一个文件名作为输入。
答案 1 :(得分:0)
我怀疑这实际上并不是你想要的。
$**
不是一个单一的结构;正是special Makefile variable $*
紧跟着shell-glob通配符*
。该行将被重写两次:首先,通过Make,重写为
!../path/to/tools/unifdef --opt1 --opt2 foo* > ../path/to/target/foo\*
然后,/bin/sh
,类似
!../path/to/tools/unifdef --opt1 --opt2 foo.c foo1.c foo2.c fooquux.c \
> ../path/to/target/foo*
然后才执行。
你没有引用任何上下文,所以我不能比这更具体。这就是为什么我认为这不可能是正确的:
除非您设置.RECIPEPREFIX
,这是我之前从未听说过的功能,但命令开头的!
没有任何意义,应该导致失败的命令,因为没有名为字面!../path/to/tools/unifdef
的可执行文件。
第二次出现$**
时的反斜杠不会转义$*
(您可以通过编写$$*
来执行此操作);它被保留,并且转义为shell-glob星,因此输出被写入一个名为../path/to/target/foo*
的文件,这是非常奇怪的,我不认为它可能是预期的。
如果目标目录glob没有被转义,则还会出现两个问题:
全局扩展在源目录和目标目录中独立发生,因此(至少可能)匹配不相关的文件集。
输出重定向(>
)仅适用于命令行上的 next next 事物;目标目录中glob匹配的所有其他内容将作为 input 提供给unifdef
。
基于对你要做的事情的疯狂猜测,我想你可能想要更像这样的东西:
# Resist the temptation to use wildcards. It will be less grief in the long run
# to list each file explicitly.
GENERIC_SOURCES := foo.c foo1.c foo2.c fooquux.c barblurf.c barbaz.c
UNIFDEFED_SOURCES := $(patsubst %.c,$(TARGET)/%-u.c,$(GENERIC_SOURCES))
# The indented lines below must be indented using exactly one hard tab character.
$(UNIFDEFED_SOURCES): %-u.c: %.c
$(TOOLSDIRECTORY)unifdef $(UNIFDEF_ARGUMENTS) $< > $@T
mv -f $@T $@
这不会尝试批量调用unifdef
;如果每个规则只创建一个输出文件,那么Make通常很多更快乐。
$(patsubst ...)
和static pattern rule是GNU make特有的功能。我通常提倡可移植性,但在Make的情况下,GNU版本比便携式功能集更强大,它值得随身携带。