วิธีพิมพ์ตัวแปรใน makefile


247

ใน makefile ของฉันฉันมีตัวแปร 'NDK_PROJECT_PATH' คำถามของฉันคือฉันจะพิมพ์ออกมาเมื่อคอมไพล์ได้อย่างไร

ฉันอ่านMake file echo แสดงสตริง "$ PATH"แล้วลอง:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

ทั้งสองให้ฉัน

"build-local.mk:102: *** missing separator.  Stop."

ใครรู้ว่าทำไมมันไม่ทำงานสำหรับฉัน

คำตอบ:


223

คุณสามารถพิมพ์ตัวแปรตามที่ makefile อ่านอยู่ (สมมติว่า GNU ทำตามที่คุณติดแท็กคำถามนี้อย่างเหมาะสม) โดยใช้วิธีนี้ (ด้วยตัวแปรที่ชื่อว่า "var"):

$(info $$var is [${var}])

คุณสามารถเพิ่มโครงสร้างนี้ลงในสูตรใดก็ได้เพื่อดูว่าสิ่งที่ make จะส่งผ่านไปยังเชลล์:

.PHONY: all
all: ; $(info $$var is [${var}])echo Hello world

ตอนนี้สิ่งที่เกิดขึ้นที่นี่คือการทำให้ร้านค้าสูตรทั้งหมด ( $(info $$var is [${var}])echo Hello world) เป็นตัวแปรเดี่ยวที่ขยายซ้ำ เมื่อตัดสินใจที่จะเรียกใช้สูตร (เช่นเมื่อคุณบอกให้สร้างall) มันจะขยายตัวแปรแล้วส่งแต่ละบรรทัดผลลัพธ์แยกจากกันไปยังเชลล์

ดังนั้นในรายละเอียดที่เจ็บปวด:

  • มันขยายตัว $(info $$var is [${var}])echo Hello world
  • การทำเช่นนี้มันจะขยายตัวครั้งแรก $(info $$var is [${var}])
    • $$ กลายเป็นตัวอักษร $
    • ${var}กลายเป็น:-)(พูด)
    • ผลข้างเคียงคือ$var is [:-)]ปรากฎตามมาตรฐาน
    • การขยายตัวของ$(info...)แม้ว่าจะว่างเปล่า
  • ทำให้ถูกทิ้งไว้ด้วย echo Hello world
    • ทำภาพพิมพ์echo Hello worldบน stdout ก่อนเพื่อให้คุณรู้ว่าจะให้เปลือกทำอะไร
  • เชลล์พิมพ์Hello worldบน stdout

2
มันควรจะเป็น (dot) .PHONY แทนที่จะเป็น PHONY หรือไม่
hammadian

172

ตามคู่มือการใช้งานของGNUและชี้โดย 'bobbogo' ในคำตอบด้านล่างคุณสามารถใช้ข้อมูล / คำเตือน / ข้อผิดพลาดเพื่อแสดงข้อความ

$(error   text…)
$(warning text…)
$(info    text…)

หากต้องการพิมพ์ตัวแปร

$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

'ข้อผิดพลาด' จะหยุดให้การดำเนินการหลังจากการแสดงสตริงข้อผิดพลาด


ว้าวไม่รู้เรื่องนี้ วิธีที่ดีกว่าเสียงก้องซึ่งซ้ำคำสั่งในบันทึก
deepelement

148

จาก "Mr. Make post" https://www.cmcrossroads.com/article/printing-value-makefile-variable

เพิ่มกฎต่อไปนี้ใน Makefile ของคุณ:

print-%  : ; @echo $* = $($*)

จากนั้นหากคุณต้องการหาค่าของตัวแปร makefile เพียงแค่:

make print-VARIABLE

และมันจะกลับมา:

VARIABLE = the_value_of_the_variable

คุณอธิบายได้ดีกว่าผู้เขียน ยกนิ้ว!
f0nzie

44

ถ้าคุณต้องการเพียงแค่เอาท์พุทคุณต้องการใช้$(info)ด้วยตัวเอง คุณสามารถทำได้ทุกที่ใน Makefile และมันจะแสดงเมื่อมีการประเมินบรรทัดนั้น:

