เป็นไปได้ไหมที่จะสร้างตัวแปรสตริงหลายบรรทัดใน Makefile


122

ฉันต้องการสร้างตัวแปร makefile ที่เป็นสตริงหลายบรรทัด (เช่นเนื้อหาของการประกาศการเผยแพร่อีเมล) สิ่งที่ต้องการ

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

It can be downloaded from $(DOWNLOAD_URL)

etc, etc"

แต่ดูเหมือนจะหาวิธีทำไม่ได้ เป็นไปได้ไหม?

คำตอบ:


172

ได้คุณสามารถใช้คำหลัก 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"

สังเกตการใช้การ$$ANNOUNCE_BODYระบุการอ้างอิงตัวแปรสภาพแวดล้อมเชลล์แทนที่จะเป็นการ$(ANNOUNCE_BODY)อ้างอิงตัวแปร make ปกติ นอกจากนี้อย่าลืมใช้เครื่องหมายคำพูดรอบการอ้างอิงตัวแปรของคุณเพื่อให้แน่ใจว่าบรรทัดใหม่ไม่ได้ตีความโดยเชลล์เอง

แน่นอนเคล็ดลับเฉพาะนี้อาจมีความอ่อนไหวต่อแพลตฟอร์มและเปลือก ฉันทดสอบบน Ubuntu Linux ด้วย GNU bash 3.2.13; YMMV


1
export ANNOUNCE_BODYตั้งค่าตัวแปรภายในกฎเท่านั้น - ไม่อนุญาตให้อ้างอิง $$ ANNOUNCE_BODY เพื่อกำหนดตัวแปรอื่น ๆ
anatoly techtonik

@techtonik หากคุณต้องการใช้ค่าANNOUNCE_BODYในนิยามตัวแปรอื่น ๆ ให้อ้างอิงเหมือนกับตัวแปร make อื่น ๆ ตัวอย่างเช่นOTHER=The variable ANNOUNCE_BODY is $(ANNOUNCE_BODY). แน่นอนว่าคุณจะต้องใช้exportเคล็ดลับหากคุณต้องการOTHERออกคำสั่ง
Eric Melski

25

แนวทางการ 'รับตัวแปรกลับหลายสายของคุณออกจาก Makefile' (ที่ระบุไว้โดยเอริค Melski เป็น 'ส่วนที่ยุ่งยาก') อีกคือการวางแผนที่จะใช้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})'

โปรดทราบว่าเครื่องหมายคำพูดเดียวในเสียงสะท้อนสุดท้ายมีความสำคัญ


4
โปรดทราบว่า "echo -e" ไม่สามารถพกพาได้ คุณน่าจะชอบ printf (1) แทน
MadScientist

2
อย่างไรก็ตามคำตอบที่ดีฉันต้องลบ=after define ANNOUNCE_BODYเพื่อให้มันทำงานได้
mschilli

13

สมมติว่าคุณต้องการพิมพ์เนื้อหาของตัวแปรของคุณบนเอาต์พุตมาตรฐานเท่านั้นมีวิธีแก้ปัญหาอื่น:

do-echo:
    $(info $(YOUR_MULTILINE_VAR))

1
นี้ไม่มีกฎ-op make: 'do-echo' is up to date.ผลิตข้อความที่ไม่พึงประสงค์: ด้วยการใช้คำสั่ง "no op" และฉันสามารถปิดเสียงได้:@: $(info $(YOUR_MULTILINE_VAR))
Guillaume Papin

@GuillaumePapin ช้าไปหน่อย แต่คุณสามารถใช้.PHONYเพื่อบอก Makefile ของคุณว่าไม่มีอะไรให้ตรวจสอบกฎนั้น Makefiles เดิมมีไว้สำหรับคอมไพเลอร์ถ้าฉันจำไม่ผิดฉันmakeก็ทำเวทมนตร์บางอย่างที่ฉันไม่เข้าใจเพื่อคาดหวังว่ากฎจะไม่เปลี่ยนแปลงอะไรเลยและด้วยเหตุนี้จึงถือว่าเป็น 'เสร็จสิ้น' การเพิ่ม.PHONY do-echoไฟล์ของคุณจะบอกmakeให้ละเว้นสิ่งนี้และเรียกใช้โค้ดต่อไป
M3D

