Можно ли создать многострочную строковую переменную в Makefile? - PullRequest
101 голосов
/ 16 марта 2009

Я хочу создать переменную makefile, которая представляет собой многострочную строку (например, текст объявления о выпуске электронной почты). что-то вроде

ANNOUNCE_BODY="
Version $(VERSION) of $(PACKAGE_NAME) has been released

It can be downloaded from $(DOWNLOAD_URL)

etc, etc"

Но я не могу найти способ сделать это. Возможно ли это?

Ответы [ 19 ]

150 голосов
/ 16 марта 2009

Да, вы можете использовать ключевое слово define для объявления многострочной переменной, например:

define ANNOUNCE_BODY
Version $(VERSION) of $(PACKAGE_NAME) has been released.

It can be downloaded from $(DOWNLOAD_URL).

etc, etc.
endef

Сложная задача - вернуть вашу многострочную переменную из make-файла. Если вы просто сделаете очевидное использование «echo $ (ANNOUNCE_BODY)», вы увидите результат, который другие разместили здесь - оболочка пытается обработать вторую и последующие строки переменной как сами команды.

Однако вы можете экспортировать значение переменной как есть в оболочку как переменную среды, а затем ссылаться на нее из оболочки как переменную среды (НЕ переменную make). Например:

export ANNOUNCE_BODY
all:
    @echo "$$ANNOUNCE_BODY"

Обратите внимание на использование $$ANNOUNCE_BODY, указывающего ссылку на переменную среды оболочки, а не $(ANNOUNCE_BODY), которая будет обычной ссылкой на переменную make. Также обязательно используйте кавычки вокруг ссылки на переменную, чтобы убедиться, что переводы строки не интерпретируются самой оболочкой.

Конечно, этот конкретный трюк может зависеть от платформы и оболочки. Я тестировал его на Ubuntu Linux с GNU bash 3.2.13; YMMV.

20 голосов
/ 04 мая 2011

Другой подход к «возвращению вашей многострочной переменной из make-файла» (отмеченной Эриком Мелски как «сложная часть») заключается в планировании использования функции subst для замены строк, введенных define в вашей многострочной строке с \n. Затем используйте -e с echo для их интерпретации. Возможно, вам придется установить .SHELL = bash, чтобы получить эхо, которое делает это.

Преимущество этого подхода состоит в том, что вы также добавляете в свой текст другие escape-символы и уважаете их.

Этот тип синтезирует все упомянутые подходы ...

Вы получите:

define newline


endef

define ANNOUNCE_BODY=
As of $(shell date), version $(VERSION) of $(PACKAGE_NAME) has been released.  

It can be downloaded from $(DOWNLOAD_URL).  

endef

someTarget:
    echo -e '$(subst $(newline),\n,${ANNOUNCE_BODY})'

Обратите внимание, что одинарные кавычки в последнем эхо имеют решающее значение.

10 голосов
/ 24 мая 2012

Предполагая, что вы хотите печатать только содержимое вашей переменной на стандартном выходе, есть другое решение:

do-echo:
    $(info $(YOUR_MULTILINE_VAR))
3 голосов
/ 16 марта 2009

Да. Вы выходите из новых строк с помощью \:

VARIABLE="\
THIS IS A VERY LONG\
TEXT STRING IN A MAKE VARIABLE"

обновление

Ах, вы хотите переводы строк? Тогда нет, я не думаю, что есть какой-то путь в ванили Make. Однако вы всегда можете использовать здесь-документ в командной части

[Это не работает, см. Комментарий от MadScientist]

foo:
    echo <<EOF
    Here is a multiple line text
    with embedded newlines.
    EOF
2 голосов
/ 23 марта 2011

Просто постскриптум к ответу Эрика Мелски: Вы можете включить вывод команд в текст, но вы должны использовать синтаксис Makefile "$ (shell foo)", а не синтаксис оболочки "$ (foo)". Например:

define ANNOUNCE_BODY  
As of $(shell date), version $(VERSION) of $(PACKAGE_NAME) has been released.  

It can be downloaded from $(DOWNLOAD_URL).  

endef
1 голос
/ 16 марта 2009

Почему бы вам не использовать символ \ n в вашей строке для определения конца строки? Также добавьте дополнительную обратную косую черту, чтобы добавить ее в несколько строк.

