Bir makefile .PHONY amacı nedir?


1738

.PHONYMakefile'de ne anlama geliyor? İçinden gitmiş bu , ama çok karmaşıktır.

Birisi bana basit terimlerle açıklayabilir mi?

Yanıtlar:


1946

Varsayılan olarak, Makefile hedefleri "dosya hedefleridir" - diğer dosyalardan dosya oluşturmak için kullanılırlar. Make hedefinin bir dosya olduğunu varsayar ve bu Makefiles yazmayı nispeten kolaylaştırır:

foo: bar
  create_one_from_the_other foo bar

Ancak, bazen Makefile'nizin dosya sistemindeki fiziksel dosyaları temsil etmeyen komutları çalıştırmasını istersiniz. Bunun iyi örnekleri ortak hedefler "temiz" ve "hepsi" dir. Muhtemelen durum böyle değildir, ancak büyük olasılıkla ana dizininizde bir dosya olabilirclean . Böyle bir durumda Make, varsayılan olarak cleanhedef bu dosyayla ilişkilendirileceği için karıştırılacaktır ve Make, dosyayı yalnızca bağımlılıklarıyla ilgili güncel görünmediğinde çalıştıracaktır.

Bu özel hedeflere sahte denir ve açıkça Dosyalarla ilişkilendirilmediğini belirtebilirsiniz, örneğin:

.PHONY: clean
clean:
  rm -rf *.o

make cleanAdlı bir dosyanız olsa bile şimdi beklendiği gibi çalışacaktır clean.

Make açısından, sahte bir hedef basitçe her zaman güncel olmayan bir hedeftir, bu nedenle ne zaman istersen make <phony_target>dosya sisteminin durumundan bağımsız olarak çalışır. Bazı yaygın makegenellikle sahte olanı vardır hedefler şunlardır: all, install, clean, distclean, TAGS, info, check.


49
@ eSKay: 'neden' sahte 'deniyor?' - çünkü bu gerçek bir hedef değil. Yani hedef adı, o hedefin komutları tarafından üretilen bir dosya değildir.
Bernard

96
@Lazer: Anadili İngilizce olan biri olup olmadığınızı bilmiyorum. Değilim. sahte kelimesi kulağa hoş geldiği anlamına gelmez. en.wiktionary.org/wiki/phony diyor ki: Sahte; sahte; yanıltıcı bir görünüme sahip.
Bahbar

57
Bağlantılı öğreticide ele alınabilse de, bu yanıt tam olarak tam değildir. .PHONY, Makefile'deki bir etiketi / dosyayı, hedefiniz ne olursa olsun topolojik türünün bir parçasıysa oluşturulmaya zorlar. Yani, sahte olarak ayarlanmış bir 'cleanup:' etiketiniz varsa ve install etiketiniz cleanup ile önkoşul olarak tanımlanırsa - yani 'install: cleanup', temizleme işlemi Makefile oluşturmaya çalıştığında her zaman çalıştırılır 'Yüklemek'. Bu, başarılı olup olmadıklarına bakılmaksızın her zaman atmak istediğiniz adımlar için yararlıdır - zaman damgalarını yok sayar ve sadece zorlar.
synthesizerpatel

9
Görevle aynı ada sahip bir dosyanız olmadığı sürece .PHONY kullanmanız gerekmediğini unutmayın. Görev her zaman yine de yürütülecek ve Makefile daha okunabilir olacaktır.
Bernard

15
"Sahte bir hedef sadece her zaman güncel olmayan bir hedeftir" - harika bir açıklama!
Danijel

730

Diyelim installki, makyaj dosyalarında çok yaygın olan bir hedefiniz var . Eğer yoksa değil kullanmak .PHONYve adlandırılmış bir dosya installMakefile ile aynı dizinde var, o zaman make installyapacak bir şey . Bunun nedeni, Make'ın kuralı "adlı dosyayı oluşturmak için böyle ve benzeri tarifleri yürüt" anlamına gelecek şekilde yorumlamasıdır install. Dosya zaten orada olduğundan ve bağımlılıkları değişmediğinden hiçbir şey yapılmayacak.

Ancak, installhedef PHONY yaparsanız, oluşturma aracına hedefin kurgusal olduğunu ve bu yapının gerçek dosyayı oluşturmasını beklememesi gerektiğini söyleyecektir. Bu nedenle installdosyanın var olup olmadığını kontrol etmeyecektir , yani: a) dosya varsa davranışı değişmeyecek ve b) fazladan stat()çağrılmayacaktır.