คุณสามารถวางไว้$(info ...)นอกกฎ make มันจะยังคงสร้างเอาต์พุต
Daniel Stevens

เอกสารประกอบ: Make Control Functions
Daniel Stevens

3

ใช่. คุณหลีกเลี่ยงการขึ้นบรรทัดใหม่ด้วย\:

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

ปรับปรุง

คุณต้องการขึ้นบรรทัดใหม่หรือไม่? ไม่ฉันไม่คิดว่าจะมีวิธีใดในการทำวานิลลา อย่างไรก็ตามคุณสามารถใช้เอกสารที่นี่ในส่วนคำสั่งได้ตลอดเวลา

[ไม่ได้ผลโปรดดูความคิดเห็นจาก MadScientist]

foo:
    echo <<EOF
    Here is a multiple line text
    with embedded newlines.
    EOF

นี่เป็นเรื่องจริง แต่ไม่ได้ให้การจัดรูปแบบใด ๆ (บรรทัดใหม่) มันกลายเป็นข้อความบรรทัดเดียว
jonner

เอกสารที่นี่หลายบรรทัดไม่ทำงานตามที่อธิบายไว้ใน GNU Make
Matt B.

3
เอกสาร Multiline ที่นี่ในสูตรอาหารจะไม่ทำงานในเวอร์ชันมาตรฐานใด ๆ ที่รองรับมาตรฐาน POSIX: มาตรฐานการทำกำหนดให้แต่ละบรรทัดแยกกันของสูตรต้องทำงานในเชลล์แยกกัน Make ไม่ทำการแยกวิเคราะห์คำสั่งใด ๆ เพื่อบอกว่าเป็นเอกสารที่นี่หรือไม่และจัดการต่างกัน หากคุณรู้จักยี่ห้อบางรุ่นที่รองรับสิ่งนี้ (ฉันไม่เคยได้ยินมาก่อน) คุณควรระบุอย่างชัดเจน
MadScientist

2

เพียงแค่คำลงท้ายไปยังคำตอบของ Eric Melski: คุณสามารถรวมเอาท์พุทของคำสั่งในข้อความได้ แต่คุณต้องใช้ไวยากรณ์ 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

2

คุณควรใช้ "define / endef" ทำการสร้าง:

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

It can be downloaded from $(DOWNLOAD_URL).

etc, etc.
endef

จากนั้นคุณควรส่งค่าของตัวแปรนี้ไปยังคำสั่งเชลล์ แต่ถ้าคุณทำสิ่งนี้โดยใช้ Make variable substitution มันจะทำให้คำสั่งแบ่งออกเป็นหลาย ๆ :

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

Qouting ก็ไม่ช่วยเช่นกัน

วิธีที่ดีที่สุดในการส่งผ่านค่าคือการส่งผ่านตัวแปรสภาพแวดล้อม:

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

หมายเหตุ:

  1. ตัวแปรจะถูกส่งออกสำหรับเป้าหมายเฉพาะนี้เพื่อให้คุณสามารถนำสภาพแวดล้อมนั้นกลับมาใช้ใหม่ได้จะไม่ได้รับมลพิษมากนัก
  2. ใช้ตัวแปรสภาพแวดล้อม (qoutes คู่และวงเล็บปีกการอบชื่อตัวแปร);
  3. การใช้เครื่องหมายคำพูดรอบตัวแปร หากไม่มีการขึ้นบรรทัดใหม่จะหายไปและข้อความทั้งหมดจะปรากฏในบรรทัดเดียว

2

สิ่งนี้ไม่ได้ให้เอกสารที่นี่ แต่จะแสดงข้อความหลายบรรทัดในลักษณะที่เหมาะสำหรับไปป์

=====

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
---
$

=====


1

ทำไมคุณไม่ใช้อักขระ \ 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"

ฉันชอบคำตอบของ Erik Melski แต่อาจเป็นเคล็ดลับสำหรับคุณอยู่แล้วทั้งนี้ขึ้นอยู่กับใบสมัครของคุณ
Roalt

