Вычисляемые имена макросов - PullRequest
0 голосов
/ 07 января 2019

Программа GNU Make доказывает возможность вычисляемых имен . Я должен использовать программу 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?

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Краткий ответ: вы можете использовать переменные окружения вместо макроса make для вычисления имен. Например, этот make-файл:

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 (недокументированное?).


Более длинный ответ. Приведенный выше make-файл использует несколько приемов или приемов. Я попытаюсь распутать их в списке из четырех предметов.

Элемент 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 на самом деле не иллюстрирует вложенность: показанная вложенность является макросом внутри переменной. Но истинное вложение работает. 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%%%%

даст:

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

В рецепте call кажется необходимым для имитации отложенного расширения; см. ответ Стефана на Переменные работают не так, как ожидалось . Не требуется в тесте Test 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.

0 голосов
/ 23 января 2019

Редактировать: Это мой первый ответ, и он не так полезен. Смотрите мой второй ответ об использовании переменных окружения.


К сожалению, 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
...