使用“$ **”在Makefile中引导文件输入

时间:2013-08-16 16:05:51

标签: c file-io makefile

我正在使用一个包含许多源文件的大型C项目。以下是其中一个makefile的一行:

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

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

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

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

其他说明:此makefile正在MSVS 2010中的Windows上运行。

2 个答案:

答案 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*

然后才执行。

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

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

  2. 第二次出现$** 时的反斜杠不会转义$*(您可以通过编写$$*来执行此操作);它被保留,并且转义为shell-glob星,因此输出被写入一个名为../path/to/target/foo*的文件,这是非常奇怪的,我不认为它可能是预期的。

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

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

    • 输出重定向(>)仅适用于命令行上的 next next 事物;目标目录中glob匹配的所有其他内容将作为 input 提供给unifdef

  4. 基于对你要做的事情的疯狂猜测,我想你可能想要更像这样的东西:

    # 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 ruleGNU make特有的功能。我通常提倡可移植性,但在Make的情况下,GNU版本比便携式功能集更强大,它值得随身携带。