2

我正在处理一个包含许多源文件的大型 C 项目。这是其中一个生成文件中的一行:

!$(TOOLSDIRECTORY)unifdef $(UNIFDEF_ARGUMENTS) $** > $(TARGET)\$**

此行引用的 Unifdef 工具是开源的,可在此处获得: http ://dotat.at/prog/unifdef/

在这种情况下,Unifdef 的最后一个参数是要处理的文件组。据我了解,此代码使用符号“$**”表示“此文件夹中的每个文件”,然后将所有输出传送到 TARGET 目录。

我的困惑是我不明白 Unifdef 如何在一个命令中接收多个文件。当 makefile 看到“$**”时,它是否将所有文件打包到一个文件流中?我了解 Unifdef 如何处理它接收的输入,但是多个文件如何变成 Unifdef 接收的单个参数?

其他注意事项:此 makefile 正在 MSVS 2010 中的 Windows 上运行。

4

2 回答 2

1

我怀疑这实际上并不能满足您的要求。

$**不是一个单一的结构;它是紧跟 shell-glob 通配符的特殊 Makefile 变量$**。该行将被重写两次:首先,由 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*

然后才被执行。

你没有引用任何上下文,所以我不能比这更具体。不过,这就是为什么我认为这是不对的:

  1. 除非你设置.RECIPEPREFIX,这是我以前从未听说过的功能,否则!命令开头的 没有任何意义,并且应该导致命令失败,因为没有可执行文件以字面意思命名!../path/to/tools/unifdef

  2. 第二次出现的反斜杠$** 不会转义$*(你可以通过写来做到这一点$$*);它被保留,并转义了 shell-glob 星,因此输出被写入一个字面上命名为 的文件../path/to/target/foo*,这很奇怪,我认为这不是预期的。

  3. 如果目标目录 glob 没有被转义,还会有两个问题:

    • 全局扩展在源目录和目标目录中独立发生,因此(至少可能)匹配不相关的文件集。

    • 输出重定向 ( >) 仅适用于命令行上的下一件事;与目标目录中的glob匹配的所有其他内容将作为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 ...)静态模式规则是GNU make特有的功能。我通常提倡可移植性,但在 Make 的情况下,GNU 化身比可移植功能集强大得多,因此值得作为依赖项携带。

于 2013-08-16T16:29:25.967 回答
1

Windows CMD 提示符将 $** 扩展为对 Unifdef 的多个单独调用,每个调用都以目录中的一个文件作为参数,并将输出通过管道传输到目标目录中的同名文件。因此,对 Unifdef 的每次调用仅接收一个文件名作为其输入。

于 2013-08-19T18:48:28.987 回答