问题
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