แสดงรายการเป้าหมาย / เป้าหมายใน GNU ที่มีตัวแปรในนิยาม


100

ฉันมี makefile ขนาดใหญ่พอสมควรที่สร้างเป้าหมายจำนวนมากได้ทันทีโดยคำนวณชื่อจากตัวแปร (เช่น foo $ (VAR): $ (PREREQS)) มีวิธีใดบ้างที่ทำให้ gnu สามารถมั่นใจได้ว่าจะพ่นรายการเป้าหมายออกมาหลังจากขยายตัวแปรเหล่านี้แล้ว?

ฉันต้องการที่จะได้รับเป้าหมายสำหรับ makefile aribitrary ฉันกำลังพยายามเขียนฟังก์ชันที่สมบูรณ์สำหรับเชลล์ของฉัน

คำตอบ:


79

คุณสามารถแยกวิเคราะห์ผลลัพธ์จากmake -pn(เช่นmake --print-data-base --dry-run) ได้หรือไม่? มันพิมพ์ตัวแปรกฎกฎโดยนัยและคำสั่งใดที่จะรันโดยละเอียด


คำตอบนี้ดูดีกว่าคำตอบอื่น ๆ มาก
Matt Joiner

ฉันยอมรับว่านี่ดีกว่ามาก ยังคงทำงานได้มากกว่าที่ฉันหวังไว้ แต่ฉันจะทำเครื่องหมายว่าเป็นคำตอบเนื่องจากไม่มีอะไรอื่นที่ดูเหมือนจะสมเหตุสมผลและ GNU ก็ไม่มีธงที่สะดวกสำหรับสิ่งที่ฉันต้องการ
BitShifter

6
โปรดทราบว่าผลลัพธ์อาจขึ้นอยู่กับเป้าหมายที่คุณระบุหาก Makefile ของคุณสร้างเป้าหมายแบบไดนามิก ผลลัพธ์อาจขึ้นอยู่กับค่าของตัวแปรสภาพแวดล้อมหรือสร้างตัวแปรที่ระบุด้วยคำสั่ง make
Reinierpost

6
ฉันชอบความกะทัดรัด +1 เพิ่มสปินของตัวเอง (อธิบายไว้ในคำตอบด้านล่าง):make -pn | sed -rn '/^[^# \t\.%].*:[^=]?/p'
Jamie

แนะนำmake -pnr. -rเอากฎโดยปริยาย
sjbx

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

นำมาจากการทำให้เสร็จสมบูรณ์ซึ่งทำงานได้อย่างมีเสน่ห์


2
ฉันพยายามสร้างนามแฝงสำหรับสิ่งนี้ใส่ไว้ในเครื่องหมายคำพูดคู่ แต่ส่งผลให้ awk มีข้อผิดพลาดทางไวยากรณ์ในเครื่องหมายจุลภาคแรก ...
drfrogsplat

3
ฉันคิดว่ามันเกี่ยวข้องกับสิ่งที่กำหนดไว้ ฉันคิดว่าถ้ากำหนดเป็นนามแฝงไดเร็กทอรีการทำงานจะกลายเป็นไดเร็กทอรีที่กำหนดไว้และดูเหมือนว่าส่วน awk ไม่ชอบจุดในไดเร็กทอรีที่ซ่อนอยู่ การกำหนดฟังก์ชันทำงาน
อิบราฮิม

ฉันใส่ไว้ในเชลล์สคริปต์~/binแทนที่จะใช้นามแฝง ใช้งานได้ดี ขอบคุณ!
mpontillo

3
นามแฝงalias mkl="make -qp | awk -F':' '/^[a-zA-Z0-9][^\$#\/\t=]*:([^=]|\$)/ {split(\$1,A,/ /);for(i in A)print A[i]}' | sort"ที่จะช่วยให้คุณประหยัดเวลาในการอ้างถึงเกมได้ 2 นาที :-)
Ciro Santilli 郝海东冠状病六四事件法轮功

1
| sort -uดูมีประโยชน์มากขึ้น :)
sherpya

14

ฉันไม่แน่ใจว่านี่เป็นเพียงการสร้าง gnu หรือไม่ แต่ก็ใช้ได้ดี:

make help


สิ่งนี้มีประโยชน์มากและจำได้ง่ายกว่านามแฝงที่กำหนดเองสำหรับวิธีการอื่น ๆ
อิบราฮิม

8
ใช้ GNU Make 3.81 ไม่ได้จริง ๆ อาจเป็นเป้าหมายใน makefiles ของคุณ: "make: *** ไม่มีกฎที่จะทำให้เป้าหมาย` `ช่วย '' หยุด"
a1an

