답변:
예, 다음과 같이 define 키워드를 사용하여 여러 줄 변수를 선언 할 수 있습니다.
define ANNOUNCE_BODY
Version $(VERSION) of $(PACKAGE_NAME) has been released.
It can be downloaded from $(DOWNLOAD_URL).
etc, etc.
endef
까다로운 부분은 여러 줄 변수를 makefile에서 다시 가져 오는 것입니다. "echo $ (ANNOUNCE_BODY)"를 사용하는 명백한 작업을 수행하면 다른 사람들이 여기에 게시 한 결과를 볼 수 있습니다. 쉘은 변수의 두 번째 및 후속 줄을 명령 자체로 처리하려고합니다.
그러나 변수 값을있는 그대로 셸에 환경 변수로 내 보낸 다음 셸에서 환경 변수 (make 변수 아님)로 참조 할 수 있습니다. 예를 들면 :
export ANNOUNCE_BODY
all:
@echo "$$ANNOUNCE_BODY"
일반 make 변수 참조가 $$ANNOUNCE_BODY
아닌 셸 환경 변수 참조를 나타내는 의 사용에 유의하십시오 $(ANNOUNCE_BODY)
. 또한 변수 참조 주위에 따옴표를 사용하여 개행 문자가 쉘 자체에서 해석되지 않도록하십시오.
물론,이 특별한 트릭은 플랫폼과 쉘에 민감 할 수 있습니다. GNU bash 3.2.13을 사용하여 Ubuntu Linux에서 테스트했습니다. YMMV.
ANNOUNCE_BODY
다른 변수 정의에서 의 값을 사용하려면 다른 make 변수처럼 참조하십시오. 예를 들면 OTHER=The variable ANNOUNCE_BODY is $(ANNOUNCE_BODY)
. 물론 명령 export
을 내리려면 여전히 트릭이 필요합니다 OTHER
.
'메이크 파일에서 여러 줄 변수를 다시 가져 오는 방법'(Eric Melski가 '까다로운 부분'으로 언급)에 대한 또 다른 접근 방식은 subst
함수를 사용 define
하여 여러 줄 문자열에 도입 된 줄 바꿈 을 \n
. 그런 다음 -e와 함께 사용 echo
하여 해석하십시오. 이를 수행하는 에코를 얻으려면 .SHELL = bash를 설정해야 할 수도 있습니다.
이 접근 방식의 장점은 다른 이스케이프 문자를 텍스트에 넣고 존중한다는 것입니다.
이런 종류의 방법은 지금까지 언급 한 모든 접근 방식을 종합합니다.
당신은 다음과 같이 끝납니다.
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})'
최종 에코의 작은 따옴표가 중요합니다.
=
애프터 define ANNOUNCE_BODY
를 제거 해야했습니다.
표준 출력에 변수의 내용 만 인쇄한다고 가정하면 다른 해결책이 있습니다.
do-echo:
$(info $(YOUR_MULTILINE_VAR))
make: 'do-echo' is up to date.
.. :는 "어떤 작전을"사용하지 않는함으로써 내가 침묵 할 수 있었다 COMAND@: $(info $(YOUR_MULTILINE_VAR))
.PHONY
Makefile에 해당 규칙을 확인할 것이 없다고 알리는 데 사용할 수 있습니다 . Makefile은 원래 컴파일러를위한 것이 었습니다. 제가 착각 make
하지 않았다면, 규칙이 아무것도 변경하지 않을 것이라고 예상 할 수없는 마술을하고 있으며 , 따라서 '완료'라고 가정합니다. .PHONY do-echo
파일에 추가하면 make
이것을 무시하고 어쨌든 코드를 실행하도록 지시합니다.
$(info ...)
make 규칙 외부에 배치 할 수 있습니다 . 여전히 출력을 생성합니다.
예. 다음과 같이 줄 바꿈을 이스케이프합니다 \
.
VARIABLE="\
THIS IS A VERY LONG\
TEXT STRING IN A MAKE VARIABLE"
아, 개행을 원하십니까? 그렇다면 바닐라 메이크에는 방법이 없다고 생각합니다. 그러나 명령 부분에서 항상 here-document를 사용할 수 있습니다.
[작동하지 않습니다. MadScientist의 의견 참조]
foo:
echo <<EOF
Here is a multiple line text
with embedded newlines.
EOF
이것은 here 문서를 제공하지 않지만 파이프에 적합한 방식으로 여러 줄 메시지를 표시합니다.
=====
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
---
$
=====
줄 끝을 정의하기 위해 문자열의 \ 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"
$(subst \n ,\n,$(TEXT))
더 나은 방법이 있었으면 좋겠지 만 텍스트를 넣었습니다 !
"define / endef"Make 구문을 사용해야합니다.
define ANNOUNCE_BODY
Version $(VERSION) of $(PACKAGE_NAME) has been released.
It can be downloaded from $(DOWNLOAD_URL).
etc, etc.
endef
그런 다음이 변수의 값을 쉘 명령에 전달해야합니다. 그러나 Make 변수 대체를 사용하여이 작업을 수행하면 명령이 여러 개로 분할됩니다.
ANNOUNCE.txt:
echo $(ANNOUNCE_BODY) > $@ # doesn't work
Qouting도 도움이되지 않습니다.
값을 전달하는 가장 좋은 방법은 환경 변수를 통해 전달하는 것입니다.
ANNOUNCE.txt: export ANNOUNCE_BODY:=$(ANNOUNCE_BODY)
ANNOUNCE.txt:
echo "$${ANNOUNCE_BODY}" > $@
주의:
.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
이러한 셸 옵션은 다음과 같습니다.
다른 흥미로운 가능성이 스스로를 제안 할 것입니다.
나는 alhadis의 대답을 가장 좋아합니다. 그러나 열 형식을 유지하려면 한 가지 더 추가하십시오.
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
make
일반적으로 빌드 프로세스를 시작할 것으로 예상합니다.
OP와 완전히 관련이 없지만 앞으로 누군가에게 도움이되기를 바랍니다. (이 질문은 Google 검색에서 가장 많이 나오는 질문입니다).
내 Makefile에서 파일의 내용을 도커 빌드 명령에 전달하고 싶었는데 많은 놀라움 끝에 다음과 같이 결정했습니다.
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)
아래 예를 참조하십시오.
주의 : 내 특정 경우에, 나는의 예를 사용하여 이미지 빌드하는 동안, SSH 키를 전달하고 싶었 https://vsupalov.com/build-docker-image-clone-private-repo-ssh-key/을 (사용 git repo를 복제하기위한 다중 단계 도커 빌드, 빌드의 두 번째 단계에서 최종 이미지에서 ssh 키를 드롭)
...
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 .
...
...
ARG MY_VAR_ENCODED
RUN mkdir /root/.ssh/ && \
echo "${MY_VAR_ENCODED}" | base64 -d > /path/to/my/file/in/container
...
GNU Make 3.82 이상에서는 여러 .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
대상이 손상됩니다!
참고 .ONESHELL
메이크 모든 대상의 원인이됩니다은 모든 명령에 대한 하나의 쉘을 사용합니다.
make version printf "Version 1.2.3 of foo-bar has been released. /bin/sh: 1: Syntax error: Unterminated quoted string make: *** [version] Error 2
(GNU make 3,81)
@printf ...
문 앞에 공백 대신 선행 TAB 문자가 있는지 확인하십시오. TAB 은 항상 4 개의 공백으로 렌더링되는 것 같습니다 ...
.ONESHELL
make 3.82에서 새로운 것으로 보입니다 .
*** missing separator. Stop.
.
실제로 유용한 답변은 아니지만 '정의'가 Ax의 답변대로 작동하지 않는다는 것을 나타냅니다 (댓글에 맞지 않음).
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)
'It'명령을 찾을 수 없다는 오류가 발생하여 ANNOUNCE BODY의 두 번째 줄을 명령으로 해석하려고합니다.
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 파일이없는 경우 생성합니다.
이 솔루션은 응용 프로그램이 POSIX 셸 환경에서 GNU Makefile 만 사용하는 경우에 사용되었습니다. 이 프로젝트는 플랫폼 호환성이 문제가되는 오픈 소스 프로젝트가 아닙니다.
목표는 특정 작업 공간의 설정과 사용을 모두 용이하게하는 Makefile을 만드는 것이 었습니다. Makefile은 다른 특별한 아카이브 등을 요구하지 않고 다양한 간단한 리소스를 함께 제공합니다. 어떤 의미에서는 쉘 아카이브입니다. 그런 다음 절차는이 Makefile을 작업 할 폴더에 놓는 것과 같은 명령을 내릴 수 있습니다. 작업 공간을 설정하고를 입력 make workspace
한 다음, blah를 입력하십시오.make blah
.
까다로울 수있는 것은 셸 인용문을 찾는 것입니다. 위의 내용은 작업을 수행하며 Makefile에서 here 문서를 지정하는 아이디어에 가깝습니다. 일반적인 사용에 좋은 아이디어인지 여부는 완전히 다른 문제입니다.
문자열 대체 사용 :
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'
) 로 교체하기 때문에 작동합니다 . 동등한 쉘 스크립트 호출을 다음과 같이 생각할 수 있습니다.
전에:
$ 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))
이것이 누군가에게 도움이되기를 바랍니다. =)
대안으로 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)'`"
export ANNOUNCE_BODY
규칙 내에서만 변수를 설정합니다. $$ ANNOUNCE_BODY를 참조하여 다른 변수를 정의 할 수 없습니다.