คุณจะรับรายชื่อเป้าหมายใน makefile ได้อย่างไร


202

ฉันใช้เรคบิต (โปรแกรมทำ Ruby) และมีตัวเลือกเพื่อรับรายการเป้าหมายที่มีอยู่ทั้งหมดเช่น

> rake --tasks
rake db:charset      # retrieve the charset for your data...
rake db:collation    # retrieve the collation for your da...
rake db:create       # Creates the databases defined in y...
rake db:drop         # Drops the database for your curren...
...

แต่ดูเหมือนจะไม่มีตัวเลือกในการทำเช่นนี้ใน GNU ทำ

เห็นได้ชัดว่ารหัสเกือบจะมีมันเป็นของปี 2007 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html

อย่างไรก็ตามฉันได้แฮ็คเล็กน้อยเพื่อแยกเป้าหมายออกจาก makefile ซึ่งคุณสามารถรวมไว้ใน makefile ได้

list:
    @grep '^[^#[:space:]].*:' Makefile

มันจะให้รายการของเป้าหมายที่กำหนดไว้ มันเป็นเพียงการเริ่มต้นเท่านั้น - มันไม่ได้กรองการพึ่งพาเช่นกัน

> make list
list:
copy:
run:
plot:
turnin:

2
ฉันอ่านคำตอบอย่างรวดเร็วซึ่งน่าสนใจ แต่สำหรับตัวฉันเองฉันต้องการให้มันเรียบง่ายและพกพาโดยใช้นามแฝง (ใน. bashrc ของฉัน): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' บ่อยครั้งที่ฉันต้องตรวจสอบ makefile ปัจจุบันและการขยาย bash เสร็จสมบูรณ์ นามแฝงของฉัน
RockyRoad


4
มันเล็กน้อยเกินไปgrep : Makefileใช่ไหม:
cibercitizen1

คำตอบ:


130

นี่เป็นความพยายามที่จะปรับปรุงวิธีการที่ยอดเยี่ยมของ @ nobarดังต่อไปนี้:

  • ใช้คำสั่งที่มีประสิทธิภาพมากขึ้นเพื่อแยกชื่อเป้าหมายซึ่งหวังว่าจะป้องกันผลบวกปลอมใด ๆ (และกำจัดออกไปโดยไม่จำเป็นsh -c)
  • ไม่กำหนดเป้าหมาย makefile ในไดเร็กทอรีปัจจุบันอย่างสม่ำเสมอ ด้วยความเคารพ makefiles ระบุไว้อย่างชัดเจนด้วย-f <file>
  • ยกเว้นเป้าหมายที่ซ่อนอยู่ - โดยการประชุมนี่เป็นเป้าหมายที่ชื่อเริ่มต้นด้วยตัวอักษรหรือตัวเลข
  • ทำให้ทำกับเป้าหมายปลอมเดียว
  • นำหน้าคำสั่งด้วย@เพื่อป้องกันไม่ให้ถูก echoed ก่อนการเรียกใช้งาน

อยากรู้อยากเห็น GNU makeไม่มีคุณสมบัติสำหรับการแสดงรายการเพียงชื่อของเป้าหมายที่กำหนดไว้ใน makefile -pตัวเลือกที่ผลิตออกที่มีเป้าหมายทั้งหมด แต่ฝังไว้ในข้อมูลจำนวนมากอื่น ๆ

วางกฎต่อไปนี้ใน makefile สำหรับ GNU makeเพื่อใช้งานเป้าหมายที่มีชื่อlistซึ่งแสดงรายชื่อเป้าหมายทั้งหมดตามลำดับตัวอักษร - เช่น: เรียกใช้เป็นmake list :

.PHONY: list
list:
    @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'

สำคัญ : ในการวางสิ่งนี้ตรวจสอบให้แน่ใจว่าบรรทัดสุดท้ายมีการย่อหน้าโดยแท็บที่แท้จริง 1 แท็บ (พื้นที่ไม่ได้ทำงาน)

โปรดทราบว่าการเรียงลำดับรายการที่เกิดจากเป้าหมายเป็นตัวเลือกที่ดีที่สุดเนื่องจากไม่ได้เรียงลำดับไม่ก่อให้เกิดประโยชน์ในการสั่งซื้อที่ลำดับที่เป้าหมายปรากฏใน Makefile จะไม่ได้เก็บรักษาไว้
นอกจากนี้เป้าหมายย่อยของกฎที่ประกอบด้วยหลายเป้าหมายจะถูกส่งออกแยกกันอย่างสม่ำเสมอดังนั้นจะเกิดจากการเรียงลำดับซึ่งมักจะไม่ปรากฏถัดจากกันและกัน เช่นกฎที่ขึ้นต้นด้วยa z:จะไม่มีเป้าหมายaและzแสดงไว้ข้างๆกันในผลลัพธ์หากมีเป้าหมายเพิ่มเติม