8
นี่เป็นการเรียกใช้เป้าหมาย "help" ใน Makefile ถ้ามีอยู่ก็จะพิมพ์อะไรบางอย่าง (ไม่สมบูรณ์รายชื่อของเป้าหมาย) ถ้ามันไม่ได้อยู่ (สถานการณ์โดยทั่วไป) ก็จะประกันตัวออกมา
pfalcon

2
ข่าวดีก็คือ cmake ดูเหมือนจะสร้างเป้าหมาย "help" ที่อ่านง่ายดี
Stéphane

นี่มันเจ๋งมาก! :) ไป cmake
Jeef

10

ผู้ตอบหลายคนแนะนำให้ใช้make -pnซึ่งจะพิมพ์ฐานข้อมูลของกฎ แต่ไม่ดำเนินการใด ๆ - ไม่มากก็น้อย ปัญหาของวิธีนี้คือ-nยังคงเรียกใช้การทำซ้ำทั้งหมดและยังทำงานได้มากเกินความจำเป็นเนื่องจากพิมพ์คำสั่งทุกคำสั่งที่จะเรียกใช้ในบิลด์ปกติ วิธีแก้ปัญหาที่มีประสิทธิภาพมากขึ้นคือการสร้าง makefile ที่ไม่สำคัญ dummy.mk ด้วยเนื้อหาเหล่านี้:

__all_targets__: ; #no-op

ตอนนี้เรียกใช้ make as make -p -f Makefile -f dummy.mk __all_targets__. ในการสร้างที่สำคัญใด ๆ ความแตกต่างของจำนวนเอาต์พุตที่สร้างขึ้นจาก make นั้นมีนัยสำคัญ ตัวอย่างเช่น:

$ gmake -pn | wc
 138985 2632330 69612711
$ gmake -f Makefile -f /tmp/dummy.mk -pn __all_targets__ | wc
  21673   93437  878985

เวลาในการดำเนินการก็ดีขึ้นอย่างมากเช่นกัน - 2.063 สำหรับเวอร์ชันแรก 0.059 วินาทีสำหรับรุ่นที่สอง


1
ความคิดที่เรียบร้อยทุกคนที่ทำงานกับระบบสร้างขนาดใหญ่จะต้องประทับใจ สถิติต้นไม้ Android Gingerbread (ไม่ได้ใช้ทำซ้ำเพื่อให้เงินฝากออมทรัพย์ไม่มากเพียงแค่ดี): " time make -pn | wc -l': 1338738 real 0m47.754s.' ":time make -f Makefile -f dummy.mk -pn __all_targets__ | wc -l 938621 real 0m40.219s
pfalcon

จุดดี. หน้าคนสำหรับmakeดูเหมือนจะแนะนำสิ่งที่คล้ายกัน แต่เป็นมิตรคือmake -p -f/dev/null
Davide

@Davide ที่ใช้งานไม่ได้: การระบุ-f /dev/nullจะป้องกันไม่ให้makeแยกวิเคราะห์ makefiles ปกติดังนั้นคุณจะได้รับงานพิมพ์เฉพาะของกฎในตัว -f Makefile -f dummy.mkนั่นเป็นเหตุผลที่ระบุวิธีการแก้ปัญหาของฉัน แต่นั่นยังไม่เพียงพอทั้งเพราะด้วย-n, makeจะไปข้างหน้าและจะเริ่มดำเนินการในกฎ Makefile ได้เป็นอย่างดี น่าเสียดายที่ฉันไม่ทราบถึงการปรับเปลี่ยนใด ๆ ที่สามารถทำให้โซลูชันง่ายขึ้นตามที่นำเสนอในตอนแรก
Eric Melski

คุณคิดถูกแน่นอน อย่างไรก็ตามหน้า make man มีข้อบกพร่องเนื่องจากระบุว่า: "ในการพิมพ์ฐานข้อมูลโดยไม่ต้องพยายามสร้างไฟล์ใหม่ให้ใช้ make -p -f / dev / null"
Davide

แก้ไขเล็กน้อยสำหรับความคิดเห็นก่อนหน้าของฉัน: ควรอ่าน "... เพราะไม่มี -n ... "
Eric Melski


7

แก้ไข: FYI ที่เก็บ git เสร็จสิ้น debian bash ในคำตอบอื่นตอนนี้รวมสคริปต์รุ่นปรับปรุงนี้ที่ปรับแต่งให้เหมาะกับกรณีการใช้งาน bash complete

#!/bin/bash

