Tanımlarında değişkenler içeren GNU make'deki hedefleri / hedefleri listeleyin


100

Değişkenlerden isimleri hesaplayarak anında bir dizi hedef oluşturan oldukça büyük bir makefile sahibim. (örn. foo $ (VAR): $ (PREREQS)). Bu değişkenleri genişlettikten sonra gnu'nun bir hedefler listesi çıkarmaya ikna edilmesinin herhangi bir yolu var mı?

Bir aribitrary makefile için hedefleri elde edebilmek istiyorum. Kabuğum için bir tamamlama işlevi yazmaya çalışıyorum.

Yanıtlar:


79

make -pn(İe make --print-data-base --dry-run) ' den çıktıyı ayrıştırabilir misiniz ? Tüm değişkenleri, kuralları, örtük kuralları ve hangi komutların zahmetli ayrıntılarla çalıştırılacağını yazdırır.


Bu cevap diğerinden çok daha güzel görünüyor.
Matt Joiner

Bunun çok daha güzel olduğuna katılıyorum. Yine de umduğumdan daha fazla iş, ama bunu yanıt olarak işaretleyeceğim çünkü başka hiçbir şey makul görünmüyor ve GNU make'in istediğim şey için uygun bir bayrağı yok.
BitShifter

6
Makefile dosyanız dinamik olarak hedefler oluşturuyorsa, çıktının belirttiğiniz hedefe bağlı olabileceğini unutmayın. Çıktı ayrıca ortam değişkenlerinin değerlerine bağlı olabilir veya make komutuyla belirtilen değişkenleri yapabilir.
reinierpost

6
Kısalığı seviyorum. +1 Kendi dönüşümü ekledim (aşağıdaki yanıtta açıklanmıştır):make -pn | sed -rn '/^[^# \t\.%].*:[^=]?/p'
Jamie

Önerin make -pnr. -rÖrtük kuralları kaldırır.
sjbx

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

Bir cazibe gibi çalışan make arg tamamlamasından alınmıştır.


2
çift ​​tırnak içine koyarak bunun için bir takma ad yapmaya çalıştım, ancak bu sadece awk'nin ilk virgülde bir sözdizimi hatası almasına neden oluyor ... bir kabuk (bash) takma adı için bundan nasıl doğru bir şekilde kaçılacağına dair herhangi bir düşünceniz var mı?
drfrogsplat

3
Sanırım tanımlandığı yerle bir ilgisi var. Sanırım bir takma ad olarak tanımlanırsa, çalışma dizini tanımlandığı dizin olur ve görünüşe göre awk bölümü gizli dizinlerdeki noktadan hoşlanmaz. Bir işlevi tanımlamak işe yarar.
İbrahim

~/binBir takma ad kullanmak yerine onu bir kabuk betiğine koydum . Harika çalışıyor; Teşekkürler!
mpontillo

3
alias mkl="make -qp | awk -F':' '/^[a-zA-Z0-9][^\$#\/\t=]*:([^=]|\$)/ {split(\$1,A,/ /);for(i in A)print A[i]}' | sort"Oyunlardan alıntı yapmaktan 2 dakika kurtaracak takma ad :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
| sort -udaha kullanışlı görünüyor :)
sherpya

14

Bunun sadece bir gnu make şey olduğundan emin değilim, ama bu iyi çalışıyor:

make help


Bu oldukça kullanışlıdır, diğer yöntemlerden biri için özel bir takma addan hatırlanması çok daha kolaydır.
Ibrahim

