Defining variables within a makefile macro (define)
I am using define
to create a macro. However, within a define construct, I am not able to create a variable. Assigning a variable doesn't cause an error, but when I try to use it a bit later, its value is empty.
For example
#######################################################
## 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
You can see from the code above that I'm duplicating the lines
$(call GENERATED_FILE,$(1),$(2),php)
and $(call GENERATED_FILE,$(1),$(3),js)
from multiple places. So I tried creating two variables as the first two statements in the macro, like so:
PHP_OUT_FILE := $(call GENERATED_FILE,$(1),$(2),php)
JS_OUT_FILE := $(call GENERATED_FILE,$(1),$(3),js)
But if I try to use them later on (still within the define), like $(PHP_OUT_FILE)
or $(JS_OUT_FILE)
, the variables are empty. I'd love to be able to remove that duplication from my macro. Am i doing it wrong? Is it not possible? Is there another way to do it?
TESTING BOTH ANSWERS
I tried eriktous's and Ise Wisteria's approach and they both "worked". Neither one creates private variables, just globals, which I am OK with, I'll just have to be careful with colliding variables and I can't make any recursive calls (which I was not planning on).
The problem with eriktous's approach is the the fact that adding $$ makes it so that the variable is evaluated outside, that is, the $$ is output as a single $ and only gets evaluated when the target is called. Therefore, calling the macro twice will override it.
Ise Wisteria's approach does do what I need though. Calling eval makes sure the variable is declared immediately and it's therefore available and expanded by the macro while the macro is being evaled. It does mean that I couldn't set it to two different values within the macro, but I'm OK with that too.
Here's the makefile I used to test it
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)
And here's the output: I've ommitted make's echoing of the statement that is to be run to make it easier to see.
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
Does applying eval
to the assignment like the following solve the problem?
$(eval PHP_OUT_FILE := $(call GENERATED_FILE,$(1),$(2),php))
$(eval JS_OUT_FILE := $(call GENERATED_FILE,$(1),$(3),js))
Hope this helps
I have been experimenting with this a bit, and I think I now understand the order of evaluation make
follows.
Ise Wisteria has offered one solution to your problem, which I think should work. Another one is to simply add a second $
when referencing the variables, like this: $$(PHP_OUT_FILE)
.
精彩评论