คำอธิบายของกฎ :

  • .PHONY: list
    • ประกาศรายชื่อเป้าหมายเป้าหมายปลอมเช่นที่ไม่ได้อ้างถึงไฟล์ซึ่งควรมีสูตรที่เรียกใช้โดยไม่มีเงื่อนไข
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • เรียกใช้makeอีกครั้งเพื่อพิมพ์และแยกฐานข้อมูลที่ได้มาจาก makefile:
      • -p พิมพ์ฐานข้อมูล
      • -Rr ไม่รวมกฎและตัวแปรในตัว
      • -qทดสอบเฉพาะสถานะล่าสุดของเป้าหมาย (โดยไม่ต้องทำอะไรใหม่) แต่ด้วยตัวเองไม่ได้ป้องกันการเรียกใช้คำสั่งสูตรในทุกกรณี ด้วยเหตุนี้:
      • -f $(lastword $(MAKEFILE_LIST))เพื่อให้แน่ใจว่า Makefile -f ...เดียวกันมีการกำหนดเป้าหมายในขณะที่ภาวนาเดิมไม่ว่าจะเป็นเป้าหมายโดยปริยายหรืออย่างชัดเจนด้วย
        Caveat : สิ่งนี้จะพังถ้า makefile ของคุณมีincludeคำสั่ง; เพื่อระบุสิ่งนี้ให้นิยามตัวแปรTHIS_FILE := $(lastword $(MAKEFILE_LIST)) ก่อนincludeคำสั่งใด ๆและใช้-f $(THIS_FILE)แทน
      • :เป็นเป้าหมายที่ไม่ถูกต้องจงใจที่มีขึ้นเพื่อให้แน่ใจว่าไม่มีคำสั่งจะถูกดำเนินการ ; 2>/dev/nullไม่แสดงข้อความแสดงข้อผิดพลาด หมายเหตุ: สิ่งนี้อาศัย-pการพิมพ์ฐานข้อมูลอย่างไรก็ตามซึ่งเป็นกรณีที่ GNU สร้าง 3.82 เศร้า GNU ทำให้มีตัวเลือกไม่ตรงไปเพียงแค่พิมพ์ฐานข้อมูลโดยไม่ต้องนอกจากนี้ยังมีการดำเนินการเริ่มต้น (หรือให้) งาน; หากคุณไม่ต้องการกำหนดเป้าหมาย Makefile เฉพาะคุณอาจใช้make -p -f/dev/nullตามที่แนะนำในmanหน้า
  • -v RS=

    • นี่เป็นสำนวน awk ที่แบ่งอินพุตเป็นบล็อกของบรรทัดที่ไม่ต่อเนื่องกัน
  • /^# File/,/^# Finished Make data base/
    • จับคู่ช่วงของบรรทัดในเอาต์พุตที่มีเป้าหมายทั้งหมด (เป็นจริงของ GNU ทำ 3.82) - โดย จำกัด การแยกวิเคราะห์ในช่วงนี้ไม่จำเป็นต้องจัดการกับผลบวกปลอมจากส่วนเอาต์พุตอื่น ๆ
  • if ($$1 !~ "^[#.]")
    • เลือกละเว้นบล็อก:
      • # ... ละเว้นกลุ่มที่ไม่ใช่เป้าหมายซึ่งบล็อกเริ่มต้นด้วย # Not a target:
      • . ... ละเว้นเป้าหมายพิเศษ
    • บล็อกอื่น ๆ ทั้งหมดควรเริ่มต้นด้วยบรรทัดที่มีเฉพาะชื่อของเป้าหมายที่กำหนดไว้อย่างชัดเจนตามด้วย :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' ลบเป้าหมายที่ไม่ต้องการออกจากผลลัพธ์:
    • '^[^[:alnum:]]'... ไม่รวมเป้าหมายที่ซ่อนอยู่ซึ่งโดยการประชุมจะเป็นเป้าหมายที่เริ่มต้นด้วยตัวอักษรหรือตัวเลข
    • '^$@$$'... ไม่รวมlistเป้าหมาย

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


นี่เป็นคำตอบที่ดี แต่ฉันจะขอคำอธิบายสำหรับแต่ละงานได้อย่างไร ขณะนี้ฉันกำลังจัดเก็บเป็นความคิดเห็นด้านบนคำจำกัดความงาน ไม่แน่ใจว่าถ้าเป็นไปได้ที่จะรวมไว้ในรายการในลักษณะที่คล้ายกันเป็นrake --tasksไม่ได้หรือไม่
Piotr Kuczynski

1
@PiotrKuczynski: คำถามที่น่าสนใจ แต่ฉันขอแนะนำให้คุณโพสต์เป็นคำถามใหม่ (ชี้ไปที่การอ้างอิงนี้)
mklement0

"น่าเศร้าที่ GNU ทำข้อเสนอไม่มีตัวเลือกโดยตรงเพียงพิมพ์ฐานข้อมูล" มี-nตัวเลือกคือ
Bulletmagnet

