2011-04-22 118 views
5

我使用define来创建一个宏。但是,在定义构造中,我无法创建变量。分配一个变量不会导致错误,但是当我稍后尝试使用它时,它的值是空的。在makefile宏中定义变量(定义)

例如

####################################################### 
## JIDL_RULE 
## Macro to build and install PHP and JS files 
## from idl.json files 
####################################################### 
## param $(1) Full path to idl.json file 
## param $(2) Path to directory to copy PHP file into (relative to where make is run from) 
## param $(3) Path to directory to copy JS file into (relative to where make is run from) 
########################################################## 
define JIDL_RULE 
# Create the output directory if it doesn't exist 
$(2): 
    mkdir -p $(2) 

$(3): 
    mkdir -p $(3) 

# Rule to generate a PHP file. Notice that we have to prepend `pwd` 
$(call GENERATED_FILE,$(1),$(2),php): $(1) 
    $(PHPHOME)/bin/php -f $(JIDL2PHP) -- `pwd`/$$< $(DATADEF_HOME) > [email protected] 

# Rule to generate a JS file 
$(call GENERATED_FILE,$(1),$(3),js): $(1) 
    $(PHPHOME)/bin/php -f $(JIDL2JS) -- `pwd`/$$< $(DATADEF_HOME) > [email protected] 

# Add those generated files to the all target 
all:: $(call GENERATED_FILE,$(1),$(2),php) $(call GENERATED_FILE,$(1),$(3),js) $(2) $(3) 

# Remove generated files on clean: 
clean:: 
    -$(RM) -f $(call GENERATED_FILE,$(1),$(2),php) $(call GENERATED_FILE,$(1),$(3),js) 

# Rules to install generated files 
$(call PHP_RULE, $(call GENERATED_FILE,$(1),$(2),php)) 
$(call JS_RULE, $(call GENERATED_FILE,$(1),$(3),js)) 
endef 

您可以从上面的代码中看到我复制线

$(call GENERATED_FILE,$(1),$(2),php)$(call GENERATED_FILE,$(1),$(3),js)从多个地方。所以,我想创建两个变量作为宏观前两个语句,就像这样:

PHP_OUT_FILE := $(call GENERATED_FILE,$(1),$(2),php) 
JS_OUT_FILE := $(call GENERATED_FILE,$(1),$(3),js) 

但是,如果我尝试以后(还是内部的定义)使用它们,就像$(PHP_OUT_FILE)$(JS_OUT_FILE),变量是空的。我很想能够从我的宏中删除重复项。我做错了吗?这不可能吗?还有另一种方法可以做到吗?

同时测试真题答案

我试图eriktous的伊势紫藤的做法,他们都“工作”。两者都不会创建私有变量,只有全局变量,我可以,我只需要小心碰撞变量,我不能做任何递归调用(我没有计划)。

eriktous的方法存在的问题是,添加$$使得变量在外部被评估,也就是说,$$被输出为单个$并且只有在目标被调用时才被评估。因此,调用宏两次将覆盖它。

伊斯紫藤的方法确实做了我需要的。调用eval可以确保变量立即被声明,因此在宏被撤销时它是可用的并且被宏扩展。这确实意味着我无法在宏中将其设置为两个不同的值,但我也可以。

这是我用来测试它

define TEST 
$(eval INNERVAR := Blah $(1)) 
inner:: 
    echo Using EVAL: INNERVAR = $(INNERVAR) 
    echo 

endef 

define TEST2 
INNERVAR2 := Blah $(1) 
inner:: 
    echo Using double dollar sign: INNERVAR2 = $$(INNERVAR2) 
    echo 
endef 

$(eval $(call TEST,TEST_1_A)) 
$(eval $(call TEST,TEST_1_B)) 
$(eval $(call TEST2,TEST_2_A)) 
$(eval $(call TEST2,TEST_2_B)) 

inner:: 
    echo is that var really private? $(INNERVAR) 
    echo is that var really private? $(INNERVAR2) 

makefile文件而这里的输出:我ommitted是运行,以使其更容易看到报表作出的呼应。

Using EVAL: INNERVAR = Blah TEST_1_A 

Using EVAL: INNERVAR = Blah TEST_1_B 

# Calling the macro twice overwrites the global variable and since 
# it's not expanded immediately, calling the macro with different params 
# will output the last value that we set the variable to 
Using double dollar sign: INNERVAR2 = Blah TEST_2_B 
Using double dollar sign: INNERVAR2 = Blah TEST_2_B 

# As expected, the variables are not private to the macro. 
is that var really private? Blah TEST_1_B 
is that var really private? Blah TEST_2_B 
+0

为什么你不能使用更容易的模式规则来实现相同的任何特殊原因?好吧,这并不能回答这个问题,但我认为你想找到一个解决方案来构建这些东西...... :) – 0xC0000022L 2011-04-22 00:15:28

+1

要解释为什么,它不会帮助回答问题。我不是在寻求解决实际问题的帮助。只是一种在定义中定义局部变量的方法:) – 2011-04-22 00:22:09

+0

@STATUS_ACCESS_DENIED:让我试着回答你的问题,也许不完全; idl.json文件位于多个文件夹中,不会复制到它们所在的文件夹中。每次对宏的调用都必须指定输出目录。请不要问我这是为什么:) – 2011-04-22 15:41:39

回答

9

是否将eval应用于如下所示的任务解决问题?

$(eval PHP_OUT_FILE := $(call GENERATED_FILE,$(1),$(2),php)) 
$(eval JS_OUT_FILE := $(call GENERATED_FILE,$(1),$(3),js)) 

希望这有助于

+0

它确实工作,真棒,谢谢,看我编辑与eriktous的方法比较。 – 2011-04-22 15:17:44

+0

谢谢,很高兴帮助:-) _eriktous_的解决方案很有趣。 在稍有不同的情况下会有所帮助。 – 2011-04-22 19:42:37

5

我一直在这个实验了一下,我想我现在明白make如下评价的顺序。
伊势紫藤提供了一个解决您的问题,我认为应该工作。另一个是在引用变量时简单地添加第二个$,如下所示:$$(PHP_OUT_FILE)

+0

这几乎可以工作......如果我只调用一次宏,请参阅编辑以获得解释。我仍然非常感谢投入。 – 2011-04-22 15:17:27