Làm thế nào để bạn có được danh sách các mục tiêu trong một tệp thực hiện?


202

Tôi đã sử dụng cào một chút (chương trình tạo Ruby) và nó có tùy chọn để nhận danh sách tất cả các mục tiêu có sẵn, ví dụ:

> 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...
...

nhưng dường như không có tùy chọn nào để thực hiện điều này trong GNU make.

Rõ ràng mã gần như có cho nó, kể từ năm 2007 - http://www.mail-archive.com/help-make@gnu.org/msg06434.html .

Dù sao, tôi đã thực hiện một chút hack để trích xuất các mục tiêu từ tệp tạo tệp, mà bạn có thể đưa vào tệp tạo tệp.

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

Nó sẽ cung cấp cho bạn một danh sách các mục tiêu được xác định. Đó chỉ là một sự khởi đầu - chẳng hạn, nó không lọc ra các phụ thuộc.

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

2
Tôi nhanh chóng đọc các câu trả lời, rất thú vị, nhưng đối với bản thân tôi, tôi thích giữ nó đơn giản, đơn giản và di động bằng cách sử dụng một bí danh (trong .bashrc của tôi): alias makefile-targets='grep "^[^#[:space:]].*:" Makefile' Thông thường tôi chỉ cần kiểm tra tệp tạo hiện tại và hoàn thành bash mở rộng bí danh của tôi
RockyRoad


4
Có phải nó quá tầm thường grep : Makefilekhông?
cibercitizen1

Câu trả lời:


130

Đây là một nỗ lực để cải thiện phương pháp tuyệt vời của @ nobar như sau:

  • sử dụng một lệnh mạnh mẽ hơn để trích xuất các tên đích, hy vọng sẽ ngăn chặn mọi sự cố giả (và cũng không cần thiết sh -c)
  • không luôn luôn nhắm mục tiêu makefile trong thư mục hiện tại ; tôn trọng makefiles được chỉ định rõ ràng với-f <file>
  • không bao gồm các mục tiêu ẩn - theo quy ước, đây là các mục tiêu có tên bắt đầu bằng chữ cái hoặc chữ số
  • làm cho làm với một đơn mục tiêu giả mạo
  • tiền tố lệnh với @để ngăn chặn nó được lặp lại trước khi thực hiện

Thật kỳ lạ, GNU makekhông có tính năng nào chỉ liệt kê tên của các mục tiêu được xác định trong tệp thực hiện. Các -ptùy chọn đầu ra sản xuất bao gồm tất cả các mục tiêu, nhưng chôn chúng trong rất nhiều thông tin khác.

Đặt quy tắc sau vào tệp makethực hiện cho GNU để triển khai mục tiêu có tên listđơn giản là liệt kê tất cả các tên mục tiêu theo thứ tự bảng chữ cái - tức là: gọi là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 '^$@$$'

Quan trọng : Khi dán này, đảm bảo rằng dòng cuối cùng được thụt vào bởi chính xác 1 tab char thực tế. (không gian không hoạt động) .

Lưu ý rằng sắp xếp danh sách kết quả của các mục tiêu là tùy chọn tốt nhất, vì việc không sắp xếp không tạo ra một thứ tự hữu ích theo thứ tự mà các mục tiêu xuất hiện trong tệp tạo tệp không được giữ nguyên.
Ngoài ra, các mục tiêu phụ của quy tắc bao gồm nhiều mục tiêu được đầu ra một cách riêng biệt và do đó, do sắp xếp, thường không xuất hiện bên cạnh nhau; ví dụ: quy tắc bắt đầu bằng a z:sẽ không có mục tiêu azđược liệt kê cạnh nhau trong đầu ra, nếu có thêm mục tiêu.