ฉันมีคำถามเกี่ยวกับเรื่องนี้ วิธีนี้ใช้งานได้ดีเป็นหลักยกเว้นฉันเห็น "ช่องว่าง" เพิ่มเติมในตอนต้นของทุกบรรทัด (ยกเว้นบรรทัดแรก) สิ่งนี้เกิดขึ้นกับคุณหรือไม่? ฉันสามารถใส่ข้อความทั้งหมดในบรรทัดเดียวโดยคั่นด้วย \ n เพื่อสร้างผลลัพธ์ที่ฉันชอบได้อย่างมีประสิทธิภาพ ปัญหาคือมันดูน่าเกลียดมากใน Makefile เอง!
Shahbaz

ฉันพบวิธีแก้ปัญหา ฉันใส่ข้อความลงไป$(subst \n ,\n,$(TEXT))แม้ว่าฉันหวังว่าจะมีวิธีที่ดีกว่านี้!
Shahbaz

1

ดูคำตอบของฉันว่าทำไมมันถึงไม่ได้ผล (อย่างน้อยก็จากความพยายามของฉัน)
Roalt

1
คู่มือจะแสดงให้คุณเห็นวิธีการที่เหมาะสมที่ทำงาน: echoใช้
Ding-Yi Chen

1

ด้วยจิตวิญญาณของ. 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

ฉันชอบคำตอบของอัลฮาดิสที่สุด แต่หากต้องการจัดรูปแบบคอลัมน์ให้เพิ่มอีกสิ่งหนึ่ง

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

บทสรุปของโปรแกรมควรจะง่ายและชัดเจนในการค้นหา ขอแนะนำให้เพิ่มข้อมูลระดับนี้ใน readme และ / หรือ manpage เมื่อผู้ใช้เรียกใช้makeโดยทั่วไปพวกเขาคาดหวังว่าจะเริ่มกระบวนการสร้าง

1
ฉันต้องการหลายครั้งเพื่อดูรายการเป้าหมายที่สร้างขึ้น ความคิดเห็นของคุณไม่สมเหตุสมผล สิ่งที่ผู้ใช้คาดหวังนั้นไม่เกี่ยวข้องหากพวกเขาใช้เวลา 3 วินาทีในการรู้ว่าต้องทำอะไรในขณะที่ข้อมูลเช่นนี้บางครั้งอาจใช้เวลาหลายชั่วโมงแทน
Xennex81

1
การใช้ความคาดหวังเป็นเหตุผลในการทำบางสิ่งก็เป็นการโต้เถียงแบบวงกลมเช่นกันเพราะผู้คนคาดหวังเราต้องทำและเพราะเราทำสิ่งนั้นพวกเขาจึงคาดหวัง
Xennex81

1

ไม่เกี่ยวข้องกับ 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)

ดูตัวอย่างด้านล่าง

nb: ในกรณีเฉพาะของฉันฉันต้องการส่งคีย์ ssh ในระหว่างการสร้างภาพโดยใช้ตัวอย่างจากhttps://vsupalov.com/build-docker-image-clone-private-repo-ssh-key/ (โดยใช้ สร้างนักเทียบท่าแบบหลายขั้นตอนเพื่อโคลน repo 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
... 

1

ด้วย 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จะทำให้เป้าหมายทั้งหมดใน Makefile ใช้เชลล์เดียวสำหรับคำสั่งทั้งหมด


น่าเสียดายที่ไม่ได้ผล: 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 ทำ 3,81)
blueyed

@blueyed ฉันเพิ่งทดสอบกับ GNU Make 3.82 และ GNU bash 4.2.45 (1) - ปล่อย: มันทำงานได้ตามที่คาดไว้ นอกจากนี้โปรดตรวจสอบการมีอยู่ของอักขระ TAB นำหน้าแทนที่จะเป็นช่องว่างหน้า@printf ...ข้อความ - ดูเหมือนว่าTAB จะแสดงผลเป็น 4 ช่องว่างเสมอ ...
sphakka

ปรากฏว่า.ONESHELLเป็นสิ่งใหม่ในการสร้าง 3.82
blueyed

