จะส่งอาร์กิวเมนต์ไปยัง Makefile จากบรรทัดคำสั่งได้อย่างไร


109

จะส่งอาร์กิวเมนต์ไปยัง Makefile จากบรรทัดคำสั่งได้อย่างไร

ฉันเข้าใจว่าฉันทำได้

$ make action VAR="value"
$ value

ด้วย Makefile

VAR = "default"
action:
    @echo $(VAR)

ฉันจะมีพฤติกรรมต่อไปนี้ได้อย่างไร?

$ make action value
value

เหรอ?

เกี่ยวกับ

$make action value1 value2
value1 value2


คำตอบ:


212

คุณอาจไม่ควรทำเช่นนี้ คุณกำลังทำลายรูปแบบพื้นฐานของวิธีการทำงาน แต่นี่คือ:

action:
        @echo action $(filter-out $@,$(MAKECMDGOALS))

%:      # thanks to chakrit
    @:    # thanks to William Pursell

แก้ไข:
เพื่ออธิบายคำสั่งแรก

$(MAKECMDGOALS) คือรายการของ "เป้าหมาย" ที่สะกดในบรรทัดคำสั่งเช่น "action value1 value2"

$@เป็นตัวแปรอัตโนมัติสำหรับชื่อเป้าหมายของกฎในกรณีนี้คือ "action"

filter-outเป็นฟังก์ชันที่ลบองค์ประกอบบางอย่างออกจากรายการ ดังนั้น$(filter-out bar, foo bar baz)ผลตอบแทนfoo baz(อาจจะละเอียดกว่านี้ แต่เราไม่ต้องการความละเอียดอ่อนที่นี่)

รวมสิ่งเหล่านี้เข้าด้วยกันและ$(filter-out $@,$(MAKECMDGOALS))ส่งคืนรายการเป้าหมายที่ระบุในบรรทัดคำสั่งอื่นที่ไม่ใช่ "action" ซึ่งอาจเป็น "value1 value2"


1
$(shell echo $(MAKECMDGOALS) | sed 's!^.* $@ !!')เพื่อละเว้นเป้าหมายทั้งหมดก่อนและพิจารณาสิ่งต่อไปนี้เป็นอาร์กิวเมนต์:make target1 target2 action value1 value2
Evgeniy Generalov

1
ขออภัยในความไม่รู้ของฉัน ฉันได้ลองใช้ googling %:และ@:ไม่พบข้อมูลว่า "คำสั่ง" เหล่านั้น (หรืออะไรก็ตามที่เรียกว่า) ทำ คุณช่วยอธิบายได้ไหม?
จอน

15
@ จอน: คู่มือการใช้งานเป็นที่นี่ ส่วนประกอบด้วย%:และ@:เป็นกฎ ชื่อเป้าหมาย%หมายความว่ามันเป็นกฎที่ตรงกับอะไร ; นั่นคือถ้า Make ไม่พบวิธีอื่นในการสร้างสิ่งที่คุณบอกให้สร้างก็จะดำเนินการตามกฎนั้น @:เป็นสูตร ; :หมายถึงทำอะไรและ@วิธีการทำมันอย่างเงียบ ๆ
เบต้า

ขอบคุณ. ตอนแรกฉันอ่านคู่มือนั้นแล้ว แต่ตอนแรกก็ไม่ได้พิจารณานั่น%:คือ% :ชื่อเป้าหมายประเภทไวลด์การ์ด ฉันไม่เห็นอะไรเลยในหน้าคู่มือนั้นเกี่ยวกับ@:แม้ว่า ... มันแนะนำว่ากฎ "ไม่ต้องทำอะไร" ก็จะมี;ตามข้อกำหนดเป้าหมายดังนั้นมันจะไม่ถูกต้องกว่าที่จะเขียน% : ;ในฐานะ "ตัวแทนทำ - ไม่มีอะไร "กฎ?
จอน

1
filter-outไม่ทำงานเมื่อการดำเนินการเป็นการอ้างอิงของเป้าหมายที่ระบุในบรรทัดคำสั่งเนื่องจาก$@จะถูกตั้งค่าเป็นชื่อของการอ้างอิงไม่ใช่อาร์กิวเมนต์ดั้งเดิมที่เรียกบนบรรทัดคำสั่ง แต่ฉันกำหนดให้MAKECMDGOALSกับอาร์เรย์เชลล์แล้วลบองค์ประกอบแรก:@ args=($(MAKECMDGOALS)); args=("$${args[@]:1}")
Gingi

18

นี่คือโซลูชันการทำงานทั่วไปที่อ้างอิงจาก @ Beta

ฉันใช้ GNU Make 4.1 กับSHELL=/bin/bashบน Makefile ของฉันดังนั้น YMMV!

สิ่งนี้ช่วยให้เรายอมรับข้อโต้แย้งเพิ่มเติม (โดยไม่ต้องทำอะไรเลยเมื่อเราได้งานที่ไม่ตรงกันแทนที่จะโยนข้อผิดพลาด)

%:
    @:

และนี่คือมาโครที่ได้รับ args สำหรับเรา:

args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`

นี่คืองานที่อาจเรียกสิ่งนี้ว่า:

test:
    @echo $(call args,defaultstring)

ผลลัพธ์จะเป็น:

$ make test
defaultstring
$ make test hi
hi

บันทึก! คุณอาจจะดีกว่าการใช้ "Taskfile" ซึ่งเป็นรูปแบบ bash ที่ทำงานคล้าย ๆ กันโดยไม่ต้องใช้ความแตกต่างของ Maketools ดูhttps://github.com/adriancooney/Taskfile


มันได้ผล !! ให้คนอื่น ๆ พยายามออกให้แน่ใจว่ามีtabก่อนที่จะไม่@echo space
Abdullah Al Maruf - Tuhin

11

aproach ง่ายกว่ามาก พิจารณางาน:

provision:
        ansible-playbook -vvvv \
        -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \
        --private-key=.vagrant/machines/default/virtualbox/private_key \
        --start-at-task="$(AT)" \
        -u vagrant playbook.yml

ตอนนี้เมื่อฉันต้องการเรียกมันฉันแค่เรียกใช้สิ่งที่ชอบ:

AT="build assets" make provision

หรือเพียงแค่:

make provisionในกรณีนี้ATคือสตริงว่าง


-2

อย่าพยายามทำสิ่งนี้

$ make action value1 value2

สร้างสคริปต์แทน:

#! /bin/sh
# rebuild if necessary
make
# do action with arguments
action "$@"

และทำสิ่งนี้:

$ ./buildthenaction.sh value1 value2

สำหรับคำอธิบายเพิ่มเติมว่าเหตุใดจึงทำเช่นนี้และข้อควรระวังของการแฮ็กเกอร์ makefile อ่านคำตอบของฉันสำหรับคำถามอื่นที่คล้ายกันมาก แต่ดูเหมือนจะไม่ซ้ำกัน: การส่งผ่านข้อโต้แย้งเพื่อ "ดำเนินการ"

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