Giải thích về quy tắc :

  • .PHONY: list
    • tuyên bố mục tiêu liệt kê một mục tiêu giả mạo, tức là, người ta không đề cập đến một tệp , do đó, công thức của nó sẽ được gọi vô điều kiện
  • $(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null

    • Gọi makelại để in và phân tích cơ sở dữ liệu bắt nguồn từ tệp thực hiện:
      • -p in cơ sở dữ liệu
      • -Rr ngăn chặn bao gồm các quy tắc và biến tích hợp
      • -qchỉ kiểm tra trạng thái cập nhật của mục tiêu (không làm lại bất cứ điều gì), nhưng bản thân nó không ngăn chặn việc thực hiện các lệnh công thức trong mọi trường hợp; vì thế:
      • -f $(lastword $(MAKEFILE_LIST))đảm bảo rằng cùng một tệp thực hiện được nhắm mục tiêu như trong lệnh gọi ban đầu, bất kể nó được nhắm mục tiêu ngầm hay rõ ràng với -f ....
        Hãy cẩn thận : Điều này sẽ phá vỡ nếu makefile của bạn có chứa các includechỉ thị; để giải quyết vấn đề này, hãy xác định biến THIS_FILE := $(lastword $(MAKEFILE_LIST)) trước bất kỳ includechỉ thị nào và sử dụng -f $(THIS_FILE)thay thế.
      • :là một mục tiêu cố ý không hợp lệ có chủ ý nhằm đảm bảo rằng không có lệnh nào được thực thi ; 2>/dev/nulltriệt tiêu thông báo lỗi kết quả. Lưu ý: -pTuy nhiên, điều này phụ thuộc vào việc in cơ sở dữ liệu, đó là trường hợp của GNU tạo ra 3,82. Đáng buồn thay, GNU make Mời lựa chọn không trực tiếp chỉ in các cơ sở dữ liệu, mà không cũng thực hiện mặc định (hoặc được) nhiệm vụ; nếu bạn không cần nhắm mục tiêu một Makefile cụ thể, bạn có thể sử dụng make -p -f/dev/null, như được đề xuất trong mantrang.
  • -v RS=

    • Đây là một thành ngữ awk chia đầu vào thành các khối của các dòng không trống liền kề.
  • /^# File/,/^# Finished Make data base/
    • Khớp với phạm vi của các dòng trong đầu ra có chứa tất cả các mục tiêu (đúng như GNU tạo 3.82) - bằng cách giới hạn phân tích cú pháp trong phạm vi này, không cần phải xử lý các dương tính giả từ các phần đầu ra khác.
  • if ($$1 !~ "^[#.]")
    • Chọn lọc bỏ qua các khối:
      • # ... bỏ qua các mục tiêu không có mục tiêu, các khối bắt đầu bằng # Not a target:
      • . ... bỏ qua các mục tiêu đặc biệt
    • Tất cả các khối khác nên bắt đầu bằng một dòng chỉ chứa tên của một mục tiêu được xác định rõ ràng theo sau :
  • egrep -v -e '^[^[:alnum:]]' -e '^$@$$' loại bỏ các mục tiêu không mong muốn khỏi đầu ra:
    • '^[^[:alnum:]]'... không bao gồm các mục tiêu ẩn , mà - theo quy ước - là các mục tiêu bắt đầu không phải bằng chữ cái hay chữ số.
    • '^$@$$'... không bao gồm listchính mục tiêu

Chạy make listsau đó in tất cả các mục tiêu, mỗi mục tiêu trên một dòng riêng; bạn có thể dẫn đếnxargs tạo một danh sách được phân tách bằng dấu cách.


Đây là một câu trả lời tuyệt vời, tuy nhiên, làm thế nào tôi có thể mô tả cho từng nhiệm vụ? Hiện tại, tôi đang lưu trữ nó như là một nhận xét trên định nghĩa nhiệm vụ. Không chắc chắn nếu nó có thể bao gồm nó trong danh sách theo cách tương tự như rake --tasksnó không?
Piotr Kuczynski

1
@PiotrKuczynski: Câu hỏi thú vị, nhưng tôi khuyên bạn nên đăng nó dưới dạng câu hỏi mới (chỉ vào câu hỏi này để tham khảo).
mkuity0

"Đáng buồn thay, GNU cung cấp không có tùy chọn trực tiếp để chỉ in cơ sở dữ liệu." Có một -nlựa chọn.
Bulletmagnet

@BONSmagnet: Mục đích của -ntùy chọn là "In các lệnh sẽ được thực thi ..." - nói cách khác: một tính năng chạy khô. Cũng không rằng báo giá của bạn thiếu italicization của từ chỉ : make -ptự làm in cơ sở dữ liệu, nhưng lúc nào cũng chạy nhiệm vụ mặc định ; hướng dẫn sử dụng khuyến cáo các clunky make -p -f/dev/nullđể tránh điều đó.
mkuity0

1
Cũng sẽ liệt kê bất kỳ mục tiêu .PHONY nào, vì vậy hãy đảm bảo bạn không có.PHONY: *
tekumara

189

Trong Bash (ít nhất), điều này có thể được thực hiện tự động khi hoàn thành tab:

make spacetabtab


1
Đã kiểm tra: bash --version = 4.2,45 (1) -release. thực hiện - đảo ngược = 3,81.
tộc

53
+1, nhưng lưu ý rằng đây không phải là tính năng bash , mà phụ thuộc vào nền tảng của bạn . Các nền tảng được chia thành ba loại: những nền tảng được cài đặt theo mặc định này (ví dụ: Debian 7, Fedora 20), những nền tảng mà bạn có thể tùy chọn cài đặt nó (ví dụ: Ubuntu 14, với . /etc/bash_completion) và những nền tảng không hỗ trợ nó (ví dụ: OSX 10.9)
mkuity0

8
Nó không hoạt động trên OS X 10.10 (không phải với bash mà với zsh).
Florian Oswald

4
Mẹo tuyệt vời nhưng cũng cần bash-completiongói. Tìm thấy ở Fedora, RHEL, Gentoo, ect.
NoelProf

4
Điều này không làm việc với các lập trình tạo ra làm mục tiêu AFAICT, ví dụ:$(RUN_TARGETS): run-%: ...
Matthias

31

Điều này rõ ràng sẽ không hoạt động trong nhiều trường hợp, nhưng nếu bạn Makefileđược tạo bởi CMake, bạn có thể chạy được 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

Bạn có tùy chọn nào để bật trong CMakeList để có được điều đó không? Tôi đã nhận được một tệp tạo tệp do CMake tạo ra và tôi không có sẵn mục tiêu trợ giúp giả
Xavier T.

Không. Trên OSX ít nhất là với một CMake gần đây (tôi thực sự đang sử dụng nightlies nhưng tôi tin rằng khi tôi viết cái này tôi đang sử dụng 3.3), chỉ cần chạy touch CMakeLists.txt && cmake . && make helpvà nó sẽ hoạt động. Tôi chỉ có thể đoán bạn đang sử dụng một cmake cổ đại, hoặc không sử dụng trình tạo Unix Makefiles?
Timmmm

Tôi đang sử dụng CMake 3.6.2 với trình tạo unix trên Windows. Tôi sẽ đào xung quanh để tìm lời giải thích vì nó có vẻ tiện dụng.
Xavier T.

26

Tôi đã kết hợp hai câu trả lời sau: https://stackoverflow.com/a/9524878/86967https://stackoverflow.com/a/7390874/86967 và đã thực hiện một số lối thoát để có thể sử dụng từ bên trong tệp tạo tệp này.

.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
Tôi cũng (gần đây) đã phát hiện ra rằng việc hoàn thành tab theo Bash sẽ liệt kê các mục tiêu có sẵn.
tộc

1
+1 cho một cách tiếp cận tuyệt vời, nhưng một vài cải tiến có thể được thực hiện: (a) chỉ định rõ ràng sh -c "…"là không cần thiết, bởi vì đó là những gì maketheo mặc định sử dụng để gọi các lệnh công thức; (b) lệnh bạn sử dụng quá đơn giản, dẫn đến kết quả dương tính giả (như bạn lưu ý); (c) nếu bạn thêm tiền tố vào lệnh @, nó sẽ không được lặp lại thành thiết bị xuất chuẩn trước khi thực hiện, không cần phải sử dụng lệnh -sgọi.
mkuity0

1
có một mục tiêu đơn giản hơn nhiều bạn có thể thêm vào: list: cat Makefile | grep "^ [Az]" | awk '{in $$ 1}' | sed "s /: // g | sort"
thamster

2
Cách tiếp cận mèo / sed thất bại ở nhiều cấp độ. Nó không mở rộng các biến và cũng không liệt kê các mục tiêu là kết quả của việc bao gồm các tệp khác.
Troy Daniels

1
@ mkuity0: Tôi thích sử dụng make -s(thông qua bí danh Bash) hơn là các lệnh tiền tố trong makefile với @. Có một số trường hợp @có thể hữu ích, đáng chú ý là tiền tố cho echocác lệnh (trong đó việc hiển thị lệnh sẽ là dư thừa), nhưng nói chung tôi không muốn sử dụng nó. Bằng cách này, tôi có thể thấy "công thức nấu ăn" khi tôi cần (bằng cách không sử dụng -s), nhưng không điển hình. Đây là tài liệu liên quan: GNU Make Manual, 5.2 Recipe Echoing .
tộc

14

Nếu bạn đã hoàn thành bash để makecài đặt, tập lệnh hoàn thành sẽ xác định một chức năng _make_target_extract_script. Chức năng này có nghĩa là để tạo ra mộtsed tập lệnh có thể được sử dụng để lấy các mục tiêu dưới dạng danh sách.

Sử dụng nó như thế này:

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

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

3
Hữu ích, nhưng lưu ý rằng không phải tất cả các nền tảng đều có tập lệnh /etc/bash_completionvà / hoặc chức năng _make_target_extract_script- dường như bạn đang ở trên Ubuntu> 12. Nếu bạn nhắm mục tiêu /usr/share/bash-completion/completions/makethay thế, cách tiếp cận của bạn sẽ hoạt động trên các nền tảng bổ sung, chẳng hạn như Fedora 20. Có các nền tảng (cũ hơn) có tệp này, nhưng không phải là chức năng (ví dụ: Debian 7 và Ubuntu 12); các nền tảng khác, chẳng hạn như OSX, hoàn toàn không đi kèm với tab make. Có lẽ gửi định nghĩa chức năng thực tế sẽ hữu ích.
mkuity0

1
Cám ơn bạn đã góp ý. Điều này được nhiều đánh giá cao. Có, tôi đã thử nghiệm điều này trên Ubuntu 14.04
hek2mgl

11

Như mkuity0 chỉ ra , một tính năng để liệt kê tất cả các mục tiêu Makefile bị thiếu trong GNU-make và câu trả lời của anh ấy và những người khác cung cấp các cách để làm điều này.

Tuy nhiên, bài viết gốc cũng đề cập đến cào , có chuyển đổi nhiệm vụ làm một cái gì đó hơi khác so với chỉ liệt kê tất cả các nhiệm vụ trong rakefile. Rake sẽ chỉ cung cấp cho bạn một danh sách các nhiệm vụ có mô tả liên quan. Nhiệm vụ không có mô tả sẽ không được liệt kê . Điều này cung cấp cho tác giả khả năng vừa cung cấp các mô tả trợ giúp tùy chỉnh và cũng bỏ qua trợ giúp cho các mục tiêu nhất định.

Nếu bạn muốn mô phỏng hành vi của rake, nơi bạn cung cấp các mô tả cho từng mục tiêu , có một kỹ thuật đơn giản để thực hiện việc này: nhúng các mô tả trong các nhận xét cho từng mục tiêu bạn muốn liệt kê.

Bạn có thể đặt mô tả bên cạnh mục tiêu hoặc, như tôi thường làm, bên cạnh thông số PHONY phía trên mục tiêu, như sau:

.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

Cái nào sẽ mang lại

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

...
help                Generate list of targets with descriptions

Bạn cũng có thể tìm thấy một ví dụ mã ngắn trong ý chính nàyở đây nữa.

Một lần nữa, điều này không giải quyết được vấn đề liệt kê tất cả các mục tiêu trong Makefile. Ví dụ: nếu bạn có một Makefile lớn có thể được tạo ra hoặc do người khác viết và bạn muốn có một cách nhanh chóng để liệt kê các mục tiêu của nó mà không cần tìm hiểu kỹ, điều này sẽ không có ích.

Tuy nhiên, nếu bạn đang viết Makefile và bạn muốn có cách tạo văn bản trợ giúp theo cách tự lập, nhất quán, kỹ thuật này có thể hữu ích.


Đây là một kỹ thuật tuyệt vời - đẹp và đơn giản nhưng cũng mô tả!
Brian Burns

Kỹ thuật tuyệt vời. Tôi đã sửa đổi điều này một chút để sử dụng echolệnh làm mô tả lệnh ( stackoverflow.com/a/52059487/814145 ).
Penghe Geng

@PengheGeng Cảm ơn bài viết. Tôi muốn làm rõ @echo "Target 1"chỉ là một trình giữ chỗ chứ không phải là "lệnh echo mô tả". Văn bản trợ giúp được tạo không xuất phát từ @echo. Trong một Makefile thực, những thứ này echosẽ được thay thế bằng lệnh xây dựng hoặc một số thứ tương tự. Tôi sẽ chỉnh sửa bài viết để làm cho điều này rõ ràng hơn.
jsp

4

Câu trả lời của @ nobar chỉ ra một cách hữu ích cách sử dụng hoàn thành tab để liệt kê các mục tiêu của makefile .

  • Điều này hoạt động tuyệt vời cho các nền tảng cung cấp chức năng này theo mặc định (ví dụ: Debian, Fedora ).

  • Trên các nền tảng khác (ví dụ: Ubuntu ), bạn phải tải rõ ràng chức năng này, theo ngụ ý của câu trả lời của @ hek2mgl :

    • . /etc/bash_completion cài đặt một số chức năng hoàn thành tab, bao gồm một chức năng cho make
    • Ngoài ra, để chỉ cài đặt hoàn thành tab cho make:
      • . /usr/share/bash-completion/completions/make
  • Đối với các nền tảng hoàn toàn không cung cấp chức năng này , chẳng hạn như OSX , bạn có thể lấy các lệnh sau (được điều chỉnh từ đây ) để thực hiện chức năng này:
_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
  • Lưu ý: Điều này không phức tạp như chức năng hoàn thành tab đi kèm với các bản phân phối Linux: đáng chú ý nhất là nó luôn nhắm mục tiêu tệp Makefile trong thư mục hiện tại , ngay cả khi dòng lệnh nhắm vào một tệp tạo tệp khác -f <file>.

4

Câu trả lời yêu thích của tôi về vấn đề này đã được Chris Down đăng trên Unix & Linux Stack Exchange. Tôi sẽ trích dẫn.

Đây là cách mô-đun hoàn thành bash để makecó được danh sách của nó:

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

Nó in ra một danh sách các mục tiêu được phân định bằng dòng mới, mà không cần phân trang.

Người dùng Brainstone đề xuất đường ống sort -uđể loại bỏ các mục trùng lặp:

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

Nguồn: Làm thế nào để liệt kê tất cả các mục tiêu trong thực hiện? (Unix & Linux SE)


4

Tập trung vào một cú pháp dễ dàng để mô tả mục tiêu tạo và có đầu ra rõ ràng, tôi đã chọn phương pháp này:

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:

Vì vậy, coi việc trên như là một Makefile và chạy nó mang lại cho bạn một cái gì đó như

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

Giải thích cho chuỗi lệnh:


Giải pháp rất hay. Tôi đã sử dụng điều này trong một vài năm nay: awk -F ':|##' '/^[^\t].+:.*##/ { printf "\033[36mmake %-28s\033[0m -%s\n", $$1, $$NF }' $(MAKEFILE_LIST) | sort với ##nhận xét trước khi cùng dòng với mục tiêu. Nhưng tôi nghĩ giải pháp của bạn cho phép trước khi đọc.
ngực

Một tệp thực hiện bao gồm hai báo cáo đầu tiên grep: parentheses not balancedtrên máy OSX 10.15 của tôi.
Malcolm Crum

@ Xin lỗi, lỗi của tôi. Cảm ơn đã chỉ ra điều đó. Đã sửa nó. yêu cầu thoát khỏi các ký hiệu đô la không được cho là bắt đầu tên biến.
Richard Kiefer

Xem ra, StackOverflow chuyển đổi các tab thành khoảng trắng khi hiển thị các phần mã ở trên, nhưng Makefiles yêu cầu các tab. Bạn có thể chỉnh sửa bài đăng và sau đó sao chép các phần, vì vậy các tab được giữ lại.
Richard Kiefer

2

Rất nhiều giải pháp khả thi ở đây, nhưng như tôi muốn nói, "nếu nó đáng làm một lần, thì đáng để làm lại." Tôi đã nâng cấp đường để sử dụng (tab) (tab), nhưng như một số người đã lưu ý, bạn có thể không có hỗ trợ hoàn thành, hoặc, nếu bạn có nhiều tệp bao gồm, bạn có thể muốn một cách dễ dàng hơn để biết mục tiêu được xác định.

Tôi chưa thử nghiệm dưới đây với các sản phẩm phụ ... Tôi nghĩ rằng nó sẽ không hoạt động. Như chúng ta biết, đệ quy làm cho được coi là có hại.

.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 := \)

