Можно ли создать многострочную строковую переменную в 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 ]

1 голос
/ 09 июня 2012

Вы должны использовать "define / endef" Создать конструкцию:

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

It can be downloaded from $(DOWNLOAD_URL).

etc, etc.
endef

Затем вы должны передать значение этой переменной в команду оболочки. Но, если вы сделаете это с помощью функции подстановки переменных, это приведет к разбивке команды на несколько:

ANNOUNCE.txt:
  echo $(ANNOUNCE_BODY) > $@               # doesn't work

Qouting тоже не поможет.

Лучший способ передать значение - передать его через переменную окружения:

ANNOUNCE.txt: export ANNOUNCE_BODY:=$(ANNOUNCE_BODY)
ANNOUNCE.txt:
  echo "$${ANNOUNCE_BODY}" > $@

Примечание:

  1. Переменная экспортируется для этой конкретной цели, так что вы можете повторно использовать эту среду, не сильно загрязняясь;
  2. Использовать переменную окружения (двойные кавычки и фигурные скобки вокруг имени переменной);
  3. Использование кавычек вокруг переменной. Без них переводы строк будут потеряны, а весь текст будет отображаться в одной строке.
1 голос
0 голосов
/ 21 июля 2011

GNU Makefile может выполнять следующие действия. Это ужасно, и я не скажу, что вы должны это делать, но я делаю это в определенных ситуациях.

PROFILE = \
\#!/bin/sh.exe\n\
\#\n\
\# A MinGW equivalent for .bash_profile on Linux.  In MinGW/MSYS, the file\n\
\# is actually named .profile, not .bash_profile.\n\
\#\n\
\# Get the aliases and functions\n\
\#\n\
if [ -f \$${HOME}/.bashrc ]\n\
then\n\
  . \$${HOME}/.bashrc\n\
fi\n\
\n\
export CVS_RSH="ssh"\n  
#
.profile:
        echo -e "$(PROFILE)" | sed -e 's/^[ ]//' >.profile

make .profile создает файл .profile, если он не существует.

Это решение использовалось, когда приложение будет использовать GNU Makefile только в среде оболочки POSIX. Проект не является проектом с открытым исходным кодом, где проблема совместимости платформ.

Цель состояла в том, чтобы создать Make-файл, который облегчает как настройку, так и использование определенного типа рабочего пространства. Makefile приносит с собой различные простые ресурсы, не требуя таких вещей, как другой специальный архив и т. Д. Это, в некотором смысле, архив оболочки. Затем процедура может сказать такие вещи, как перетащить этот Makefile в папку для работы. Для настройки своего рабочего пространства введите make workspace, затем, чтобы сделать бла, введите make blah и т. Д.

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

0 голосов
/ 03 октября 2016

Использовать подстановка строк :

VERSION := 1.1.1
PACKAGE_NAME := Foo Bar
DOWNLOAD_URL := https://go.get/some/thing.tar.gz

ANNOUNCE_BODY := Version $(VERSION) of $(PACKAGE_NAME) has been released. \
    | \
    | It can be downloaded from $(DOWNLOAD_URL) \
    | \
    | etc, etc

Тогда в свой рецепт положите

    @echo $(subst | ,$$'\n',$(ANNOUNCE_BODY))

Это работает, потому что Make заменяет все вхождения | (обратите внимание на пробел) и заменяет его символом новой строки ($$'\n'). Вы можете думать, что эквивалентные вызовы shell-скрипта выглядят примерно так:

До:

$ echo "Version 1.1.1 of Foo Bar has been released. | | It can be downloaded from https://go.get/some/thing.tar.gz | | etc, etc"

После того, как:

$ echo "Version 1.1.1 of Foo Bar has been released.
>
> It can be downloaded from https://go.get/some/thing.tar.gz
> 
> etc, etc"

Я не уверен, доступен ли $'\n' в системах, отличных от POSIX, но если вы можете получить доступ к одному символу новой строки (даже читая строку из внешнего файла), основной принцип тот же.

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

print = $(subst | ,$$'\n',$(1))

Где бы вы вызывали это так:

@$(call print,$(ANNOUNCE_BODY))

Надеюсь, это кому-нибудь поможет. =)

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

Не очень полезный ответ, но просто для того, чтобы указать, что 'define' не работает, как ответил Акс (не поместился в комментарии):

VERSION=4.3.1
PACKAGE_NAME=foobar
DOWNLOAD_URL=www.foobar.com

define ANNOUNCE_BODY
    Version $(VERSION) of $(PACKAGE_NAME) has been released
    It can be downloaded from $(DOWNLOAD_URL)
    etc, etc
endef

all:
    @echo $(ANNOUNCE_BODY)

Выдает ошибку, что команда «Это» не может быть найдена, поэтому он пытается интерпретировать вторую строку ANNOUNCE BODY как команду.

0 голосов
/ 29 апреля 2018

В качестве альтернативы вы можете использовать команду printf. Это полезно на OSX или других платформах с меньшим количеством функций.

Чтобы просто вывести многострочное сообщение:

all:
        @printf '%s\n' \
            'Version $(VERSION) has been released' \
            '' \
            'You can download from URL $(URL)'

Если вы пытаетесь передать строку в качестве аргумента другой программе, вы можете сделать это следующим образом:

all:
        /some/command "`printf '%s\n' 'Version $(VERSION) has been released' '' 'You can download from URL $(URL)'`"
0 голосов
/ 28 января 2010

у меня сработало:

ANNOUNCE_BODY="first line\\nsecond line"

all:
    @echo -e $(ANNOUNCE_BODY)
0 голосов
/ 18 мая 2018

Не полностью связано с ОП, но, надеюсь, это поможет кому-то в будущем. (поскольку этот вопрос наиболее часто встречается при поиске в Google).

В моем Makefile я хотел передать содержимое файла команде сборки docker, после долгих потрясений я решил:

 base64 encode the contents in the Makefile (so that I could have a single line and pass them as a docker build arg...)
 base64 decode the contents in the Dockerfile (and write them to a file)

см. Пример ниже.

nb: В моем конкретном случае я хотел передать ключ ssh во время сборки образа, используя пример из https://vsupalov.com/build-docker-image-clone-private-repo-ssh-key/ (используя многоэтапную сборку докера для клонирования репозитория git, затем отбросьте ssh ключ от финального изображения на 2 этапе сборки)

Makefile

...
MY_VAR_ENCODED=$(shell cat /path/to/my/file | base64)

my-build:
    @docker build \
      --build-arg MY_VAR_ENCODED="$(MY_VAR_ENCODED)" \
      --no-cache \
      -t my-docker:build .
...

Dockerfile

...
ARG MY_VAR_ENCODED

RUN mkdir /root/.ssh/  && \
    echo "${MY_VAR_ENCODED}" | base64 -d >  /path/to/my/file/in/container
... 
0 голосов
/ 26 апреля 2012

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

  ANNOUNCE.txt:
    rm -f $@
    echo "Version $(VERSION) of $(PACKAGE_NAME) has been released" > $@
    echo "" >> $@
    echo "It can be downloaded from $(DOWNLOAD_URL)" >> $@
    echo >> $@
    echo etc, etc" >> $@

Это позволяет избежать каких-либо предположений относительно версии эха.

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