@Bulletmagnet: วัตถุประสงค์ของ-nตัวเลือกนี้คือ "พิมพ์คำสั่งที่จะถูกดำเนินการ ... " - อีกนัยหนึ่งคือคุณลักษณะแบบเรียกใช้แบบแห้ง ไม่ใช่ว่าคำพูดของคุณไม่มีตัวเอียงของคำเพียง : make -pโดยตัวมันเองจะพิมพ์ฐานข้อมูล แต่ยังคงทำงานเริ่มต้นเสมอ ; คู่มือแนะนำ clunky make -p -f/dev/nullเพื่อหลีกเลี่ยงปัญหานั้น
mklement0

1
จะแสดงรายการเป้าหมาย. PHONY ใด ๆ ดังนั้นโปรดตรวจสอบให้แน่ใจว่าคุณไม่มี.PHONY: *
tekumara

189

ภายใต้ Bash (อย่างน้อย) สิ่งนี้สามารถทำได้โดยอัตโนมัติด้วยการเติมแท็บ:

make spacetabtab


1
ทดสอบแล้ว: bash --version = 4.2.45 (1) - ปล่อย make --version = 3.81
nobar

53
+1 แต่ทราบว่านี้ไม่ได้เป็นทุบตีคุณลักษณะ แต่ขึ้นอยู่กับคุณแพลตฟอร์ม แพลตฟอร์มแบ่งออกเป็นสามประเภท: ผู้ที่ติดตั้งความสำเร็จนี้เป็นค่าเริ่มต้น (เช่น Debian 7, Fedora 20), ที่ที่คุณสามารถเลือกติดตั้งได้ (เช่น Ubuntu 14, พร้อม. /etc/bash_completion) และผู้ที่ไม่สนับสนุนเลย (เช่น OSX 10.9)
mklement0

8
มันทำงานบน OS X 10.10 (ไม่ใช่กับ bash แต่ใช้ zsh)
Florian Oswald

4
เคล็ดลับที่ดี แต่ยังต้องการbash-completionแพคเกจ พบได้ใน Fedora, RHEL, Gentoo, ect
NoelProf

4
สิ่งนี้ใช้ไม่ได้กับ AFAICT ที่สร้างโดยทางโปรแกรมเช่น$(RUN_TARGETS): run-%: ...
Matthias

31

สิ่งนี้เห็นได้ชัดว่าใช้งานไม่ได้ในหลายกรณี แต่ถ้าคุณMakefileสร้างโดย CMake คุณอาจสามารถเรียกใช้งานmake helpได้

$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... install
etc

คุณมีตัวเลือกใดบ้างที่จะเปิดใน CMakeList ของคุณเพื่อรับสิ่งนั้น ฉันได้รับ makefile ที่สร้างโดย CMake และฉันไม่มีเป้าหมายช่วยเหลือหลอกที่มีอยู่
Xavier T.

Nope อย่างน้อยใน OSX ด้วย CMake ล่าสุด (ฉันใช้ nightlies จริง ๆ แต่ฉันเชื่อว่าเมื่อฉันเขียนสิ่งนี้ฉันใช้ 3.3) เพียงแค่เรียกใช้touch CMakeLists.txt && cmake . && make helpและควรใช้งานได้ ฉันเดาได้แค่ว่าคุณใช้ cmake โบราณหรือไม่ใช้เครื่องกำเนิด Unix Makefiles?
Timmmm

ฉันใช้ CMake 3.6.2 กับตัวสร้าง unix บน Windows ฉันจะขุดไปหาคำอธิบายเพราะมันดูเป็นประโยชน์
ซาเวียร์ต.

26

ฉันรวมคำตอบสองคำนี้: https://stackoverflow.com/a/9524878/86967และhttps://stackoverflow.com/a/7390874/86967 และได้หลบหนีบ้างเพื่อให้สามารถใช้จากภายใน makefile ได้

.PHONY: no_targets__ list
no_targets__:
list:
    sh -c "$(MAKE) -p no_targets__ | awk -F':' '/^[a-zA-Z0-9][^\$$#\/\\t=]*:([^=]|$$)/ {split(\$$1,A,/ /);for(i in A)print A[i]}' | grep -v '__\$$' | sort"

.

$ make -s list
build
clean
default
distclean
doc
fresh
install
list
makefile ## this is kind of extraneous, but whatever...
run

10
ฉันได้ค้นพบว่าการทำแท็บเสร็จสมบูรณ์ภายใต้ Bash จะแสดงรายการเป้าหมายที่มี
nobar

1
+1 สำหรับแนวทางที่ยอดเยี่ยม แต่อาจมีการปรับปรุงเล็กน้อย: (ก) การระบุอย่างชัดเจนsh -c "…"นั้นไม่จำเป็นเนื่องจากเป็นmakeค่าเริ่มต้นที่ใช้เรียกคำสั่งสูตร (b) คำสั่งที่คุณใช้นั้นง่ายเกินไปทำให้เกิดผลบวกปลอม (ดังที่คุณทราบ) (c) หากคุณนำหน้าคำสั่งด้วยคำสั่ง@นั้นจะไม่ถูกสะท้อนไปยัง stdout ก่อนที่จะดำเนินการโดยไม่จำเป็นต้องใช้-sในการเรียกใช้
mklement0