ANNOUNCE_BODY=" \n\
Version $(VERSION) of $(PACKAGE_NAME) has been released \n\
\n\
It can be downloaded from $(DOWNLOAD_URL) \n\
\n\
etc, etc"
1 голос
/ 28 мая 2017

Мне больше всего нравится ответ Альхадиса. Но чтобы сохранить колоночное форматирование, добавьте еще одну вещь.

SYNOPSIS := :: Synopsis: Makefile\
| ::\
| :: Usage:\
| ::    make .......... : generates this message\
| ::    make synopsis . : generates this message\
| ::    make clean .... : eliminate unwanted intermediates and targets\
| ::    make all ...... : compile entire system from ground-up\
endef

Выходы:

:: Synopsis: Makefile 
:: 
:: Usage: 
:: make .......... : generates this message 
:: make synopsis . : generates this message 
:: make clean .... : eliminate unwanted intermediates and targets 
:: make all ...... : compile entire system from ground-up
1 голос
/ 13 февраля 2014

С GNU Make опция .ONESHELL - ваш друг, когда дело доходит до многострочных фрагментов оболочки. Собрав воедино подсказки из других ответов, я получаю:

VERSION = 1.2.3
PACKAGE_NAME = foo-bar
DOWNLOAD_URL = $(PACKAGE_NAME).somewhere.net

define nwln

endef

define ANNOUNCE_BODY
Version $(VERSION) of $(PACKAGE_NAME) has been released.

It can be downloaded from $(DOWNLOAD_URL).

etc, etc.
endef

.ONESHELL:

# mind the *leading* <tab> character
version:
    @printf "$(subst $(nwln),\n,$(ANNOUNCE_BODY))"

Убедитесь, что при копировании и вставке приведенного выше примера в ваш редактор все символы <tab> сохраняются, иначе цель version сломается!

1 голос
/ 14 ноября 2016

В духе .ONESHELL, можно приблизиться в сложных условиях .ONESHELL:

define _oneshell_newline_


endef

define oneshell
@eval "$$(printf '%s\n' '$(strip                            \
                         $(subst $(_oneshell_newline_),\n,  \
                         $(subst \,\/,                      \
                         $(subst /,//,                      \
                         $(subst ','"'"',$(1))))))' |       \
          sed -e 's,\\n,\n,g' -e 's,\\/,\\,g' -e 's,//,/,g')"
endef

Пример использования будет примерно таким:

define TEST
printf '>\n%s\n' "Hello
World\n/$$$$/"
endef

all:
        $(call oneshell,$(TEST))

Показывает вывод (при условии pid 27801):

>
Hello
World\n/27801/

Этот подход допускает некоторые дополнительные функции:

define oneshell
@eval "set -eux ; $$(printf '%s\n' '$(strip                            \
                                    $(subst $(_oneshell_newline_),\n,  \
                                    $(subst \,\/,                      \
                                    $(subst /,//,                      \
                                    $(subst ','"'"',$(1))))))' |       \
                     sed -e 's,\\n,\n,g' -e 's,\\/,\\,g' -e 's,//,/,g')"
endef

Эти параметры оболочки будут:

  • Печатать каждую команду по мере ее выполнения
  • Выход по первой неудачной команде
  • Считать использование неопределенных переменных оболочки ошибкой

Другие интересные возможности, скорее всего, появятся.

1 голос
/ 11 октября 2014

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

=====

MSG = this is a\\n\
multi-line\\n\
message

method1:
     @$(SHELL) -c "echo '$(MSG)'" | sed -e 's/^ //'

=====

Вы также можете использовать вызываемые макросы Gnu:

=====

MSG = this is a\\n\
multi-line\\n\
message

method1:
        @echo "Method 1:"
        @$(SHELL) -c "echo '$(MSG)'" | sed -e 's/^ //'
        @echo "---"

SHOW = $(SHELL) -c "echo '$1'" | sed -e 's/^ //'

method2:
        @echo "Method 2:"
        @$(call SHOW,$(MSG))
        @echo "---"

=====

Вот вывод:

=====

$ make method1 method2
Method 1:
this is a
multi-line
message
---
Method 2:
this is a
multi-line
message
---
$

=====

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...