Genellikle Makefile'nizde hedef adıyla aynı ada sahip bir çıktı dosyası oluşturmayan tüm hedefler PHONY olmalıdır. Bu genellikle içerir all, install, clean, distclean, vb.


6
@PineappleUndertheSea Kabul edilen cevap, başlangıçtaki değersizlik seviyesinden önemli ölçüde geliştirildi ve şimdi bu kadar iyi. Yorumunuzu anlamak için düzeltme geçmişine bakmak zorunda kaldım.
Mark Amery

2
Kod tabanımda asla 'install' veya benzeri bir dosya olmayacağından bu biraz anlamsız görünüyor. Çoğu dosyanın bir dosya uzantısı olur ve dosya uzantısı olmayan dosyalar genellikle 'README' gibi tüm büyük harflerle yazılır. Sonra tekrar, 'install.sh' yerine 'install' adında bir bash betiğiniz varsa, kötü bir zaman geçireceksiniz.
nucleartide

6
@JasonTu Bu mutlaka doğru değildir. Bash komut dosyası oluşturma kuralları , ana işlevleri varmış gibi çalışan "programlar" için .shveya .bashuzantısını atlamanızı ve dahil ettiğiniz kitaplıklar için bir uzantı eklemeyi ayırmanızı ister source mylib.sh. Aslında, bu SO sorusunu aldım çünkü Makefile'm ile aynı dizinde bir senaryo vardıinstall
Kyle

10
@Kyle Evet, geçmiş kendimin ne anlama geldiğinden emin değilim. Bugünlerde .PHONYher zaman kullanıyorum ...
nucleartide

2
@JasonTu Buradaki çözüm basittir: bir zaman makinesi oluşturun ve geçmiş benliğinizi "değiştirin". Sizinle birlikte bir kürek almanızı tavsiye ederim, böylece kimse .PHONYsürümün siz olduğunuzu anlamıyor .
Mateen Ulhaq

120

NOT : Marka oluşturma aracı, makefile dosyasını okur ve kuraldaki ':' sembolünün her iki yanındaki dosyaların değişiklik zaman damgalarını denetler.

Misal

Bir 'test' dizininde aşağıdaki dosyalar bulunur:

prerit@vvdn105:~/test$ ls
hello  hello.c  makefile

Makefile içinde bir kural aşağıdaki gibi tanımlanır:

hello:hello.c
    cc hello.c -o hello

Şimdi 'hello' dosyasının 'hello.c' dosyasından sonra oluşturulan bazı verileri içeren bir metin dosyası olduğunu varsayalım. Dolayısıyla, 'merhaba' modifikasyonunun (veya yaratılmasının) zaman damgası 'merhaba' dan daha yeni olacaktır. Komut satırından 'merhaba olun' çağrıldığında şu şekilde yazdırılacaktır:

make: `hello' is up to date.

Şimdi 'hello.c' dosyasına erişin ve içine kod sözdizimini veya mantığını etkilemeyen bazı beyaz boşluklar koyun ve kaydedin ve çıkın. Şimdi merhaba.c'nin değişiklik zaman damgası 'merhaba'dan daha yeni. Şimdi 'merhaba olun' çağrılırsa, komutlar şu şekilde yürütülür:

cc hello.c -o hello

Ve 'merhaba' dosyasının (metin dosyası) üzerine yeni bir ikili dosya 'merhaba' (yukarıdaki derleme komutunun sonucu) yazılır.

Aşağıdaki gibi makefile .PHONY kullanırsak:

.PHONY:hello

hello:hello.c
    cc hello.c -o hello

ve 'merhaba yap' çağrılırsa, pwd 'testinde bulunan herhangi bir dosyayı yok sayar ve komutu her seferinde yürütür.

Şimdi diyelim ki 'merhaba' hedefinin beyan edilmiş bir bağımlılığı yok:

hello:
    cc hello.c -o hello

ve "merhaba" dosyası pwd "testinde" zaten mevcutsa, "merhaba olun" her zaman şu şekilde gösterilir:

make: `hello' is up to date.

3
Bu sadece çalıştırdığım komutları mantıklı kılmakla makekalmıyor, aynı zamanda bir bütün olarak mantıklı bir hale geliyor, hepsi dosyalar hakkında! Bu cevap için teşekkürler.
Kzqai