1
มีเป้าหมายทำให้ง่ายขึ้นมากที่คุณสามารถเพิ่ม: list: cat Makefile | grep "^ [Az]" | awk '{พิมพ์ $$ 1}' | sed "s /: // g | sort"
thamster

2
วิธีการ cat / sed ล้มเหลวในหลายระดับ มันไม่ได้ขยายตัวแปรและยังไม่สามารถระบุเป้าหมายที่เป็นผลมาจากการรวมไฟล์อื่น ๆ
ทรอยแดเนียลส์

1
@ mklement0: ฉันชอบที่จะใช้make -s(ผ่านนามแฝงทุบตี) มากกว่า prefixing คำสั่งใน Makefile @ด้วย มีบางกรณีที่@อาจมีประโยชน์โดยเฉพาะอย่างยิ่งในฐานะเป็นคำนำหน้าสำหรับechoคำสั่ง (ที่การแสดงคำสั่งจะซ้ำซ้อน) แต่โดยทั่วไปฉันไม่ต้องการใช้ ด้วยวิธีนี้ฉันสามารถเห็น "สูตรอาหาร" เมื่อฉันต้องการ (โดยไม่ได้ใช้-s) แต่โดยทั่วไปไม่ได้ นี่คือเอกสารที่เกี่ยวข้อง: GNU ทำให้ Manual, 5.2 สูตรสะท้อน
สูงศักดิ์

14

หากคุณมีเสร็จสิ้นการทุบตีสำหรับการติดตั้งสคริปต์เสร็จสิ้นจะกำหนดฟังก์ชั่นmake _make_target_extract_scriptฟังก์ชั่นนี้มีวัตถุประสงค์เพื่อสร้างsedสคริปต์ที่สามารถใช้เพื่อให้ได้เป้าหมายเป็นรายการ

ใช้แบบนี้:

# Make sure bash completion is enabled
source /etc/bash_completion 

# List targets from Makefile
sed -nrf <(_make_target_extract_script --) Makefile

3
มีประโยชน์ แต่โปรดทราบว่าไม่ใช่ทุกแพลตฟอร์มที่มีสคริปต์/etc/bash_completionและ / หรือฟังก์ชั่น_make_target_extract_script- ดูเหมือนว่าคุณจะอยู่บน Ubuntu> 12 หากคุณกำหนดเป้าหมาย/usr/share/bash-completion/completions/makeแทนแนวทางของคุณจะทำงานบนแพลตฟอร์มเพิ่มเติมเช่น Fedora 20 มีแพลตฟอร์มที่เก่ากว่า ไฟล์นี้ แต่ไม่ใช่ฟังก์ชั่น (เช่น Debian 7 และ Ubuntu 12); แพลตฟอร์มอื่น ๆ เช่น OSX ไม่ได้มาด้วยความสมบูรณ์แท็บmakeที่ทั้งหมด บางทีการโพสต์นิยามฟังก์ชันที่แท้จริงอาจเป็นประโยชน์
mklement0

1
ขอบคุณสำหรับความคิดเห็นของคุณ นี่คือความนิยมมาก ใช่ฉันได้ทดสอบสิ่งนี้บน Ubuntu 14.04
hek2mgl

11

เมื่อmklement0 ชี้ให้เห็นคุณลักษณะสำหรับการแสดงรายการเป้าหมาย Makefile ทั้งหมดหายไปจาก GNU-make และคำตอบของเขาและอื่น ๆ มีวิธีในการทำเช่นนี้

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

หากคุณต้องการเลียนแบบพฤติกรรมของ rake ที่คุณให้คำอธิบายสำหรับแต่ละเป้าหมายมีเทคนิคง่าย ๆ สำหรับการทำสิ่งนี้: ฝังคำอธิบายในข้อคิดเห็นสำหรับแต่ละเป้าหมายที่คุณต้องการแสดง

คุณสามารถใส่คำอธิบายถัดจากเป้าหมายหรือตามที่ฉันทำบ่อยๆถัดจากสเปค PHONY เหนือเป้าหมายเช่นนี้:

.PHONY: target1 # Target 1 help text
target1: deps
    [... target 1 build commands]

.PHONY: target2 # Target 2 help text
target2:
    [... target 2 build commands]

...                                                                                                         

.PHONY: help # Generate list of targets with descriptions                                                                
help:                                                                                                                    
    @grep '^.PHONY: .* #' Makefile | sed 's/\.PHONY: \(.*\) # \(.*\)/\1 \2/' | expand -t20

ซึ่งจะให้ผลผลิต

$ make help
target1             Target 1 help text
target2             Target 2 help text

...
help                Generate list of targets with descriptions

