Liệt kê các mục tiêu / mục tiêu trong GNU thực hiện có chứa các biến trong định nghĩa của chúng


100

Tôi có một tệp trang điểm khá lớn tạo ra một số mục tiêu nhanh chóng bằng tên tính toán từ các biến. (ví dụ: foo $ (VAR): $ (PREREQS)). Có cách nào mà gnu thực hiện có thể bị thuyết phục để đưa ra danh sách các mục tiêu sau khi nó đã mở rộng các biến này không?

Tôi muốn có thể có được các mục tiêu cho một tệp trang điểm thuộc tính lưu trữ. Tôi đang cố gắng viết một hàm hoàn thành cho trình bao của mình.

Câu trả lời:


79

Bạn có thể phân tích cú pháp đầu ra từ make -pn(tức là make --print-data-base --dry-run) không? Nó in ra tất cả các biến, quy tắc, quy tắc ngầm và những lệnh nào sẽ được chạy một cách chi tiết.


Câu trả lời này trông đẹp hơn nhiều so với câu trả lời kia.
Matt Joiner

Tôi đồng ý rằng điều này là đẹp hơn nhiều. Vẫn còn nhiều việc hơn tôi hy vọng, nhưng tôi sẽ đánh dấu nó là câu trả lời vì không có gì khác có vẻ hợp lý và GNU make không có một lá cờ thuận tiện cho những gì tôi muốn.
BitShifter

6
Lưu ý rằng đầu ra có thể phụ thuộc vào mục tiêu bạn chỉ định, nếu Makefile của bạn tạo mục tiêu động. Kết quả đầu ra cũng có thể phụ thuộc vào giá trị của các biến môi trường hoặc tạo các biến được chỉ định bằng lệnh make.
reinierpost

6
Tôi thích sự ngắn gọn. +1 Đã thêm vòng quay của riêng tôi (được mô tả trong câu trả lời bên dưới):make -pn | sed -rn '/^[^# \t\.%].*:[^=]?/p'
Jamie

Đề nghị make -pnr. Loại -rbỏ các quy tắc ngầm.
sjbx

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

Lấy từ quá trình hoàn thành make arg, hoạt động như một sự quyến rũ.


2
tôi đã cố tạo một bí danh cho điều này, đặt nó trong dấu ngoặc kép, nhưng nó chỉ dẫn đến việc awk có lỗi cú pháp trên dấu phẩy đầu tiên ... bất kỳ suy nghĩ nào về cách thoát chính xác điều này cho bí danh shell (bash)?
drfrogsplat

3
Tôi nghĩ nó có một cái gì đó để làm với nơi nó được xác định. Tôi nghĩ nếu nó được định nghĩa là một bí danh thì thư mục làm việc của nó sẽ trở thành thư mục nơi nó được định nghĩa và rõ ràng phần awk không thích dấu chấm trong các thư mục ẩn. Xác định một chức năng hoạt động.
Ibrahim

Tôi chỉ đặt nó trong một tập lệnh shell ~/binthay vì sử dụng một bí danh. Hoạt động tuyệt vời; cảm ơn!
mpontillo

3
Bí danh alias mkl="make -qp | awk -F':' '/^[a-zA-Z0-9][^\$#\/\t=]*:([^=]|\$)/ {split(\$1,A,/ /);for(i in A)print A[i]}' | sort"sẽ giúp bạn tiết kiệm 2 phút khi chơi trò chơi trích dẫn :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
| sort -uvẻ hữu ích hơn :)
sherpya

14

Tôi không chắc đây có phải chỉ là một sản phẩm gnu hay không, nhưng điều này hoạt động tốt:

make help


Điều này khá tiện dụng, dễ nhớ hơn nhiều so với bí danh tùy chỉnh cho một trong các phương pháp khác.
Ibrahim

8
Không thực sự hoạt động trên GNU Make 3.81, có thể là một mục tiêu trong makefiles của bạn: "make: *** Không có quy tắc nào để thực hiện mục tiêu` giúp đỡ '. Dừng lại "
a1an

8
Điều này chỉ gọi mục tiêu "trợ giúp" trong Makefile. Nếu nó tồn tại, nó sẽ in ra thứ gì đó (không phải danh sách mục tiêu đầy đủ ), nếu nó không tồn tại (tình huống điển hình), nó sẽ cứu trợ.
pfalcon

2
Tin tốt là cmake dường như tạo ra một mục tiêu "trợ giúp" dễ đọc.
Stéphane

Điều này thật tuyệt! :) Đi cmake
Jeef

10

