9

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

例如

#######################################################
## 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) > $$@

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

# 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)or $(JS_OUT_FILE),则变量为空。我希望能够从我的宏中删除该重复项。我做错了吗?不可能吗?还有另一种方法吗?

测试两个答案

我尝试了 eriktous 和 Ise Wisteria 的方法,它们都“有效”。两者都没有创建私有变量,只是全局变量,我可以接受,我只需要小心冲突变量,我不能进行任何递归调用(我没有计划这样做)。

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

伊势紫藤的方法确实可以满足我的需要。调用 eval 可确保立即声明变量,因此在对宏进行求值时,该变量可用并由宏扩展。这确实意味着我无法在宏中将其设置为两个不同的值,但我也可以接受。

这是我用来测试它的makefile

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) 

这是输出:我省略了 make 对要运行的语句的回显,以便更容易看到。

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
4

2 回答 2

15

像下面这样申请eval作业能解决问题吗?

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

希望这可以帮助

于 2011-04-22T01:21:54.953 回答
5

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

于 2011-04-22T13:38:47.953 回答