Makefile:如何以便携方式从外部获取规则目标的文件名

时间:2010-03-08 18:58:49

标签: shell makefile

我需要获取一些外部数据以在Makefile中形成输出文件名。

GNU Make 中,我可以这样做:

NAME=$(shell some_commands)
$(NAME).out: file.in
     compile "$<" -o "$@"

其他一些规则以$(NAME).out为先决条件,因此我需要$(NAME).out作为目标。我不能在这里使用替换+引号,因为它不是由shell解释的。​​

我从 BSD Make 手册页看到,在Mac OS X上,我应该可以做这样的事情(虽然我还无法测试):

NAME!=some_commands
$(NAME).out: file.in
     compile "$<" -o "$@"

有可能以便携方式做这种事情吗?

我不想生成Makefile并使构建过程混乱。我虽然包含,但它们在Make版本中也有不同的语法。

3 个答案:

答案 0 :(得分:2)

我可以提出几个技巧。所有这些都是基于将some_commands的执行外包给规则主体,并确保其结果得到正确使用。

  1. 这是我的最爱。包含您自己创建的包含$(NAME)规则的makefile。在处理开始时,它将被重新创建并显示正确的目标。问题是创建这个makefile的过程是在shell命令中完成的:

    include aux_makefile
    .PHONY aux_makefile
    aux_makefile:
        NAME=`some_commands` ; ( \
            echo $$NAME.out: file.in ; \
            echo "\t rm aux_makefile" ; \
            echo "\t compile ..."  ) >$@
    
  2. 第一个变体:创建一个包装器makefile,它首先写入辅助makefile,然后递归调用原始makefile,辅助makefile包含在其中。无需特殊的构建目标。

  3. 使用静态名称制作虚拟目标;它将代表$(NAME).out。即:

    all: dummy    # Instead of all: $(NAME).out
    dummy: file.in
       NAME=`some_commands`; compile "$<" -o "$$NAME"
       touch $@
    

答案 1 :(得分:2)

这有点笨拙,我不太了解不同版本的Make知道它是否真的可移植,但它可能有用,它满足你的严格条件(没有生成makefile,没有'include',事情可能取决于$(NAME).out)。如果您打算从命令行中创建一个目标(例如,“all”),那么您可以这样写:

ifeq ($(origin NAME), undefined)
all:
    @$(MAKE) -s all NAME=some_commands_using_substituion_and_quotes
else
all: some_preqs_maybe_including_NAME
    do_other_things
endif

运行Make时,NAME是未定义的,因此规则会在定义了NAME的情况下再次运行Make,因为命令IS由shell解释。 (“@”和“-s”只是为了让它更安静。)如果你试图“手动”制作其他目标,你将遇到很多麻烦,因为$(NAME)将评估为空。

答案 2 :(得分:1)

如果您不尝试使用不可移植的 BSD 扩展,有一种可移植的方法可以做到这一点。

一个有效的 makefile 看起来像这样:

NAME = $(shell some command) # This is the non-portable gmake syntax
NAME :sh= some command       # This is mostly portable from SunPro Make

all:
    echo $(NAME)

第二种方法由 SunPro Make 于 1986 年引入,smakeBSD make 也支持。

如果您想验证这一点,SunPro Makesmake 是 schilytools 的一部分。