TL; DR อย่าพยายามทำสิ่งนี้
$ make run arg
สร้างสคริปต์แทน:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
และทำสิ่งนี้:
$ ./buildandrunprog.sh arg
ตอบคำถามที่ระบุไว้:
คุณสามารถใช้ตัวแปรในสูตร
run: prog
./prog $(var)
จากนั้นส่งการกำหนดตัวแปรให้เป็นอาร์กิวเมนต์เพื่อสร้าง
$ make run var=arg
./prog arg
นี้จะดำเนินการ
แต่ระวังข้อผิดพลาด ฉันจะทำอย่างละเอียดเกี่ยวกับข้อผิดพลาดของวิธีนี้และวิธีการอื่น ๆ ต่อไป
ตอบความตั้งใจที่อยู่เบื้องหลังคำถาม:
ข้อสันนิษฐาน: คุณต้องการเรียกใช้prog
ด้วยอาร์กิวเมนต์บางตัว แต่ให้สร้างใหม่ก่อนที่จะทำงานหากจำเป็น
คำตอบ: สร้างสคริปต์ที่สร้างใหม่ถ้าจำเป็นแล้วเรียกใช้ prog ด้วย args
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
สคริปต์นี้ทำให้ความตั้งใจชัดเจนมาก มันใช้ make เพื่อทำสิ่งที่มันดีสำหรับ: building มันใช้เชลล์สคริปต์เพื่อทำสิ่งที่ดีสำหรับ: การประมวลผลแบบแบตช์
รวมทั้งคุณสามารถทำสิ่งอื่นที่คุณอาจต้องการด้วยความยืดหยุ่นและการแสดงออกของเชลล์สคริปต์อย่างเต็มที่โดยไม่มีคำเตือนทั้งหมดของ makefile
ไวยากรณ์การโทรก็เหมือนกันในทางปฏิบัติแล้ว:
$ ./buildandrunprog.sh foo "bar baz"
เปรียบเทียบกับ:
$ ./prog foo "bar baz"
ตรงกันข้ามกับ
$ make run var="foo bar\ baz"
พื้นหลัง:
make ไม่ได้ถูกออกแบบมาเพื่อส่งอาร์กิวเมนต์ไปยังเป้าหมาย อาร์กิวเมนต์ทั้งหมดในบรรทัดคำสั่งถูกตีความว่าเป็นเป้าหมาย (aka เป้าหมาย) เป็นตัวเลือกหรือเป็นการกำหนดตัวแปร
ดังนั้นถ้าคุณเรียกใช้สิ่งนี้:
$ make run foo --wat var=arg
ทำให้จะตีความrun
และfoo
เป็นเป้าหมาย (เป้าหมาย) เพื่ออัปเดตตามสูตรของพวกเขา --wat
เป็นตัวเลือกสำหรับการทำ และvar=arg
เป็นการกำหนดตัวแปร
สำหรับรายละเอียดเพิ่มเติมดูได้ที่: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
สำหรับคำศัพท์โปรดดูที่: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
เกี่ยวกับวิธีการกำหนดตัวแปรและทำไมฉันถึงแนะนำมัน
$ make run var=arg
และตัวแปรในสูตร
run: prog
./prog $(var)
นี่เป็นวิธีที่ "ถูกต้อง" และตรงไปตรงมาที่สุดในการส่งผ่านข้อโต้แย้งไปยังสูตร แต่ในขณะที่มันสามารถใช้เพื่อเรียกใช้โปรแกรมที่มีข้อโต้แย้งมันไม่ได้ถูกออกแบบมาให้ใช้อย่างนั้น ดูhttps://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
ในความคิดของฉันนี้มีข้อเสียอย่างหนึ่งใหญ่: สิ่งที่คุณต้องการจะทำคือการทำงานที่มีการโต้แย้งprog
arg
แต่แทนที่จะเขียน:
$ ./prog arg
คุณกำลังเขียน:
$ make run var=arg
สิ่งนี้จะได้รับที่น่าอึดอัดใจมากขึ้นเมื่อพยายามที่จะผ่านข้อโต้แย้งหรือข้อโต้แย้งที่มีช่องว่าง:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
เปรียบเทียบกับ:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
สำหรับบันทึกนี่คือสิ่งที่ฉันprog
ดูเหมือน:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
โปรดทราบว่าคุณไม่ควรใส่$(var)
เครื่องหมายคำพูดใน makefile:
run: prog
./prog "$(var)"
เพราะprog
จะได้รับเพียงหนึ่งอาร์กิวเมนต์:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
ทั้งหมดนี้เป็นเหตุผลที่ฉันแนะนำให้กับเส้นทางนี้
เพื่อความสมบูรณ์ที่นี่มีวิธีการอื่น ๆ "ผ่านการขัดแย้งเพื่อให้ทำงาน"
วิธีที่ 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
คำอธิบายสั้น ๆ : กรองเป้าหมายปัจจุบันออกจากรายการเป้าหมาย สร้าง catch all all ( %
) ซึ่งไม่ทำอะไรเลยที่จะเพิกเฉยต่อเป้าหมายอื่น ๆ
วิธีที่ 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
คำอธิบายสั้นสุดถ้าเป้าหมายคือแล้วเอาประตูแรกและสร้างเป้าหมายอะไรทำเพื่อเป้าหมายที่เหลืออยู่โดยใช้run
eval
ทั้งสองจะอนุญาตให้คุณเขียนบางสิ่งเช่นนี้
$ make run arg1 arg2
สำหรับคำอธิบายที่ละเอียดยิ่งขึ้นศึกษาคู่มือการทำ: https://www.gnu.org/software/make/manual/html_node/index.html
ปัญหาของวิธีที่ 1:
อาร์กิวเมนต์ที่ขึ้นต้นด้วยเส้นประจะถูกตีความโดย make และไม่ผ่านเป็นเป้าหมาย
$ make run --foo --bar
วิธีแก้ปัญหา
$ make run -- --foo --bar
อาร์กิวเมนต์ที่มีเครื่องหมายเท่ากับจะถูกตีความโดย make และไม่ผ่าน
$ make run foo=bar
ไม่มีวิธีแก้ไข
ขัดแย้งกับช่องว่างเป็นที่น่าอึดอัดใจ
$ make run foo "bar\ baz"
ไม่มีวิธีแก้ไข
หากมีข้อโต้แย้งเกิดขึ้นrun
(เท่ากับเป้าหมาย) ก็จะถูกลบออก
$ make run foo bar run
จะทำงาน./prog foo bar
แทน./prog foo bar run
วิธีแก้ปัญหาที่เป็นไปได้ด้วยวิธีที่ 2
หากการโต้เถียงเป็นเป้าหมายที่ถูกกฎหมายมันก็จะถูกเรียกใช้
$ make run foo bar clean
จะทำงาน./prog foo bar clean
แต่ยังมีสูตรสำหรับเป้าหมายclean
(สมมติว่ามีอยู่)
วิธีแก้ปัญหาที่เป็นไปได้ด้วยวิธีที่ 2
เมื่อคุณพิมพ์ผิดเป้าหมายที่ถูกต้องมันจะถูกเพิกเฉยอย่างเงียบ ๆ เพราะจับเป้าหมายทั้งหมด
$ make celan
จะเพิกเฉยอย่างเงียบ ๆ celan
ก็จะเงียบไม่สนใจ
วิธีแก้ปัญหาคือการทำให้ทุกอย่างละเอียด ดังนั้นคุณจะเห็นสิ่งที่เกิดขึ้น แต่นั่นสร้างเสียงรบกวนมากสำหรับเอาต์พุตที่ถูกต้อง
ปัญหาของวิธีที่ 2:
หากอาร์กิวเมนต์มีชื่อเดียวกันกับเป้าหมายที่มีอยู่แล้ว make จะพิมพ์คำเตือนว่ามันถูกเขียนทับ
ไม่มีวิธีแก้ปัญหาที่ฉันรู้
อาร์กิวเมนต์ที่มีเครื่องหมายเท่ากับจะยังคงถูกตีความโดย make และไม่ผ่าน
ไม่มีวิธีแก้ไข
การขัดแย้งกับช่องว่างยังคงน่าอึดอัดใจ
ไม่มีวิธีแก้ไข
การโต้เถียงกับการแบ่งช่องว่างeval
พยายามที่จะสร้างไม่ทำอะไรเลยเป้าหมาย
วิธีแก้ปัญหา: สร้างการจับทั่วโลกทุกเป้าหมายโดยไม่ทำอะไรเลย ด้วยปัญหาดังกล่าวข้างต้นว่าจะไม่สนใจเป้าหมายที่ชอบด้วยกฎหมายที่ผิดพลาดอีกต่อไป
มันใช้eval
เพื่อแก้ไข makefile ที่รันไทม์ คุณจะไปได้ไกลแค่ไหนในแง่ของความสามารถในการอ่านและการดีบักและหลักการของความประหลาดใจอย่างน้อยที่สุดหลักการน้อยมหัศจรรย์
วิธีแก้ปัญหา: ไม่ทำเช่นนี้ !! 1 prog
แทนเขียนสคริปต์เปลือกที่วิ่งให้แล้ววิ่ง
ฉันได้ทำการทดสอบโดยใช้ gnu make เท่านั้น สิ่งอื่น ๆ อาจมีพฤติกรรมที่แตกต่างกัน
TL; DR อย่าพยายามทำสิ่งนี้
$ make run arg
สร้างสคริปต์แทน:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
และทำสิ่งนี้:
$ ./buildandrunprog.sh arg