BTW: *** missing separator. Stop.ข้อผิดพลาดเมื่อมีการใช้ช่องว่างแทนแท็บจะเป็น
blueyed

0

ไม่ใช่คำตอบที่เป็นประโยชน์ แต่เพียงเพื่อระบุว่า 'กำหนด' ไม่ทำงานตามที่ 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 เป็นคำสั่ง



0

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 เท่านั้น โครงการนี้ไม่ใช่โครงการโอเพ่นซอร์สที่ปัญหาความเข้ากันได้ของแพลตฟอร์มเป็นปัญหา

เป้าหมายคือการสร้าง Makefile ที่อำนวยความสะดวกทั้งการตั้งค่าและการใช้งานพื้นที่ทำงานบางประเภท Makefile นำมาพร้อมกับทรัพยากรที่เรียบง่ายต่างๆโดยไม่ต้องใช้สิ่งต่างๆเช่นที่เก็บถาวรพิเศษอื่น ๆ ในแง่หนึ่งมันเป็นไฟล์เก็บถาวรเชลล์ จากนั้นโพรซีเดอร์สามารถพูดสิ่งต่างๆเช่นวาง Makefile นี้ในโฟลเดอร์เพื่อใช้งานได้ตั้งค่าการป้อนพื้นที่ทำงานของคุณmake workspaceจากนั้นทำ blah ให้ป้อนmake blahฯลฯ

สิ่งที่อาจยุ่งยากคือการหาสิ่งที่จะอ้างถึง ข้างต้นทำงานได้ดีและใกล้เคียงกับแนวคิดในการระบุเอกสารที่นี่ใน Makefile ไม่ว่าจะเป็นความคิดที่ดีสำหรับการใช้งานทั่วไปเป็นปัญหาอื่น ๆ


0

ฉันเชื่อว่าคำตอบที่ปลอดภัยที่สุดสำหรับการใช้งานข้ามแพลตฟอร์มคือการใช้หนึ่งเสียงสะท้อนต่อบรรทัด:

  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" >> $@

สิ่งนี้หลีกเลี่ยงการตั้งสมมติฐานใด ๆ เกี่ยวกับเวอร์ชันของเสียงสะท้อนที่มีอยู่


0

ใช้การแทนที่สตริง :

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))

หวังว่านี่จะช่วยใครสักคน =)


ฉันชอบอันนี้ที่สุด แต่หากต้องการจัดรูปแบบคอลัมน์ให้เพิ่มอีกสิ่งหนึ่ง `SYNOPSIS: = :: เรื่องย่อ: Makefile \ | :: \ | :: การใช้งาน: \ | :: make .......... : สร้างข้อความนี้ \ | :: ทำเรื่องย่อ : สร้างข้อความนี้ \ | :: ทำความสะอาด .... : กำจัดตัวกลางและเป้าหมายที่ไม่ต้องการ \ | :: make all ...... : รวบรวมระบบทั้งหมดจาก ground-up \ endef
jlettvin

ความคิดเห็นไม่อนุญาตให้ใช้รหัส จะส่งเป็นคำตอบ. ฉันชอบอันนี้ที่สุด แต่หากต้องการจัดรูปแบบคอลัมน์ให้เพิ่มอีกสิ่งหนึ่ง `SYNOPSIS: = :: เรื่องย่อ: Makefile`` | :: `` | :: การใช้งาน: `` | :: make .......... : สร้างข้อความนี้ `` | :: ทำเรื่องย่อ : สร้างข้อความนี้ `` | :: make clean .... : กำจัดตัวกลางและเป้าหมายที่ไม่ต้องการ `` | :: make all ...... : รวบรวมระบบทั้งหมดจาก ground-up` `endef`
jlettvin

@jlettvin ดูคำตอบของฉันสำหรับคำตอบของคุณ บทสรุปของโปรแกรมควรแน่นอนไม่ได้ถูกฝังอยู่ภายใน Makefile โดยเฉพาะอย่างยิ่งไม่เป็นงานที่เริ่มต้น

0

คุณสามารถใช้คำสั่ง 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)'`"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.