在 makefile 宏中定义变量 (define)

发布于 2024-11-02 22:57:34 字数 3348 浏览 0 评论 0原文

我正在使用 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)$(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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

倾城花音 2024-11-09 22:57:34

eval 应用于如下所示的分配是否可以解决问题?

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

希望这有帮助

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

我不吻晚风 2024-11-09 22:57:34

我已经对此进行了一些尝试,我想我现在理解了 make 的求值顺序。
伊势紫藤为您的问题提供了一种解决方案,我认为应该有效。另一种方法是在引用变量时简单地添加第二个 $,如下所示:$$(PHP_OUT_FILE)

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文