我需要获取一些外部数据以在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版本中也有不同的语法。
答案 0 :(得分:2)
我可以提出几个技巧。所有这些都是基于将some_commands
的执行外包给规则主体,并确保其结果得到正确使用。
这是我的最爱。包含您自己创建的包含$(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 ..." ) >$@
第一个变体:创建一个包装器makefile,它首先写入辅助makefile,然后递归调用原始makefile,辅助makefile包含在其中。无需特殊的构建目标。
使用静态名称制作虚拟目标;它将代表$(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 年引入,smake
和 BSD make
也支持。
如果您想验证这一点,SunPro Make
和 smake
是 schilytools 的一部分。