คุณสามารถค้นหาตัวอย่างรหัสย่อในส่วนสำคัญนี้และที่นี่ด้วย

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

อย่างไรก็ตามหากคุณกำลังเขียน Makefile และคุณต้องการวิธีสร้างข้อความช่วยเหลือด้วยวิธีการจัดทำเอกสารด้วยตนเองที่สอดคล้องกันเทคนิคนี้อาจมีประโยชน์


นี่เป็นเทคนิคที่ยอดเยี่ยม - ดีและเรียบง่าย แต่ให้คำอธิบายด้วย!
Brian Burns

เทคนิคที่ยอดเยี่ยม ฉันแก้ไขบิตนี้เพื่อใช้echoคำสั่งเป็นคำอธิบายคำสั่ง ( stackoverflow.com/a/52059487/814145 )
Penghe Geng

@PengheGeng ขอบคุณสำหรับการโพสต์ ฉันต้องการทำให้ชัดเจน@echo "Target 1"เป็นเพียงตัวยึดตำแหน่งและไม่ใช่ "คำอธิบาย echo คำสั่ง" ข้อความช่วยเหลือที่สร้างขึ้นไม่ได้มาจาก@echoของ ใน Makefile จริงสิ่งเหล่านี้echoจะถูกแทนที่ด้วยคำสั่ง build หรือบางอย่าง ฉันจะแก้ไขโพสต์เพื่อให้ชัดเจนยิ่งขึ้น
jsp

4

@ nobar ของคำตอบที่แสดงให้เห็นว่าเป็นประโยชน์กับวิธีการใช้แท็บเสร็จสิ้นการลงรายการเป้าหมาย Makefile ของ

  • สิ่งนี้ใช้งานได้ดีสำหรับแพลตฟอร์มที่ให้ฟังก์ชันการทำงานนี้เป็นค่าเริ่มต้น (เช่นDebian, Fedora )

  • บนแพลตฟอร์มอื่น ๆ (เช่นUbuntu ) คุณต้องโหลดการทำงานนี้อย่างชัดเจนตามที่ระบุโดยคำตอบของ @ hek2mgl :

    • . /etc/bash_completion ติดตั้งฟังก์ชั่นการเติมแท็บหลายรายการรวมถึงฟังก์ชันสำหรับ make
    • อีกวิธีหนึ่งในการติดตั้งเฉพาะแท็บเสร็จสมบูรณ์สำหรับmake:
      • . /usr/share/bash-completion/completions/make
  • สำหรับแพลตฟอร์มที่ไม่มีฟังก์ชั่นนี้เลยเช่นOSXคุณสามารถระบุคำสั่งต่อไปนี้ (ปรับจากที่นี่ ) เพื่อนำไปใช้งาน:
_complete_make() { COMPREPLY=($(compgen -W "$(make -pRrq : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}' | egrep -v '^[^[:alnum:]]' | sort | xargs)" -- "${COMP_WORDS[$COMP_CWORD]}")); }
complete -F _complete_make make
  • หมายเหตุ: นี่คือไม่ซับซ้อนเช่นการทำงานของแท็บเสร็จที่มาพร้อมกับลินุกซ์: สะดุดตาที่สุดก็คงเส้นคงวาเป้าหมาย Makefile ในที่ปัจจุบันไดเรกทอรีแม้ว่าคำสั่งเป้าหมายบรรทัด Makefile -f <file>แตกต่างกันด้วย

4

คำตอบที่ฉันชอบมากที่สุดคือโพสต์โดยChris Downที่ Unix & Linux Stack Exchange ฉันจะพูด

นี่คือวิธีที่โมดูล bash เสร็จสิ้นสำหรับmakeรับรายการ:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}'

มันพิมพ์รายการเป้าหมายที่คั่นด้วย newline โดยไม่ต้องเพจจิ้ง

ผู้ใช้Brainstoneแนะนำให้ไปที่ piping sort -uเพื่อลบรายการที่ซ้ำกัน:

make -qp | awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ {split($1,A,/ /);for(i in A)print A[i]}' | sort -u

ที่มา: วิธีแสดงรายการเป้าหมายทั้งหมดในการสร้าง (Unix & Linux SE)


4

มุ่งเน้นไปที่ไวยากรณ์ที่ง่ายสำหรับการอธิบายเป้าหมายการผลิตและการมีผลลัพธ์ที่สะอาดฉันเลือกวิธีนี้:

help:
    @grep -B1 -E "^[a-zA-Z0-9_-]+\:([^\=]|$$)" Makefile \
     | grep -v -- -- \
     | sed 'N;s/\n/###/' \
     | sed -n 's/^#: \(.*\)###\(.*\):.*/\2###\1/p' \
     | column -t  -s '###'


#: Starts the container stack
up: a b
  command

#: Pulls in new container images
pull: c d 
    another command

make-target-not-shown:

# this does not count as a description, so leaving
# your implementation comments alone, e.g TODOs
also-not-shown:

ดังนั้นการปฏิบัติตามข้างต้นในฐานะ Makefile และการเรียกใช้มันให้สิ่งที่คุณต้องการ

> make help
up          Starts the container stack
pull        Pulls in new container images

คำอธิบายสำหรับ chain of command:

  • ครั้งแรก grep เป้าหมายทั้งหมดและสาย preceeding ของพวกเขาดูhttps://unix.stackexchange.com/a/320709/223029
  • จากนั้นได้รับการกำจัดแยกกลุ่มให้ดูhttps://stackoverflow.com/a/2168139/1242922
  • จากนั้นเราจะยุบคู่ของแต่ละบรรทัดที่จะแยกได้ในภายหลังดูhttps://stackoverflow.com/a/9605559/1242922
  • จากนั้นเราแยกวิเคราะห์บรรทัดที่ถูกต้องและลบบรรทัดที่ไม่ตรงกันดูhttps://stackoverflow.com/a/8255627/1242922และให้ผลลัพธ์ตามลำดับที่เราต้องการ: คำสั่งจากนั้นอธิบาย
  • สุดท้ายเราจัดการผลลัพธ์เช่นตาราง

ทางออกที่ดีมาก ฉันใช้สิ่งนี้มาสองสามปีแล้ว: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort กับ##ความคิดเห็นก่อนหน้าในบรรทัดเดียวกับเป้าหมาย แต่ฉันคิดว่าโซลูชันของคุณจะช่วยให้สามารถอ่านได้ก่อน
thoroc

makefile ประกอบด้วยรายงานสองบรรทัดแรกgrep: parentheses not balancedบนเครื่อง OSX 10.15 ของฉัน
Malcolm Crum

@ Crummy ขออภัยความผิดพลาดของฉัน ขอบคุณที่ชี้นำ ซ่อมมัน. make จำเป็นต้องหลีกเลี่ยงสัญญาณดอลลาร์ที่ไม่ควรเริ่มชื่อตัวแปร
Richard Kiefer

ระวัง StackOverflow แปลงแท็บเป็นช่องว่างเมื่อแสดงส่วนของรหัสด้านบน แต่ Makefiles จำเป็นต้องใช้แท็บ คุณสามารถแก้ไขโพสต์แล้วคัดลอกส่วนต่างๆได้ดังนั้นแท็บจะยังคงอยู่
Richard Kiefer

2

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

ฉันไม่ได้ทดสอบด้านล่างด้วย sub-make ... ฉันคิดว่ามันจะไม่ทำงาน อย่างที่เราทราบกันว่าการเรียกซ้ำทำให้เกิดอันตราย

.PHONY: list ls
ls list :
    @# search all include files for targets.
    @# ... excluding special targets, and output dynamic rule definitions unresolved.
    @for inc in $(MAKEFILE_LIST); do \
    echo ' =' $$inc '= '; \
    grep -Eo '^[^\.#[:blank:]]+.*:.*' $$inc | grep -v ':=' | \
    cut -f 1 | sort | sed 's/.*/  &/' | sed -n 's/:.*$$//p' | \
    tr $$ \\\ | tr $(open_paren) % | tr $(close_paren) % \
; done

# to get around escaping limitations:
open_paren := \(
close_paren := \)

ซึ่งฉันชอบเพราะ:

  • รายการเป้าหมายโดยรวมไฟล์
  • เอาต์พุตนิยามเป้าหมายแบบไดนามิกดิบ (แทนที่ตัวคั่นตัวแปรด้วยโมดูโล)
  • เอาต์พุตแต่ละเป้าหมายบนบรรทัดใหม่
  • ดูเหมือนชัดเจน (ความคิดเห็นส่วนตัว)

คำอธิบาย:

  • ไฟล์ foreach ใน MAKEFILE_LIST
  • เอาท์พุทชื่อของไฟล์
  • บรรทัด grep ที่มีเครื่องหมายโคลอนซึ่งไม่ได้เยื้องไม่ใช่ความคิดเห็นและไม่ขึ้นต้นด้วยจุด
  • ไม่รวมการแสดงออกที่ได้รับมอบหมายทันที (: =)
  • ตัดเรียงลำดับเยื้องและสับการพึ่งพากฎ (หลังโคลอน)
  • ตัวคั่นตัวแปร munge เพื่อป้องกันการขยายตัว

ตัวอย่างผลลัพธ์:

 = Makefile = 
  includes
  ls list
 = util/kiss/snapshots.mk = 
  rotate-db-snapshots
  rotate-file-snapshots
  snap-db
  snap-files
  snapshot
 = util/kiss/main.mk = 
  dirs
  install
   %MK_DIR_PREFIX%env-config.php
   %MK_DIR_PREFIX%../srdb

1

