Почему Make не допускает отступы в операторах if? - PullRequest
0 голосов
/ 22 февраля 2019

Когда я пытаюсь прочитать make-файл с вложенной логикой, это постоянная проблема, что Make не позволяет использовать отступы , если .Почему это так, и есть ли хороший способ обойти это ограничение и при этом иметь читаемые make-файлы?

Обновление : теперь я понимаю, что этот вопрос основан на ложной предпосылке, ноЯ полагаю, что оставить его здесь может быть ценным для любого, кто совершит ту же ошибку, что и я.

Ответы [ 2 ]

0 голосов
/ 12 марта 2019

Благодаря помощи других, теперь я понимаю, что мой вопрос поставлен на ложную предпосылку.Makefiles абсолютно do позволяют использовать более точные операторы с отступом или скорее условные выражения с отступом.Они не допускают - по крайней мере, из коробки - условные выражения с вкладками .Это связано с тем, что по умолчанию Make интерпретирует tabs как особо значимые символы.Почти любая строка, начинающаяся с символа табуляции, интерпретируется как часть рецепта .Следовательно, любая строка, которая не предназначена для использования в рецепте, например условные выражения, должна , а не начинаться с табуляции.

Что касается ответа на часть моего вопроса, которая задала почему они решили использовать символ табуляции таким образом, я не нашел ответа.Возможно, дизайнеры предполагали, что условные условия будут использоваться экономно.

Что касается обходных путей, здесь я попытаюсь описать пару.

Первое решение - ужасная боль, если у вас нет редактора, который показывает пробел символов, но если вы это сделаете, самое простое, что вы можете сделать, это просто добавить несколько пробелов для отступа вашего кода без рецепта.Хотя это довольно хакерский обходной путь и, вероятно, не рекомендуется.

Другое решение (любезно предоставленное @Stefan Becker) - установить для специальной переменной , .RECIPEPREFIX любой символ, отличный от tab.Вот пример того, что я попробовал:

.RECIPEPREFIX := >
# Now, all recipes will begin with the > character rather than a tab.

things = something another_thing something_else nothing
nothing = true

something: another_thing something_else
# See how each line of a recipe now begins with >.
# You can see I also added a tab after the >. 
# These tabs doesn't mean anything to Make; it's just for readability.
>   $(info Making $@.)
>   @touch $@

another_thing:
>   $(info Making $@.)
    # See also how lines like comments can be tabbed, 
    # but no longer add anything meaningful to recipes.
>   @touch $@

something_else:
>   $(info Making $@.)
>   @touch $@
    # And just to prove the situation with conditionals is resolved...
    # See how the @touch command begins with the new RECIPEPREFIX 
    # but the conditionals don't.
    ifeq ($(nothing),true)
>       $(info Also making nothing, because nothing is true.)
>       @touch nothing
    endif

.PHONY: everything_clean
everything_clean:
>   $(info Cleaning up everything.)
>   rm -f $(things)

Стоит помнить одну вещь: строки рецептов должны начинаться с нового RECIPEPREFIX.То есть что-то вроде этого не будет работать:

something: another_thing something_else
# Remember that the RECIPEPREFIX must come first. 
# Indenting your recipe lines first and then using the RECIPEPRIFX will not work.
    >$(info Making $@.)
    >@touch $@
0 голосов
/ 22 февраля 2019

Не знаю, почему у вас сложилось впечатление, что условные отступы не поддерживаются.Кажется, они работают нормально, когда я использую их в следующем примере:

.PHONY: all
all:

CONFIGS :=

ifeq ($(CONFIG1),1)
  $(info CONFIG1 selected)

  CONFIGS += config1
  all: config1

  config1:
    @echo $@


  ifeq ($(CONFIG2),1)
    $(info CONFIG2 selected)

    CONFIGS += config2
    all: config2

    config2:
    @echo $@

  else
    $(info CONFIG2 not selected)
  endif
else
  $(info CONFIG1 NOT selected)
endif

all:
    @echo "all: $(CONFIGS)"

ПРИМЕЧАНИЕ : TABS в моем примере, вероятно, не выживет при копировании и вставке.Поэтому вам придется повторно вводить их для рецептов.

Тестовый прогон:

$ make
CONFIG1 NOT selected
all:

$ make CONFIG1=1
CONFIG1 selected
CONFIG2 not selected
config1
all:  config1

$ make CONFIG1=1 CONFIG2=1
CONFIG1 selected
CONFIG2 selected
config1
config2
all:  config1 config2

Но ...

Есть один случай, когдаОтступы могут привести к проблемам.Цитируя GNU make manual :

Рецепт - это действие, которое выполняет make.Рецепт может иметь более одной команды, либо в одной строке, либо в отдельной строке. Обратите внимание: вам нужно ставить символ табуляции в начале каждой строки рецепта!Это мрак, который ловит неосторожных.

Поскольку GNU make занимает все строки с отступом TAB после того, как правило будет частью рецепта для правила, следующее не будет выполнено для make CONFIG1=1:

.PHONY: all
all:

CONFIGS :=

config1:
# TAB in the following line
    @echo $@

# the following lines are indented with TABs
    ifeq ($(CONFIG1),1)
    CONFIGS += config1
    test1:
        @echo $@
    endif

ifeq ($(CONFIG1),1)
all: config1
endif

all:
# TAB in the following line
    @echo "all: $(CONFIGS)"
$ make CONFIG1=1
config1
ifeq (1,1)
/bin/sh: -c: line 0: syntax error near unexpected token `1,1'
/bin/sh: -c: line 0: `ifeq (1,1)'
make: *** [Makefile:9: config1] Error 1

Решение

  1. организовать make-файл, чтобы сначала иметь условные выражения, а затем правила, то есть больше нет отступов TAB после правил, кроме рецептов, или
  2. всегда используйтеПРОБЕЛЫ для условного, переменного назначения и строк правил.
  3. установите .RECIPEPREFIX на непробельный символ , например, >, и используйте его для обозначения строк рецепта. 1

Если у вас нет редактора, который показывает разницу между табуляцией и пробелами, альтернатива 2, вероятно, сведет вас с ума.Я бы предложил альтернативу 1 вместо ...

Следующие работы для make CONFIG2=1:

.PHONY: all
all:

CONFIGS :=

config2:
# TAB in the following line
    @echo $@

# the following lines are indented with SPACES
    ifeq ($(CONFIG2),1)
    CONFIGS += config2
    test2:
# 2 TABs in the following line
        @echo $@
    endif

ifeq ($(CONFIG2),1)
all: config2
endif

all:
# TAB in the following line
    @echo "all: $(CONFIGS)"
$ make CONFIG2=1
config2
all:  config2

1 Вы можете испытать искушение:установите .RECIPEPREFIX на SPACE следующим образом:

_empty        :=
_space        := $(_empty) $(_empty)
.RECIPEPREFIX := $(_space)

, а затем переключите свой редактор, чтобы использовать только пробелы.Но это усугубляет ситуацию, т. Е. Теперь make не может отличить нормальный отступ от рецепта.Если вы попробуете это с приведенным выше примером, вы заметите, что теперь он завершается неудачно для любого вызова, который включает одно из отступных правил.

...