Computed macro names

久未见 提交于 2019-12-24 08:31:54

问题


The GNU Make program proves the feature of computed names. I have to use Microsoft nmake program and need to check if either a macro has a specified value or is at least defined.

The makefile defines a macro FOO with the value DEVICE. Further it can be that the macro PLAT_DEVICE is defined with the value 1. In GNU make syntax you could use

FOO=DEVICE
PLAT_DEVICE=1

!if "$(PLAT_$(FOO))" == "1"
!message I am here.
!endif

The value of the macro FOO defines what other macro is checked here. Unfortunately nmake doesn't understand this. The condition evaluates always to false, the message is never shown.

How can I implement this with nmake?


回答1:


Edit: This is my first answer, and is not that useful. See my second answer on using environment variables.


Unfortunately, NMAKE does not have Computed Variable Names as in GNU Make.

But it does allow the construction of macro names from other macros: see https://docs.microsoft.com/en-us/cpp/build/defining-an-nmake-macro?view=vs-2017.

So the following work-around may work, depending on your situation:

DEVICE = 1
PLAT_DEVICE_$(DEVICE) =

!ifdef PLAT_DEVICE_1
!message I am here.
!endif

Or, as minor variation of this idea:

DEVICE = 1
PLAT_DEVICE_$(DEVICE) = plat_device

!if "plat_device" == "$(PLAT_DEVICE_1)"
!message I am here.
!endif



回答2:


Short answer: you can use environment variables instead of make macros to compute the names, For example, this 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

will give:

>nmake -l
I am here.

Or this variant,

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%%%%

will give:

>nmake -l
Test 1a: I am here.
Test 1b: I am here too.
Test 2a: 42
Test 2b: 42

One major drawback in this answer is that the exporting has to be done explicitly for each make macro. The nmake -l switch is a just an abbreviation for /nologo (undocumented?).


Longer answer. The above makefile uses several techniques or tricks. I will try to unravel these in a list of four items.

Item 1: First note nmake, unlike GNU make, has persistent environment variables (aka variables in nmake). For example,

all: bar
    @echo Test 3: %%BAR%%

bar:
    @set BAR=Hello World!

gives:

>nmake -l
Test 3: Hello World!

Item 2: You can convert macros to variables, or create a variable, in at least two places:

  • in a recipe command line, as shown in Item 1, or
  • in a command executed during preprocessing, in square brackets [...].

For example,

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%%

gives:

>nmake -l
Test 4: This works!
Test 5: This works!

>nmake -l BBB=BAZ
Test 4: This also works!
Test 5: This also works!

Two odd points about this. First, it seems each variable must be set with its own command. For example,

!if [set FOO_BAR=$(FOO_BAR) && set FOO_BAZ=$(FOO_BAZ)]
!endif

does not work (I may be missing something obvious here). Second, the && connective is almost irrelevant here: it does not short-circuit in nmake, and we are discarding the the result, so probably anything else like + would work just as well.

Item 3: Item 2 doesn't really illustrate nesting: the nesting shown is a macro within a variable. But true nesting does work. The makefile:

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%%%%

will give:

>nmake -l
Test 6: I am here
Test 7: This works!

In the recipe, the call seems to be needed simulate delayed expansion; see Stephan's answer to Variables are not behaving as expected. It is not needed in the Test 6, =="This works!" test.

Item 4: The preprocessing tests shown in:

!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

are similar to the Unix test command, except here TRUE=1.



来源:https://stackoverflow.com/questions/54074507/computed-macro-names

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!