อันนี้มีประโยชน์กับฉันเพราะฉันต้องการเห็นเป้าหมายการสร้างที่ต้องการ (และการอ้างอิง) โดยเป้าหมายทำให้ ฉันรู้ว่าการสร้างเป้าหมายไม่สามารถเริ่มต้นด้วย "" ตัวละคร ฉันไม่รู้ว่ารองรับภาษาใดฉันจึงไปกับการแสดงออกวงเล็บของ egrep

cat Makefile | egrep "^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$"

1

สิ่งนี้อยู่ไกลจากความสะอาด แต่ทำเพื่อฉัน

make -p 2&>/dev/null | grep -A 100000 "# Files" | grep -v "^$" | grep -v "^\(\s\|#\|\.\)" | grep -v "Makefile:" | cut -d ":" -f 1

ฉันใช้make -pที่ทิ้งฐานข้อมูลภายในคู stderr ใช้อย่างรวดเร็วและสกปรกgrep -A 100000เพื่อให้ด้านล่างของผลลัพธ์ จากนั้นฉันทำความสะอาดผลลัพธ์ด้วยสองสามgrep -vครั้งและในที่สุดก็ใช้cutเพื่อรับสิ่งที่อยู่ข้างหน้าลำไส้ใหญ่นั่นคือเป้าหมาย

นี่ก็เพียงพอแล้วสำหรับสคริปต์ผู้ช่วยของฉันใน Makefiles ส่วนใหญ่ของฉัน

แก้ไข: เพิ่มgrep -v Makefileที่เป็นกฎภายใน


1