Mà tôi thích vì:

  • liệt kê các mục tiêu bằng cách bao gồm tập tin.
  • định nghĩa mục tiêu động động đầu ra (thay thế các dấu phân cách biến bằng modulo)
  • xuất từng mục tiêu trên một dòng mới
  • có vẻ rõ ràng hơn (ý kiến ​​chủ quan)

Giải trình:

  • tập tin foreach trong MAKEFILE_LIST
  • xuất tên của tập tin
  • dòng grep chứa dấu hai chấm, không được thụt lề, không nhận xét và không bắt đầu bằng dấu chấm
  • loại trừ các biểu thức gán ngay lập tức (: =)
  • cắt, sắp xếp, thụt lề và cắt phụ thuộc quy tắc (sau dấu hai chấm)
  • munge biến phân cách để ngăn chặn mở rộng

Đầu ra mẫu:

 = 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

Điều này hữu ích với tôi vì tôi muốn xem các mục tiêu xây dựng cần thiết (và phụ thuộc của chúng) theo mục tiêu thực hiện. Tôi biết rằng làm cho các mục tiêu không thể bắt đầu bằng dấu "." tính cách. Tôi không biết ngôn ngữ nào được hỗ trợ, vì vậy tôi đã sử dụng biểu thức ngoặc của egrep.

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