$(info VAR="$(VAR)")

จะส่งออกVAR="<value of VAR>"เมื่อใดก็ตามที่ทำให้กระบวนการที่บรรทัด พฤติกรรมนี้ขึ้นอยู่กับตำแหน่งมากดังนั้นคุณต้องตรวจสอบให้แน่ใจว่าการ$(info)ขยายเกิดขึ้นหลังจากทุกอย่างที่สามารถแก้ไข$(VAR)ได้เกิดขึ้นแล้ว!

ตัวเลือกทั่วไปมากขึ้นคือการสร้างกฎพิเศษสำหรับการพิมพ์ค่าของตัวแปร โดยทั่วไปกฎจะดำเนินการหลังจากกำหนดตัวแปรดังนั้นสิ่งนี้จะแสดงให้คุณเห็นถึงคุณค่าที่ใช้จริง (แม้ว่าจะเป็นไปได้สำหรับกฎที่จะเปลี่ยนตัวแปร ) การจัดรูปแบบที่ดีจะช่วยให้ชัดเจนว่าตัวแปรถูกตั้งค่าไว้ที่ใดและ$(flavor)ฟังก์ชั่นจะบอกคุณว่าตัวแปรชนิดใดที่เป็น ดังนั้นในกฎนี้:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*ขยายไปถึงก้านที่% รูปแบบจับคู่ในกฎ
  • $($*)$*ขยายไปยังค่าของตัวแปรที่มีชื่อจะได้รับโดยโดย
  • [และ]เห็นได้ชัดว่าการขยายตัววิเคราะห์ตัวแปร คุณสามารถใช้"และ"หรือคล้ายกัน
  • $(flavor $*)บอกคุณว่ามันคือตัวแปรชนิดใด หมายเหตุ: $(flavor) ใช้ชื่อตัวแปรไม่ใช่ส่วนขยาย ดังนั้นถ้าคุณพูดว่าmake print-LDFLAGSคุณจะได้รับ$(flavor LDFLAGS)ซึ่งเป็นสิ่งที่คุณต้องการ
  • $(info text)ให้ผลลัพธ์ ทำให้การพิมพ์textบน stdout เป็นผลข้างเคียงของการขยายตัว การขยายตัวของ$(info)แม้ว่าจะว่างเปล่า คุณสามารถคิดถึงมันได้@echoแต่ที่สำคัญมันไม่ได้ใช้เชลล์ดังนั้นคุณไม่ต้องกังวลกับกฎการอ้างอิงเชลล์
  • @trueมีเพียงเพื่อให้คำสั่งสำหรับกฎ หากไม่มีสิ่งนั้น makeก็จะส่งออกprint-blah is up to dateเช่นกัน ฉันรู้สึกว่า@trueมันชัดเจนมากขึ้นว่ามันไม่ได้เป็น op

เรียกใช้คุณจะได้รับ

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]

สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม จะวิจารณ์หรือการร้องขอคำชี้แจงจากผู้เขียนแสดงความคิดเห็นด้านล่างโพสต์ของพวกเขา - คุณสามารถแสดงความคิดเห็นในโพสต์ของคุณเองและเมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด- จากการทบทวน
Dragon Energy

ขอบคุณสำหรับความคิดเห็น ฉันเข้าใจว่าฉันสามารถแสดงความคิดเห็นเมื่อฉันมีชื่อเสียงเพียงพอ แต่ฉันควรทำอย่างไรในระหว่างนี้ ฉันเชื่อว่าคำตอบของฉันให้คุณค่าเพิ่มเติมดังนั้นฉันไม่ควรเพิ่มหรือไม่
Jim Nasby

1
ฉันขอแนะนำให้เขียนสิ่งนี้ใหม่เพื่อเป็นคำตอบแบบสแตนด์อโลนที่แข่งขันกับสิ่งที่คุณแสดงความคิดเห็นแทนที่จะเขียนเป็นความคิดเห็นนอกสถานที่กับคำตอบนั้น
Charles Duffy

