计算的宏名称
Posted
技术标签:
【中文标题】计算的宏名称【英文标题】:Computed macro names 【发布时间】:2019-01-07 12:31:41 【问题描述】:GNU Make 程序证明了computed names 的特性。我必须使用 Microsoft nmake 程序,并且需要检查宏是否具有指定值或至少已定义。
makefile 定义了一个宏FOO
,其值为DEVICE
。此外,宏PLAT_DEVICE
可能是用值1
定义的。在 GNU make 语法中,您可以使用
FOO=DEVICE
PLAT_DEVICE=1
!if "$(PLAT_$(FOO))" == "1"
!message I am here.
!endif
宏FOO
的值定义了此处检查的其他宏。不幸的是,nmake 不明白这一点。条件总是为假,消息永远不会显示。
如何使用 nmake 来实现?
【问题讨论】:
【参考方案1】:编辑:这是我的第一个答案,并没有那么有用。请参阅我关于使用环境变量的第二个答案。
很遗憾,NMAKE 没有 GNU Make 中的计算变量名。
但它确实允许从其他宏构造宏名称:请参阅https://docs.microsoft.com/en-us/cpp/build/defining-an-nmake-macro?view=vs-2017。
因此,根据您的情况,以下解决方法可能有效:
DEVICE = 1
PLAT_DEVICE_$(DEVICE) =
!ifdef PLAT_DEVICE_1
!message I am here.
!endif
或者,作为这个想法的微小变化:
DEVICE = 1
PLAT_DEVICE_$(DEVICE) = plat_device
!if "plat_device" == "$(PLAT_DEVICE_1)"
!message I am here.
!endif
【讨论】:
【参考方案2】:简答:您可以使用环境变量代替make宏来计算名称,例如,这个makefile:
FOO=DEVICE
PLAT_DEVICE=1
!if [set PLAT_DEVICE=$(PLAT_DEVICE)] # add macro to environment
!endif
!if [cmd /c if "%PLAT_$(FOO)%"=="1" exit 1] # do test
!message I am here.
!endif
将给予:
>nmake -l
I am here.
或者这个变种,
FOO=DEVICE
PLAT_DEVICE=42
!if [set FOO=$(FOO)] && \
[set PLAT_DEVICE=$(PLAT_DEVICE)]
!endif
!if [cmd /c if "%PLAT_$(FOO)%"=="42" exit 1]
!message Test 1a: I am here.
!endif
!if [cmd /c if "%PLAT_%FOO%%"=="42" exit 1]
!message Test 1b: I am here too.
!endif
all:
@ echo Test 2a: %%PLAT_$(FOO)%%
@call echo Test 2b: %%PLAT_%%FOO%%%%
将给予:
>nmake -l
Test 1a: I am here.
Test 1b: I am here too.
Test 2a: 42
Test 2b: 42
这个答案的一个主要缺点是必须为每个 make 宏显式地完成导出。 nmake -l
开关只是 /nologo
的缩写(未记录?)。
更长的答案。 上面的 makefile 使用了几种技术或技巧。我将尝试在包含四个项目的列表中解开这些内容。
第 1 项: 第一个注释 nmake
与 GNU make 不同,它具有持久性环境变量(在 nmake 中也称为 变量)。例如,
all: bar
@echo Test 3: %%BAR%%
bar:
@set BAR=Hello World!
给予:
>nmake -l
Test 3: Hello World!
第 2 项:您可以将宏转换为变量,或创建变量,至少在两个地方:
在配方命令行中,如第 1 项所示,或 在预处理期间执行的命令中,方括号[...]
。
例如,
AAA = FOO
BBB = BAR
FOO_BAR = This works!
FOO_BAZ = This also works!
!if [set FOO_BAR=$(FOO_BAR)] && \
[set FOO_BAZ=$(FOO_BAZ)] && \
[set CCC=%$(AAA)_$(BBB)%]
!endif
all:
@echo Test 4: %%$(AAA)_$(BBB)%%
@echo Test 5: %%CCC%%
给予:
>nmake -l
Test 4: This works!
Test 5: This works!
>nmake -l BBB=BAZ
Test 4: This also works!
Test 5: This also works!
关于这个有两个奇怪的地方。首先,似乎每个变量都必须使用自己的命令进行设置。例如,
!if [set FOO_BAR=$(FOO_BAR) && set FOO_BAZ=$(FOO_BAZ)]
!endif
不起作用(我可能在这里遗漏了一些明显的东西)。其次,&&
连接词在这里几乎是无关紧要的:它不会在 nmake 中短路,我们会丢弃结果,所以可能像 +
这样的其他任何东西也可以正常工作。
第 3 项: 第 2 项并没有真正说明嵌套:显示的嵌套是变量中的宏。但真正的嵌套确实有效。生成文件:
AAA = FOO
BBB = BAR
FOO_BAR = This works!
!if [set AAA=$(AAA)] && \
[set BBB=$(BBB)] && \
[set FOO_BAR=$(FOO_BAR)]
!endif
!if [cmd /c if "%%AAA%_%BBB%%"=="This works!" exit 1]
!message Test 6: I am here
!endif
all:
@call echo Test 7: %%%%AAA%%_%%BBB%%%%
将给予:
>nmake -l
Test 6: I am here
Test 7: This works!
在配方中,call
似乎需要模拟延迟扩展;见Stephan's answer 至Variables are not behaving as expected。测试 6 中不需要它,=="This works!"
测试。
第4项:预处理测试如下:
!if [cmd /c if "%PLAT_$(FOO)%"=="42" exit 1]
!message Test 1a: I am here.
!endif
!if [cmd /c if "%PLAT_%FOO%%"=="42" exit 1]
!message Test 1b: I am here too.
!endif
类似于 Unix 的 test
命令,除了这里的 TRUE=1。
【讨论】:
以上是关于计算的宏名称的主要内容,如果未能解决你的问题,请参考以下文章