1

Điều này là xa sạch, nhưng đã làm công việc, đối với tôi.

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

Tôi sử dụng make -pkết xuất cơ sở dữ liệu nội bộ, mương stderr, sử dụng nhanh và bẩn grep -A 100000để giữ đáy của đầu ra. Sau đó, tôi làm sạch đầu ra với một vài grep -vvà cuối cùng sử dụng cutđể lấy những gì trước dấu hai chấm, cụ thể là các mục tiêu.

Điều này là đủ cho các kịch bản trợ giúp của tôi trên hầu hết các Makefiles của tôi.

EDIT: thêm vào grep -v Makefileđó là một quy tắc nội bộ


1

Đây là một sửa đổi cho câu trả lời rất hữu ích của jsp ( https://stackoverflow.com/a/45843594/814145 ). Tôi thích ý tưởng không chỉ nhận được một danh sách các mục tiêu mà cả những mô tả của chúng. Makefile của jsp đặt mô tả làm nhận xét, mà tôi tìm thấy thường sẽ được lặp lại trong lệnh echo mô tả của mục tiêu. Vì vậy, thay vào đó, tôi trích xuất mô tả từ lệnh echo cho từng mục tiêu.

Ví dụ 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

Đầu ra của 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

Ghi chú:

  • Giống như câu trả lời của jsp , chỉ các mục tiêu PHONY có thể được liệt kê, có thể hoặc không thể hoạt động cho trường hợp của bạn
  • Ngoài ra, nó chỉ liệt kê các mục tiêu PHONY có lệnh echohoặc :là lệnh đầu tiên của công thức. :có nghĩa là "không làm gì". Tôi sử dụng nó ở đây cho những mục tiêu không cần tiếng vang, chẳng hạn nhưall mục tiêu ở trên.
  • Có một mẹo bổ sung cho helpmục tiêu để thêm ":" vào make helpđầu ra.

0

Một câu trả lời bổ sung cho ở trên.

đã thử nghiệm trên MacOSX chỉ sử dụng mèo và awk trên thiết bị đầu cuối

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

sẽ xuất ra tệp tạo như dưới đây:

mục tiêu1

mục tiêu2

mục tiêu3

trong Makefile, nó phải là cùng một câu lệnh, đảm bảo rằng bạn thoát khỏi các biến bằng cách sử dụng biến $$ chứ không phải biến $.

Giải trình

mèo - nhổ ra nội dung

| - phân tích cú pháp ống dẫn đến awk tiếp theo

awk - chạy regex không bao gồm "shell" và chỉ chấp nhận các dòng "Az" sau đó in ra cột đầu tiên $ 1

awk - một lần nữa xóa ký tự cuối cùng ":" khỏi danh sách

đây là một đầu ra thô và bạn có thể làm nhiều thứ thú vị hơn chỉ với AWK. Cố gắng tránh sed vì nó không nhất quán trong các biến thể BSD, tức là một số hoạt động trên * nix nhưng thất bại trên các BSD như MacOSX.

Hơn

Bạn sẽ có thể thêm phần này (có sửa đổi) vào một tệp để tạo , vào thư mục hoàn thành bash mặc định /usr/local/etc/bash-completion.d/ nghĩa là khi bạn "tạo tab tab " .. nó sẽ hoàn thành mục tiêu dựa trên một tập lệnh lót.


bạn cũng có thể sử dụng make -qp thay vì cat. vì vậy nó sẽ trở thành make -qp | awk '/: / &&! /: = / && / ^ [Az] / &&! / PATH / &&! / HIỂN THỊ / &&! / TERM_SESSION / &&! / USER_TEXT_ENCODING / &&! / Makefile / {print , chiều dài ($ 0) -1) | "sort -u"} '
Jimmy MG Lim

0

Tôi thường làm:

grep install_target Makefile

Nó sẽ trở lại với một cái gì đó như:

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

Tôi hi vọng cái này giúp được


0

Đối với một Bash Script

Đây là một cách rất đơn giản để thực hiện việc này bash- dựa trên nhận xét của @ cibercitizen1 ở trên :

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

Cũng xem câu trả lời có thẩm quyền hơn của @ Marc.2377, trong đó cho biết mô-đun hoàn thành Bash đã makethực hiện như thế nào.


-4

không chắc tại sao câu trả lời trước lại phức tạp đến vậy:

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

8
Các câu trả lời trước là quá phức tạp, bởi vì nó bao gồm tất cả các kịch bản rằng câu trả lời của bạn không bao gồm: (a) bao gồm các mục tiêu được xác định thông qua các biến (ví dụ $(SHELLS): ...), (b) bao gồm các mục tiêu mà bắt đầu bằng một chữ số, (c) không bao gồm các định nghĩa biến , (d) nhắm mục tiêu tệp thực hiện phù hợp nếu makeđược chỉ định với đường dẫn tệp thực hiện rõ ràng. (a) là thiếu sót rất quan trọng: ngay cả khi bạn nhắm mục tiêu vào tệp thực hiện đúng , việc phân tích tệp thô sẽ không hoạt động trong trường hợp chung, do thiếu mở rộng biến.
mkuity0

6
Bên cạnh đó, rất phức tạp: lệnh của bạn có thể được đơn giản hóa theo các điều sau - nhưng điểm chính là nó không đủ mạnh : awk -F: '/^[A-z]/ {print $$1}' Makefile. Cuối cùng, một điểm học thuật chủ yếu: sử dụng [A-z]chứ không phải [:alpha:]là bạn sẽ bỏ lỡ các mục tiêu bắt đầu bằng một ký tự nước ngoài, chẳng hạn như á.
mkuity0

@ mkuity0 Lệnh awk đầu tiên của bạn hoạt động độc đáo và đơn giản nhất cho đến nay, mặc dù sử dụng [: alpha:] dường như phá vỡ nó vì một số lý do - nó bỏ lỡ một số mục tiêu trong tệp thử nghiệm.
Brian Burns

@ bburns.km: Tính xấu của tôi: Đáng lẽ tôi nên nói [[:alpha:]]chứ không phải [:alpha:]( [:alpha:]đại diện cho tập hợp các chữ cái nhận biết địa phương bên trong một lớp ký tự ( [...]), do đó nhu cầu hiệu quả của double [[ / ]].
mkuity0

4
Tại sao câu trả lời này rất phức tạp? Bạn quản lý để thu thập một số tội lỗi vô dụng trong đoạn trích ngắn này. awk -F: '/^[A-Za-z]/ { print $$1 }' Makefilesử dụng một quy trình duy nhất và hy vọng một biểu thức chính quy chính xác hơn (mặc dù bạn tất nhiên có thể có các mục tiêu với dấu gạch dưới, số, v.v., như đã lưu ý trong các nhận xét trước đó).
tripleee
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.