@JimNasby ใช่สิ่งที่ Charles แนะนำ จริงๆแล้วมันอาจช่วยในการเริ่มต้นที่จะลบส่วนที่ "เสียใจไม่พอที่จะแสดงความคิดเห็น" ส่วนหนึ่งเพราะมันเป็นชนิดของธงสีแดง หากคุณเปลี่ยนเป็นคำตอบที่สมบูรณ์ (สามารถแก้ไขได้ทั้งหมดตามที่คุณต้องการ) มันน่าจะทำได้ค่อนข้างดี ไชโย
Dragon Energy

ยอดเยี่ยม - นี่เป็นคำตอบที่ดีกว่าตอนนี้ :)
Charles Duffy

6

@echo $ (NDK_PROJECT_PATH) เป็นวิธีที่ดีที่จะทำ ฉันไม่คิดว่าข้อผิดพลาดมาจากที่นั่น โดยทั่วไปแล้วข้อผิดพลาดนี้จะปรากฏขึ้นเมื่อคุณพิมพ์ข้อความที่พิมพ์ผิด: ฉันคิดว่าคุณมีช่องว่างที่คุณควรมีแท็บ


2
ฉันลอง '@echo $ (NDK_PROJECT_PATH)' ฉันยังคงพบข้อผิดพลาด "build-local.mk:102: *** ตัวแยกขาดหายไปหยุด" ฉันมีที่ว่าง 1 หลัง 'echo' ไม่มีช่องว่างหรือแท็บหน้า '@echo'
ไมเคิล

คุณแน่ใจหรือว่าข้อผิดพลาดมาจากบรรทัดนี้ บรรทัดนี้อยู่ในกฎหรือไม่? เธออาจจะต้องเยื้อง ...

6

ทุกรุ่น makeต้องการนั้นบรรทัดคำสั่งจะถูกเยื้องกับ TAB (ไม่ใช่ช่องว่าง) เป็นอักขระตัวแรกในบรรทัด หากคุณแสดงให้เราเห็นกฎทั้งหมดแทนที่จะเป็นเพียงสองบรรทัดที่เป็นปัญหาเราสามารถให้คำตอบที่ชัดเจนยิ่งขึ้น แต่ควรเป็นดังนี้:

myTarget: myDependencies
        @echo hi

โดยที่อักขระตัวแรกในบรรทัดที่สองต้องเป็น TAB


4

วิ่ง make -n ; มันแสดงให้คุณเห็นค่าของตัวแปร ..

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

คำสั่ง:

export NDK_PROJECT_PATH=/opt/ndk/project
make -n 

เอาท์พุท:

echo /opt/ndk/project

แม้ว่ามันจะมีประโยชน์ทีเดียวและฉันก็ใช้--just-printเหมือนกันในแทนการประหารชีวิต
Fredrick Gauss

3

สิ่งนี้makefileจะสร้างข้อความแสดงข้อผิดพลาด 'ตัวคั่นหายไป':

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

มีแท็บก่อนที่จะได้เป็น@echo "All done"(แม้ว่าdone:กฎและการกระทำที่มีความฟุ่มเฟือยส่วนใหญ่) @echo PATH=$(PATH)แต่ไม่ก่อน

ปัญหาคือการเริ่มต้นของเส้นallควรมีเครื่องหมายจุดคู่:หรือเท่ากับ=เพื่อระบุว่าเป็นเส้นเป้าหมายหรือบรรทัดมาโครและไม่มีทั้งตัวคั่นดังนั้นจึงขาดหายไป

การดำเนินการที่สะท้อนค่าของตัวแปรต้องเชื่อมโยงกับเป้าหมายอาจเป็นเป้าหมายจำลองหรือเป้าหมาย PHONEY และบรรทัดเป้าหมายนั้นจะต้องมีเครื่องหมายจุดคู่อยู่ หากคุณเพิ่ม a :after allในตัวอย่างmakefileและแทนที่ช่องว่างนำหน้าในบรรทัดถัดไปด้วยแท็บมันจะทำงานได้ตามปกติ

