Yanıtlar:
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 clean
hedef 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 clean
Adlı 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 make
genellikle sahte olanı vardır hedefler şunlardır: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Diyelim install
ki, makyaj dosyalarında çok yaygın olan bir hedefiniz var . Eğer yoksa değil kullanmak .PHONY
ve adlandırılmış bir dosya install
Makefile ile aynı dizinde var, o zaman make install
yapacak 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, install
hedef 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 install
dosyanı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.
.sh
veya .bash
uzantı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
.PHONY
her zaman kullanıyorum ...
.PHONY
sürümün siz olduğunuzu anlamıyor .
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.
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.
make
kalmıyor, aynı zamanda bir bütün olarak mantıklı bir hale geliyor, hepsi dosyalar hakkında! Bu cevap için teşekkürler.
.PHONY: install
En iyi açıklama GNU manuel yapmak kendisi: 4.6 Sahte Hedefler bölümü .
.PHONY
make '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
.
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:
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 fileall
gelen filefwd
için file
, şimdi fileall
her defasında yeniden inşa olsun, ama yalnızca bağımlı hedeflerin bir dosya olarak buna karşı bayat etmez.
Özel hedef .PHONY:
, sahte hedeflerin bildirilmesine izin verir, böylece make
gerç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.
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 superclean
ateş olur clean
, andsomethingelse
ve catcher superclean
; ama PHONY ile make superclean
ateş etmeyeceksin catcher superclean
.
clean
Hedefin 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, superclean
hedef gerçekten sahte, bu yüzden yapmak onu superclean
hedef için deps sağlayan başka bir şeyle biriktirmeye çalışacaktır - bu diğer superclean
hedefleri ve %
hedefi içerir.
Unutmayın andsomethingelse
ya 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