Một số phản hồi đã đề xuất sử dụng make -pn, nó sẽ in ra cơ sở dữ liệu các quy tắc nhưng không thực thi bất cứ điều gì - dù ít hay nhiều. Vấn đề với cách tiếp cận này là -nnó vẫn gọi tất cả các lệnh đệ quy, và nó vẫn làm nhiều việc hơn mức cần thiết, bởi vì nó in ra mọi lệnh mà nó sẽ được gọi trong một bản dựng thông thường. Một giải pháp hiệu quả hơn sẽ là tạo một makefile nhỏ, dummy.mk, với các nội dung sau:

__all_targets__: ; #no-op

Bây giờ gọi make as make -p -f Makefile -f dummy.mk __all_targets__. Trên bất kỳ công trình đáng kể nào, sự khác biệt về số lượng đầu ra do sản xuất tạo ra là đáng kể. Ví dụ:

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

Thời gian thực thi cũng tốt hơn đáng kể - 2,063 giây cho phiên bản đầu tiên, 0,059 giây cho phiên bản thứ hai.


1
Ý tưởng gọn gàng, tất cả những người làm việc với hệ thống xây dựng lớn sẽ đánh giá cao nó. Thống kê cho Android Gingerbread tree (không sử dụng đệ quy, vì vậy tiết kiệm không lớn, chỉ tốt): " 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

Điểm tốt. Man page makedường như cho thấy một cái gì đó tương tự nhưng thân thiện, cụ thể làmake -p -f/dev/null
Davide

@Davide sẽ không hoạt động: việc chỉ định -f /dev/nullsẽ ngăn không cho makephân tích cú pháp các tệp trang điểm thông thường, vì vậy bạn sẽ chỉ nhận được bản in của các quy tắc tích hợp sẵn. Đó là lý do tại sao giải pháp của tôi chỉ định -f Makefile -f dummy.mk. Nhưng điều đó cũng không đủ, bởi vì với -n, makesẽ tiếp tục và thực sự bắt đầu thực hiện các quy tắc trong makefile. Rất tiếc, tôi không biết về bất kỳ sửa đổi nào có thể đơn giản hóa giải pháp như đã trình bày ban đầu.
Eric Melski,

Tất nhiên bạn có quyền. Tuy nhiên man page của make có lỗi, bởi vì nó khẳng định: "Để in cơ sở dữ liệu mà không cần cố gắng để làm lại bất kỳ tập tin, sử dụng làm -p -f / dev / null"
Davide

Điều chỉnh nhẹ để bình luận trước đây của tôi: nó nên đọc "... vì không -n ..."
Eric Melski


7

Chỉnh sửa: FYI kho lưu trữ git hoàn thành bash debian trong một câu trả lời khác hiện đã kết hợp một phiên bản nâng cao của tập lệnh này được điều chỉnh cho phù hợp với các trường hợp sử dụng hoàn thành bash.

#!/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

Đây là một tập lệnh hoàn chỉnh hơn nhiều so với tập lệnh hoàn thành debian bash vì nó cung cấp kết quả cho các quy tắc đã tạo, đó là những gì câu hỏi yêu cầu và câu trả lời được bình chọn nhiều nhất (tập lệnh hoàn thành debian bash tại máy chủ debian git) không đi đủ xa.

Đây không phải là tập lệnh gốc mà tôi đã liên kết nhưng nó đơn giản hơn nhiều và thao tác nhanh hơn.


BTW, mod, nếu câu trả lời này không hoàn toàn phù hợp với tất cả các chính sách do sắc thái của nó là văn bản, vui lòng bình luận trước khi xóa. Tôi sẽ thực hiện bất kỳ điều chỉnh hợp pháp nào cần thiết để câu hỏi này thực sự có được câu trả lời đầy đủ và hợp lệ.
codehot

Để kiểm tra nhanh, tôi lấy mã nguồn gcc và chạy ./configure && time ~ / makecomp.sh | wc -l trong đó ~ / makecomp.sh là câu trả lời của tôi. ... cấu hình đầu ra ... config.status: tạo Makefile 3312 thực 0m0.401s người dùng 0m0.412s sys 0m0.028s
Codehot

Như một thử nghiệm khác, tôi đã sử dụng makefile demo tại Codehot.blogspot.co.uk/2012/08/… tạo quy tắc giả để xây dựng và kiểm tra các lần vượt qua bài kiểm tra đơn vị. Ví dụ này sử dụng nhiều tính năng của make hơn là một dự án autoconf đa nền tảng điển hình, vì vậy tập lệnh trong câu trả lời này trả về 14 mục tiêu thực trong khi hoàn thành bash cho make trên ubuntu chỉ trả về hai quy tắc hữu ích và sau đó là 5 tệp nguồn.
codehot