คุณอาจจะมีปัญหาที่คล้ายคลึงใกล้เส้น 102 makefileเดิม หากคุณแสดง 5 บรรทัดที่ไม่ว่างเปล่าและไม่มีความคิดเห็นก่อนการดำเนินการ echo ที่ล้มเหลวอาจเป็นไปได้ที่จะทำการวินิจฉัยให้เสร็จสิ้น อย่างไรก็ตามเนื่องจากมีการถามคำถามในเดือนพฤษภาคม 2556 จึงไม่น่าเป็นไปได้ที่makefileจะยังคงมีการชำรุด(สิงหาคม 2557) ดังนั้นคำตอบนี้จึงไม่สามารถตรวจสอบได้ มันสามารถใช้เพื่อแสดงให้เห็นถึงวิธีการที่เป็นไปได้ที่เกิดปัญหา


3

ไม่จำเป็นต้องแก้ไข Makefile

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE

2

ปัญหาคือเสียงสะท้อนนั้นทำงานได้ภายใต้บล็อกการดำเนินการเท่านั้น คืออะไรหลังจาก "xx:"

ดังนั้นสิ่งใดก็ตามที่อยู่เหนือบล็อกการเรียกใช้ครั้งแรกจึงเป็นเพียงการเริ่มต้นดังนั้นจึงไม่มีคำสั่งการเรียกใช้งาน

ดังนั้นสร้างการดำเนินการ blocl


1

ซึ่งสามารถทำได้ในลักษณะทั่วไปและมีประโยชน์มากเมื่อทำการดีบัก makefile ที่ซับซ้อน ทำตามเทคนิคเดียวกับที่อธิบายไว้ในคำตอบอื่นคุณสามารถแทรกสิ่งต่อไปนี้ใน makefile ใด ๆ :

# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)

  # take the rest of the arguments as variable names
  VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))

  # turn them into do-nothing targets
  $(eval $(VAR_NAMES):;@:))

  # then print them
  .PHONY: print
  print:
          @$(foreach var,$(VAR_NAMES),\
            echo '$(var) = $($(var))';)
endif

จากนั้นคุณสามารถทำ "พิมพ์" เพื่อดัมพ์ค่าของตัวแปรใด ๆ :

$ make print CXXFLAGS
CXXFLAGS = -g -Wall

1

คุณสามารถสร้างกฎ vars ในไฟล์สร้างของคุณเช่นนี้:

dispvar = echo $(1)=$($(1)) ; echo

.PHONY: vars
vars:
    @$(call dispvar,SOMEVAR1)
    @$(call dispvar,SOMEVAR2)

: มีบางวิธีที่มีประสิทธิภาพมากขึ้นในการถ่ายโอนข้อมูลตัวแปรทั้งหมดที่นี่มีGNU ยี่ห้อ: รายการค่าของตัวแปรทั้งหมด (หรือ "มาโคร") ในระยะโดยเฉพาะอย่างยิ่ง


0

หากคุณไม่ต้องการแก้ไข Makefile เองคุณสามารถใช้--evalเพื่อเพิ่มเป้าหมายใหม่แล้วดำเนินการเป้าหมายใหม่เช่น

make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

คุณสามารถแทรกอักขระ TAB ที่ต้องการในบรรทัดคำสั่งโดยใช้ CTRL-V, TAB

ตัวอย่าง Makefile จากด้านบน:

all: do-something

TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1

ฉันพยายามเรียกใช้สคริปต์ของคุณ แต่ฉันได้รับข้อผิดพลาดmake: *** missing separator. Stop.
Rinaldi Segecin

อ๊ะขอโทษคง ไม่พบโคลอนในตอนท้ายของเป้าหมาย "การทดสอบการพิมพ์"
ลุย

อันที่จริงคุณไม่จำเป็นต้องมีการขึ้นบรรทัดใหม่และแท็บอัฒภาคจะพอเพียง:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

ถ้าคุณใช้ android make (mka) @echo $(NDK_PROJECT_PATH)จะไม่ทำงานและให้ข้อผิดพลาดกับคุณ*** missing separator. Stop." ใช้คำตอบนี้ถ้าคุณพยายามพิมพ์ตัวแปรใน android make

NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))

ที่ทำงานให้ฉัน


0

ฉันมักจะสะท้อนกับข้อผิดพลาดถ้าฉันต้องการดูค่าตัวแปร (เฉพาะในกรณีที่คุณต้องการดูค่ามันจะหยุดการทำงาน)

@echo $ (ข้อผิดพลาด NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

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