นี่คือการแก้ไขคำตอบที่เป็นประโยชน์ของjsp ( https://stackoverflow.com/a/45843594/814145 ) ฉันชอบความคิดในการได้รับไม่เพียง แต่รายการเป้าหมาย แต่ยังรวมถึงคำอธิบายของพวกเขา Makefile ของjspทำให้คำอธิบายเป็นความคิดเห็นซึ่งฉันพบบ่อยจะซ้ำในคำสั่ง echo คำอธิบายของเป้าหมาย ดังนั้นฉันจะแยกคำอธิบายจากคำสั่ง echo สำหรับแต่ละเป้าหมาย

ตัวอย่าง Makefile:

.PHONY: all
all: build
        : "same as 'make build'"

.PHONY: build
build:
        @echo "Build the project"

.PHONY: clean
clean:
        @echo "Clean the project"

.PHONY: help
help:
        @echo -n "Common make targets"
        @echo ":"
        @cat Makefile | sed -n '/^\.PHONY: / h; /\(^\t@*echo\|^\t:\)/ {H; x; /PHONY/ s/.PHONY: \(.*\)\n.*"\(.*\)"/    make \1\t\2/p; d; x}'| sort -k2,2 |expand -t 20

ผลลัพธ์ของmake help:

$ make help
Common make targets:
    make all        same as 'make build'
    make build      Build the project
    make clean      Clean the project
    make help       Common make targets

หมายเหตุ:

  • เช่นเดียวกับคำตอบของjspเฉพาะเป้าหมายของ PHONY เท่านั้นที่จะแสดงรายการซึ่งอาจหรืออาจไม่เหมาะกับกรณีของคุณ
  • นอกจากนี้จะแสดงรายการเป้าหมาย PHONY เหล่านั้นที่มีechoหรือ:คำสั่งเป็นคำสั่งแรกของสูตรเท่านั้น :แปลว่า "ไม่ทำอะไรเลย" ฉันใช้ที่นี่สำหรับเป้าหมายที่ไม่จำเป็นต้องใช้เสียงสะท้อนเช่นallเป้าหมายด้านบน
  • มีเคล็ดลับเพิ่มเติมสำหรับhelpเป้าหมายในการเพิ่ม ":" ในmake helpเอาต์พุต

0

อีกคำตอบเพิ่มเติมข้างต้น

ทดสอบบน MacOSX โดยใช้ cat และ awk บนเทอร์มินัลเท่านั้น

cat Makefile | awk '!/SHELL/ && /^[A-z]/ {print $1}' | awk '{print substr($0, 1, length($0)-1)}'

จะส่งออกของไฟล์ทำเหมือนด้านล่าง:

target1

target2

target3

ใน Makefile ควรเป็นคำสั่งเดียวกันตรวจสอบให้แน่ใจว่าคุณได้หลีกเลี่ยงตัวแปรโดยใช้ตัวแปร $$ แทนที่จะเป็น $ variable

คำอธิบาย

แมว - คายเนื้อหา

| - ไปป์แยกวิเคราะห์เอาต์พุตไปที่ awk ถัดไป

awk - รัน regex ยกเว้น "shell" และยอมรับเฉพาะบรรทัด "Az" จากนั้นพิมพ์คอลัมน์แรก $ 1

awk - ลบอักขระตัวสุดท้าย ":" ออกจากรายการอีกครั้ง

นี่เป็นผลลัพธ์คร่าวๆและคุณสามารถทำสิ่งที่ขี้ขลาดมากขึ้นด้วย AWK พยายามหลีกเลี่ยงการใช้งานเนื่องจากไม่สอดคล้องกันในสายพันธุ์ BSD เช่นทำงานบน * ระวัง แต่ล้มเหลวใน BSD เช่น MacOSX

มากกว่า

คุณควรจะสามารถเพิ่มสิ่งนี้ (ด้วยการแก้ไข) ลงในไฟล์สำหรับสร้างลงในโฟลเดอร์ทุบตีเริ่มต้น /usr/local/etc/bash-completion.d/ ความหมายเมื่อคุณ "สร้างแท็บแท็บ " .. มันจะเสร็จสมบูรณ์ เป้าหมายขึ้นอยู่กับสคริปต์ liner หนึ่งรายการ


คุณยังสามารถใช้ make -qp แทนที่จะเป็น cat ดังนั้นมันจะกลายเป็น make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / DISPLAY / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&&! / Makefile / {พิมพ์ย่อย ($ 0, 1 ความยาว ($ 0) -1) "sort -u"} '
จิมมี่ MG Lim

0

ฉันมักจะทำ:

grep install_targets Makefile

มันจะกลับมาพร้อมกับสิ่งที่ชอบ:

install_targets = install-xxx1 install-xxx2 ... etc

ฉันหวังว่านี่จะช่วยได้


0

สำหรับ Bash Script

นี่เป็นวิธีที่ง่ายมากในการทำbashตามความคิดเห็นโดย @ cibercitizen1 ด้านบน :

grep : Makefile | awk -F: '/^[^.]/ {print $1;}'

ดูคำตอบที่เชื่อถือได้มากขึ้นโดย @ Marc.2377 ด้วยเช่นกันซึ่งระบุว่าโมดูล Bash completion makeทำอย่างไร


-4

ไม่แน่ใจว่าทำไมคำตอบก่อนหน้านี้จึงซับซ้อน:

list:
    cat Makefile | grep "^[A-z]" | awk '{print $$1}' | sed "s/://g" 

8
คำตอบก่อนหน้ามีความซับซ้อนเช่นนั้นเพราะมันครอบคลุมทุกสถานการณ์ว่าคำตอบของคุณไม่ครอบคลุมถึง: (ก) การรวมของเป้าหมายที่กำหนดไว้ผ่านทางตัวแปร (เช่น$(SHELLS): ...), (ข) การรวมของเป้าหมายที่เริ่มต้นด้วยตัวเลข (ค) ไม่ใช่ รวมของคำจำกัดความตัวแปร (d) กำหนดเป้าหมาย makefile ที่เหมาะสมหากmakeระบุด้วยพา ธ makefile อย่างชัดเจน (a) เป็นข้อบกพร่องที่สำคัญ: แม้ว่าคุณจะกำหนดเป้าหมายไฟล์ที่ถูกต้องได้อย่างแม่นยำแต่การแยกไฟล์ดิบจะไม่ทำงานในกรณีทั่วไปเนื่องจากขาดการขยายตัวของตัวแปร
mklement0

6
เช่นกันอีกครั้งซับซ้อน: คำสั่งของคุณได้ง่ายต่อไปนี้ - แต่ประเด็นหลักก็คือว่ามันพอที่จะไม่แข็งแกร่งawk -F: '/^[A-z]/ {print $$1}' Makefile : สุดท้ายเป็นจุดที่นักวิชาการส่วนใหญ่: การใช้[A-z]มากกว่าหมายความว่าคุณจะพลาดเป้าหมายที่ขึ้นต้นด้วยตัวอักษรต่างประเทศเช่น[:alpha:] á
mklement0

@ mklement0 คำสั่ง awk แรกของคุณทำงานได้ดีและเป็นวิธีที่ง่ายที่สุดแม้ว่าการใช้ [: alpha:] ดูเหมือนว่าจะทำลายด้วยเหตุผลบางประการ - มันพลาดเป้าหมายบางอย่างในไฟล์ทดสอบ
Brian Burns

@ bburns.km: ไม่ดีของฉัน: ฉันควรจะพูด[[:alpha:]]มากกว่า[:alpha:]( [:alpha:]หมายถึงชุดของตัวอักษรที่ตระหนักถึงสถานที่ภายในคลาสตัวอักษร ( [...]) ดังนั้นความต้องการที่มีประสิทธิภาพสำหรับคู่ [[ / ]].
mklement0

4
ทำไมคำตอบนี้จึงซับซ้อน? คุณสามารถรวบรวมบาปที่ไร้ประโยชน์หลายอย่างในตัวอย่างสั้น ๆ นี้ awk -F: '/^[A-Za-z]/ { print $$1 }' Makefileใช้กระบวนการเดียวและหวังว่านิพจน์ปกติที่ถูกต้องมากขึ้น (แน่นอนว่าคุณสามารถมีเป้าหมายที่มีเครื่องหมายขีดล่างตัวเลข ฯลฯ เช่นเดียวกับที่ระบุไว้ในความคิดเห็นก่อนหน้านี้)
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.