【问题标题】: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 来实现?

【问题讨论】:

    标签: 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 answerVariables 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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多