8
GNU Make 3.81 üzerinde gerçekten çalışmıyorum, muhtemelen makefiles'ınızda bir hedef: "make: ***
Hedefi`

8
Bu sadece Makefile'da "yardım" hedefini çağırır. Varsa, bir şey yazdırır ( hedeflerin tam listesini değil ), yoksa (tipik durum), kurtarır.
pfalcon

2
İyi haber, cmake'nin okunması kolay güzel bir "yardım" hedefi oluşturduğu görülüyor.
Stéphane

Bu harika! :) Go cmake
Jeef

10

Birkaç cevaplayıcı make -pn, kuralların veritabanını yazdıracak, ancak hiçbir şey yürütmeyecek - az ya da çok kullanılmasını önerdi . Bu yaklaşımla ilgili sorun -n, hala tüm özyinelemeli yapıları çağırması ve yine de gereğinden çok daha fazla iş yapmasıdır, çünkü normal bir yapıda çağırdığı her komutu yazdırır. Daha verimli bir çözüm, şu içeriklerle önemsiz bir makefile, dummy.mk oluşturmak olacaktır:

__all_targets__: ; #no-op

Şimdi farklı yap'ı çağırın make -p -f Makefile -f dummy.mk __all_targets__. Herhangi bir önemli yapıda, markanın ürettiği çıktı miktarındaki fark önemlidir. Örneğin:

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

Yürütme süresi de önemli ölçüde daha iyiydi - ilk sürüm için 2.063 saniye, ikincisi için 0.059 saniye.


1
Harika bir fikir, büyük yapı sistemleriyle çalışan herkes bunu takdir edecek. Android için İstatistikler Gingerbread ağacı (özyinelemeli yapım kullanmaz, bu nedenle tasarruf çok büyük değildir, sadece iyidir): " 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

İyi bir nokta. Man sayfası makebenzer ama dostça bir şey öneriyor gibi görünüyor, yanimake -p -f/dev/null
Davide

Tam olarak işe yaramayacak @Davide: belirtmek , normal makefile dosyalarını ayrıştırmayı -f /dev/nullengelleyecektir make, böylece yalnızca yerleşik kuralların bir çıktısını alacaksınız. Bu yüzden benim çözümüm belirtiyor -f Makefile -f dummy.mk. Ama bu da yeterli değil, çünkü ile -n, makedevam edecek ve aslında makefile'daki kuralları da uygulamaya başlayacak. Maalesef, çözümü orijinal olarak sunulduğu şekliyle basitleştirebilecek herhangi bir değişikliğin farkında değilim.
Eric Melski

Tabii ki haklısın. Bununla birlikte, make man sayfasında bir hata var, çünkü şöyle diyor: "Veri tabanını herhangi bir dosyayı yeniden oluşturmaya çalışmadan yazdırmak için make -p -f / dev / null kullanın"
Davide

Önceki -n
yorumumda


7

Düzenleme: Bilginize, başka bir yanıttaki debian bash tamamlama git deposu artık bu komut dosyasının bash tamamlama kullanım durumlarına göre uyarlanmış gelişmiş bir sürümünü içeriyor.

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

Bu, debian bash tamamlama betiğinden çok daha eksiksiz bir betiktir, çünkü sorunun sorduğu ve en çok oylanan cevap (debian git sunucusundaki debian bash tamamlama betiği) yeterince ileri gitmeyen oluşturulan kurallar için sonuçlar sağlar.

Bu bağlandığım orijinal senaryo değil ama çok daha basit ve daha hızlı.


BTW, modlar, eğer bu cevap metindeki nüans nedeniyle tüm politikalara tam olarak uymuyorsa, lütfen silmeden önce yorum yapın. Bu sorunun gerçekten eksiksiz ve geçerli bir yanıt alması için gerekli yasal düzenlemeleri yapacağım.
codeshot

Hızlı bir test olarak gcc kaynak kodunu aldım ve ./configure && time ~ / makecomp.sh | wc -l burada ~ / makecomp.sh cevabım. ... çıktıyı yapılandırın ... config.status: Makefile 3312 oluşturuluyor 0m0.401s kullanıcı 0m0.412s sys 0m0.028s
codhot

Başka bir test olarak, codehot.blogspot.co.uk/2012/08/… adresinde birim testi geçişlerini oluşturmak ve kontrol etmek için sözde kurallar üreten demo makefile'ı kullandım . Bu örnek, tipik bir platformlar arası autoconf projesinden daha fazla make özelliği kullanır, bu nedenle bu cevaptaki komut dosyası 14 gerçek hedef döndürürken, ubuntu yapmak için bash tamamlama yalnızca iki yararlı kural ve ardından 5 kaynak dosya döndürür.
codhot

4

Bu, Todd Hodes çözümüne dayalı takma adın kodudur

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

3

Bu güzel bir çıktı verecektir:

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


2

Sanırım bu partiye biraz geç kaldım, ancak belirli bir komut arıyorsanız, deneyebilirsiniz.

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

Bu çoğunlukla işe yarar, ancak yine de bir vpathyönerge gibi bazı hedef dışı şeyler içerebilir . make'In yerleşik kurallarına bağlı değilseniz, şunu kullanabilirsiniz:make -qpR , ardışık düzendeki ilk komut olarak .


Freetz (.org) ile denedim. Dahil edilen çok sayıda makefile listeler ve tüm hedefleri listelememiştir.
Robert Siemer

1

Ruby çözümü:

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

1

Solaris 10 ve turbo C kabuğu üzerinde çalışıyorum. Verilen çözüm makefile projem için çalışmıyor. yukarıdaki komut satırını tcsh sözdizimine değiştirdikten sonra bile. Ancak, kullanarak kolay bir çözüm bulabileceğinizi öğrendim

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

remake versiyonu:

remake --version

dır-dir

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

ve diğer bazı önemsiz sürüm verileri


0

Aynı soruyu aramaya gittim ve şu dönüşü buldum:

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

Bu, tüm yorum satırlarını, desen kurallarını (sekmelerle başlayan satırlar), tüm özleri (örnek .c.ove %.o: %.cdesenler) kaldırır .


kabul edilen cevabın yorumunu okumadı: Jack'in cevabı için +1 ... gist.github.com/777954 - pvandenberk 13 Ocak 14:47
Jamie

0

Bu çözümü başka bir başlıkta buldum:

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

Ayrıca aşağıdakilere de ekleyebilirsiniz Makefile:

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

Ve uygula make list.


-1

Tabii, ama ne zaman tükürmesini istiyorsun?

Kuralı çalıştırırken hedefin adını bildirmek için kurala bir satır koyun:

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

Hepsini bir kerede tükürmek için ayrı bir PHONY hedefi oluşturabilirsiniz:

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

Ve bu, varsayılan hedefinizin bir ön koşulu haline getirilebilir:

all: show_vars
    ...

DÜZENLE:
Rasgele bir makefile'ın tüm olası hedeflerini göstermenin bir yolunu istiyorsunuz, sanırım bu, müdahaleci olmayan anlamına geliyor. İyi...

Bunu tam olarak yapmak ve karmaşık makefile'lerle başa çıkmak için, örneğin evalifadelerle oluşturulan kuralları içeren bir Make emülatörüne yakın bir şey yazmanız gerekir. Pratik değil.

Basit kuralların hedeflerini görmek için, rastgele bir makefile üzerinde çalışan bir makefile tarayıcısı olarak görev yapacak bir makefile yazabilirsiniz:

  1. Sed kullanarak makefile'dan tüm hedef isimleri alın.
  2. değişkenleri genişletmek için kullanmak üzere makefile 'dahil'.
  3. `Show_%:; kullanın tüm hedefleri yazdırmak için echo $$ * `

Bu etkileyici bir çalışma olurdu. Hedefin çabaya değer olduğundan emin misin?


Tam olarak istediğim gibi değil. Sahip olabileceğim keyfi bir makefile için hedeflerin bir listesini çıkarabilmek istiyorum. Kabuğum için bir argüman tamamlama işlevi yazmaya çalışıyorum ve makefile dosyalarının mantıklı bir yardımı olmasına güvenemiyorum.
BitShifter

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

1
-1: Bu yaklaşım, basit değişken atamaları ( :=) için bile yanlış pozitifler üretir .
thiton

Önce test etmeliydin. Yine de denemen iyi.
Konrad Viltersten
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.