SCRIPT='
  /^# Make data base/,/^# Files/d             # skip until files section
  /^# Not a target/,+1          d             # following target isnt
  /^\.PHONY:/                   d             # special target
  /^\.SUFFIXES:/                d             # special target
  /^\.DEFAULT:/                 d             # special target
  /^\.PRECIOUS:/                d             # special target
  /^\.INTERMEDIATE:/            d             # special target
  /^\.SECONDARY:/               d             # special target
  /^\.SECONDEXPANSION/          d             # special target
  /^\.DELETE_ON_ERROR:/         d             # special target
  /^\.IGNORE:/                  d             # special target
  /^\.LOW_RESOLUTION_TIME:/     d             # special target
  /^\.SILENT:/                  d             # special target
  /^\.EXPORT_ALL_VARIABLES:/    d             # special target
  /^\.NOTPARALLEL:/             d             # special target
  /^\.ONESHELL:/                d             # special target
  /^\.POSIX:/                   d             # special target
  /^\.NOEXPORT:/                d             # special target
  /^\.MAKE:/                    d             # special target

# The stuff above here describes lines that are not
#  explicit targets or not targets other than special ones
# The stuff below here decides whether an explicit target
#  should be output.

  /^[^#\t:=%]+:([^=]|$)/ {                    # found target block
    h                                         # hold target
    d                                         # delete line
  }
  /^# File is an intermediate prerequisite/ { # nope
    s/^.*$//;x                                # unhold target
    d                                         # delete line
  }
  /^([^#]|$)/ {                               # end of target block
    s/^.*$//;x                                # unhold target
    s/:.*$//p                                 # write current target
    d                                         # hide any bugs
  }
'

make -npq .DEFAULT 2>/dev/null | sed -n -r "$SCRIPT" \
  | sort | uniq

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

นี่ไม่ใช่สคริปต์ดั้งเดิมที่ฉันเชื่อมโยง แต่มันง่ายกว่ามากและสัมผัสได้เร็วกว่า


BTW, mods หากคำตอบนี้ไม่สอดคล้องกับนโยบายทั้งหมดเนื่องจากความแตกต่างเล็กน้อยของข้อความโปรดแสดงความคิดเห็นก่อนลบ ฉันจะทำการปรับเปลี่ยนตามกฎหมายที่จำเป็นเพื่อให้คำถามนี้ได้รับคำตอบที่สมบูรณ์และถูกต้อง
codehot

ในการทดสอบอย่างรวดเร็วฉันคว้าซอร์สโค้ด gcc และรัน. / กำหนดค่า && เวลา ~ / makecomp.sh | wc -l โดยที่ ~ / makecomp.sh คือคำตอบของฉัน ... การส่งออกการกำหนดค่า ... config.status: สร้าง Makefile 3312 จริง 0m0.412s ใช้ 0m0.401s SYS 0m0.028s
codeshot

ในการทดสอบอื่นฉันใช้การสาธิต makefile ที่odeshot.blogspot.co.uk/2012/08/…ซึ่งสร้างกฎหลอกสำหรับการสร้างและตรวจสอบการทดสอบหน่วย ตัวอย่างนี้ใช้คุณสมบัติของ make มากกว่าโปรเจ็กต์ autoconf ข้ามแพลตฟอร์มทั่วไปดังนั้นสคริปต์ในคำตอบนี้จึงส่งคืนเป้าหมายจริง 14 เป้าหมายในขณะที่ bash เสร็จสิ้นสำหรับ make บน ubuntu จะส่งคืนกฎที่มีประโยชน์เพียงสองกฎจากนั้นจึงส่งไฟล์ต้นฉบับ 5 ไฟล์
codehot




2

เดาว่าฉันมางานปาร์ตี้นี้ช้าไปหน่อย แต่ถ้าคุณกำลังมองหาคำสั่งเฉพาะคุณสามารถลองได้

make -qp | grep -v '^# ' | grep -v '^[[:space:]]' | grep --only-matching '^.*:'

วิธีนี้ใช้งานได้เป็นส่วนใหญ่แม้ว่าอาจยังรวมถึงสิ่งที่ไม่ใช่เป้าหมายเช่นvpathคำสั่ง หากคุณไม่ได้ขึ้นอยู่กับmakeกฎในตัวคุณสามารถใช้make -qpRเป็นคำสั่งแรกในไปป์ไลน์


ฉันลองกับ freetz (.org) แสดงรายการ makefiles จำนวนมากและไม่ได้ระบุเป้าหมายทั้งหมด
Robert Siemer


1

ฉันกำลังทำงานกับ solaris 10 anda turbo C shell โซลูชันที่ระบุใช้ไม่ได้กับโปรเจ็กต์ makefile ของฉัน แม้ว่าจะเปลี่ยนบรรทัดคำสั่งด้านบนเป็นไวยากรณ์ tcsh แล้วก็ตาม อย่างไรก็ตามฉันพบว่าคุณสามารถหาวิธีง่ายๆโดยใช้

remake --tasks | grep -v "clean some static output or just grep tabs on start of line" | awk ´{print $1}´

เวอร์ชั่นรีเมค:

remake --version

คือ

GNU Make 3.82+dbg0.8
Built for sparc-sun-sparc2-9

และข้อมูลเวอร์ชันที่ไม่สำคัญอื่น ๆ


0

ฉันมองหาคำถามเดียวกันและคิดเรื่องนี้ขึ้นมา:

make -pn | sed -rn '/^[^# \t\.%].*:/p'

สิ่งนี้จะลบบรรทัดข้อคิดเห็นกฎรูปแบบทั้งหมด (บรรทัดที่ขึ้นต้นด้วยแท็บ) เนื้อแท้ทั้งหมด (ตัวอย่าง.c.oและ%.o: %.cรูปแบบ)


ไม่ได้อ่านความคิดเห็นจากคำตอบที่ยอมรับ: +1 สำหรับคำตอบของแจ็ค ... gist.github.com/777954 - pvandenberk 13 ม.ค. เวลา 14:47 น.
Jamie

0

พบวิธีแก้ปัญหานี้ในหัวข้ออื่น:

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

คุณยังสามารถเพิ่มลงในMakefile:

list:
    sh -c "cat Makefile | egrep \"^[[:alnum:][:punct:]]{0,}:[[:space:]]{0,}[[:alnum:][:punct:][:space:]]{0,}$\\""

make listและดำเนินการ


-1

แน่นอน แต่คุณต้องการให้มันคายออกเมื่อใด

หากต้องการรายงานชื่อของเป้าหมายเมื่อเรียกใช้กฎให้ใส่บรรทัดในกฎ:

foo$(VAR): $(PREREQS)
    @echo now making the foo target: $@
    do_other_stuff...

หากต้องการคายออกมาทั้งหมดในครั้งเดียวคุณสามารถสร้างเป้าหมาย PHONY แยกกันได้:

.PHONY: show_vars
show_vars:
    @echo foo$(VAR)
    @echo bar$(PARAM) blah$(FLAG)
    # and so on

และสิ่งนี้สามารถทำให้เป็นข้อกำหนดเบื้องต้นของเป้าหมายเริ่มต้นของคุณ:

all: show_vars
    ...

แก้ไข:
คุณต้องการวิธีแสดงเป้าหมายที่เป็นไปได้ทั้งหมดของ makefile โดยพลการซึ่งฉันคิดว่าหมายถึงไม่ล่วงล้ำ ดี...

หากต้องการทำอย่างถูกต้องและสามารถรับมือกับ makefiles ที่ซับซ้อนได้เช่นการเกี่ยวข้องกับกฎที่สร้างโดยevalคำสั่งคุณจะต้องเขียนสิ่งที่ใกล้เคียงกับ Make emulator ทำไม่ได้

หากต้องการดูเป้าหมายของกฎง่ายๆคุณสามารถเขียน makefile ที่จะทำหน้าที่เป็นเครื่องสแกน makefile ซึ่งทำงานบน makefile โดยพลการ:

  1. รับชื่อเป้าหมายทั้งหมดจาก makefile โดยใช้ sed
  2. "รวม" makefile เพื่อใช้ขยายตัวแปร
  3. ใช้ `show_%:; echo $$ * "เพื่อพิมพ์เป้าหมายทั้งหมด

นี่คงเป็นผลงานที่น่าประทับใจ แน่ใจหรือว่าเป้าหมายนั้นคุ้มค่ากับความพยายาม?


ไม่ใช่สิ่งที่ฉันต้องการ ฉันต้องการที่จะสร้างรายชื่อเป้าหมายสำหรับ makefile โดยพลการที่ฉันอาจมี ฉันพยายามเขียนฟังก์ชันการเติมอาร์กิวเมนต์สำหรับเชลล์ของฉันและฉันไม่สามารถพึ่งพา makefiles ที่มีความช่วยเหลือที่สมเหตุสมผลได้
BitShifter

-4
grep ^[a-z].*\:$ Makefile | sed s,:,,g

1
-1: วิธีนี้ทำให้เกิดผลบวกปลอมแม้กระทั่งสำหรับการกำหนดตัวแปรอย่างง่าย ( :=)
thiton

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