4

Đây là mã cho bí danh dựa trên giải pháp Todd Hodes

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

3

Điều này sẽ cho kết quả tốt:

make -pn | perl -F: -ane 'print "$F[0]\n" if /^\w+\s*:/' | sort


2

Đoán là tôi đến bữa tiệc này hơi muộn, nhưng nếu bạn đang tìm kiếm một lệnh cụ thể, bạn có thể thử

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

Điều này chủ yếu hoạt động, mặc dù nó vẫn có thể bao gồm một số nội dung không phải mục tiêu như vpathchỉ thị. Nếu bạn không phụ thuộc vào makecác quy tắc có sẵn của ', bạn có thể sử dụng make -qpRlàm lệnh đầu tiên trong đường dẫn.


Tôi đã thử nó với freetz (.org). Liệt kê rất nhiều trang điểm được bao gồm và không liệt kê tất cả các mục tiêu.
Robert Siemer

1

Giải pháp Ruby:

`make -qp`.split("\n").select{|l| l =~ /^\w/ && l !~ /=/}.map{|l| l.sub(/:.*/,'')}

1

Tôi đang làm việc trên solaris 10 và một vỏ turbo C. Giải pháp đã cho không hoạt động cho dự án makefile của tôi. ngay cả sau khi thay đổi dòng lệnh trên thành cú pháp tcsh. Tuy nhiên, tôi phát hiện ra rằng bạn có thể nhận được một giải pháp dễ dàng bằng cách sử dụng

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

phiên bản làm lại:

remake --version

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

và một số dữ liệu phiên bản không quan trọng khác


0

Tôi đã đi tìm câu hỏi tương tự và nghĩ ra vòng quay này:

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

Thao tác này sẽ xóa tất cả các dòng chú thích, quy tắc mẫu (dòng bắt đầu bằng tab), tất cả nội dung (ví dụ .c.o%.o: %.cmẫu).


đã không đọc nhận xét từ câu trả lời được chấp nhận: +1 cho câu trả lời của Jack ... gist.github.com/777954 - pvandenberk 13 tháng 1 lúc 14:47
Jamie

0

Đã tìm thấy giải pháp này trong một chủ đề khác:

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

Bạn cũng có thể thêm nó vào Makefile:

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

Và thực hiện make list.


-1

Chắc chắn rồi, nhưng khi nào bạn muốn nó nhổ chúng ra?

Để báo cáo tên của mục tiêu khi nó chạy quy tắc, hãy đặt một dòng trong quy tắc:

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

Để loại bỏ tất cả chúng cùng một lúc, bạn có thể tạo một mục tiêu PHONY riêng biệt:

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

Và điều này có thể được coi là điều kiện tiên quyết của mục tiêu mặc định của bạn:

all: show_vars
    ...

CHỈNH SỬA:
Bạn muốn có một cách để hiển thị tất cả các mục tiêu có thể có của một makefile tùy ý, mà tôi cho rằng có nghĩa là không xâm phạm. Tốt...

Để làm điều đó chính xác và có thể đối phó với các cấu hình phức tạp, chẳng hạn như liên quan đến các quy tắc được xây dựng bởi các evalcâu lệnh, bạn phải viết một cái gì đó gần với Trình giả lập Make. Không thực tế.

Để xem mục tiêu của các quy tắc đơn giản, bạn có thể viết một makefile hoạt động như một trình quét makefile, hoạt động trên một makefile tùy ý:

  1. Lấy tất cả các tên đích từ makefile bằng cách sử dụng sed.
  2. `include` the makefile để sử dụng nó để mở rộng các biến.
  3. Sử dụng `show_% :; echo $$ * `để in tất cả các mục tiêu

Đây sẽ là một tác phẩm ấn tượng. Bạn có chắc mục tiêu đó đáng để nỗ lực không?


Không hoàn toàn như những gì tôi muốn. Tôi muốn có thể tạo ra một danh sách các mục tiêu cho một makefile tùy ý mà tôi có thể có. Tôi đang cố gắng viết một hàm hoàn thành đối số cho trình bao của mình và tôi không thể dựa vào việc trang điểm có bất kỳ trợ giúp hợp lý nào.
BitShifter

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

1
-1: Cách tiếp cận này tạo ra kết quả dương tính sai ngay cả đối với các phép gán biến đơn giản ( :=).
thiton 20/12/11

Bạn nên thử nó trước. Thật tốt khi bạn cố gắng.
Konrad Viltersten
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.