80
.PHONY: install
  • "install" kelimesinin bu Makefile dosyasındaki bir dosya adını temsil etmediği anlamına gelir;
  • Makefile'ın aynı dizinde "install" adlı bir dosyayla ilgisi olmadığı anlamına gelir.


33

En iyi açıklama GNU manuel yapmak kendisi: 4.6 Sahte Hedefler bölümü .

.PHONYmake 'biridir Dahili Hedef Adları Özel . İlginizi çekebilecek başka hedefler de var, bu yüzden bu referansları gözden kaçırmaya değer.

Bir .PHONY hedefi düşünmenin zamanı geldiğinde, make, bu ada sahip bir dosyanın var olup olmadığına veya son değişiklik süresinin ne olduğuna bakılmaksızın koşulsuz olarak çalışacaktır.

Ayrıca, markanınall ve gibi Standart Hedefleri ile de ilgilenebilirsiniz clean.


11

Ayrıca, fiziksel bir hedef başka bir fiziksel hedefe bağlı olan sahte hedefe bağlı olduğunda, ".PHONY" için önemli bir zor işlem vardır:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Basitçe TARGET2'yi güncellediyseniz TARGET1'in TARGET1'e karşı bayat kabul edilmesini beklersiniz, bu nedenle TARGET1 yeniden oluşturulmalıdır. Ve gerçekten bu şekilde çalışıyor .

Zor kısmı, TARGET2'nin TARGET1'e karşı bayat olmadığı durumlarda - bu durumda TARGET1'in yeniden oluşturulmamasını beklemelisiniz.

Bu şaşırtıcı bir şekilde işe yaramaz çünkü: sahte hedef yine de çalıştırıldı (sahte hedefler normalde olduğu gibi) , yani sahte hedef güncellenmiş sayılır . Ve bu nedenle TARGET1 sahte hedefe karşı bayat kabul edilir .

Düşünmek:

all: fileall

fileall: file2 filefwd
    echo file2 file1 >fileall


file2: file2.src
    echo file2.src >file2

file1: file1.src
    echo file1.src >file1
    echo file1.src >>file1

.PHONY: filefwd
.PHONY: filefwd2

filefwd: filefwd2

filefwd2: file1
    @echo "Produced target file1"


prepare:
    echo "Some text 1" >> file1.src
    echo "Some text 2" >> file2.src

Bununla oynayabilirsiniz:

  • önce "kaynak dosyaları" hazırlamak için "hazırlayın" yapın
  • güncellenmiş görmek için belirli dosyalara dokunarak bununla oynayın

Fileall'ın sahte bir hedef yoluyla dolaylı olarak dosya1'e bağlı olduğunu görebilirsiniz - ancak bu bağımlılık nedeniyle her zaman yeniden oluşturulur. İçinde bağımlılık değiştirirseniz fileallgelen filefwdiçin file, şimdi fileallher defasında yeniden inşa olsun, ama yalnızca bağımlı hedeflerin bir dosya olarak buna karşı bayat etmez.


5

Özel hedef .PHONY:, sahte hedeflerin bildirilmesine izin verir, böylece makegerçek dosya adları olarak kontrol edilmez: bu dosyalar hala mevcut olsa bile her zaman çalışır.

Birkaç koyabilirsiniz .PHONY:Gözlerinde farklı Makefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

Sahte hedefleri bildirmenin başka bir yolu daha var: '::'

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

'::' özel bir anlama sahiptir: hedefler sahte ve birkaç kez görünebilirler:

clean ::
    rm file1

...


clean ::
    rm file2

Komut blokları birbiri ardına çağrılır.


3

Onları sık sık varsayılan hedefe ateş etmemelerini söylemek için kullanıyorum.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Sahte olmadan, make supercleanateş olur clean, andsomethingelseve catcher superclean; ama PHONY ile make supercleanateş etmeyeceksin catcher superclean.

cleanHedefin PHONY olduğunu söyleme konusunda endişelenmemiz gerekmiyor , çünkü tamamen sahte değil. Hiçbir zaman temiz dosyayı üretmese de, ateş etme komutları vardır, bu yüzden make son hedef olduğunu düşünür.

Ancak, supercleanhedef gerçekten sahte, bu yüzden yapmak onu supercleanhedef için deps sağlayan başka bir şeyle biriktirmeye çalışacaktır - bu diğer supercleanhedefleri ve %hedefi içerir.

Unutmayın andsomethingelseya da hakkında hiçbir şey söylemiyoruz blah, bu yüzden açıkça alıcıya gidiyorlar.

Çıktı şöyle görünür:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
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.