Apa tujuan dari .PHONY di makefile?

1739

Apa yang dimaksud .PHONYdengan Makefile? Saya sudah melalui ini , tetapi terlalu rumit.

Adakah yang bisa menjelaskannya kepada saya secara sederhana?

Lazer
sumber

Jawaban:

1947

Secara default, target Makefile adalah "target file" - target tersebut digunakan untuk membuat file dari file lain. Anggap targetnya adalah file, dan ini membuat penulisan Makefiles relatif mudah:

foo: bar
  create_one_from_the_other foo bar

Namun, kadang-kadang Anda ingin Makefile Anda menjalankan perintah yang tidak mewakili file fisik dalam sistem file. Contoh yang baik untuk ini adalah target umum "bersih" dan "semua". Kemungkinannya bukan ini masalahnya, tetapi Anda mungkin berpotensi memiliki nama file cleandi direktori utama Anda. Dalam kasus seperti itu, Make akan menjadi bingung karena secara default cleantarget akan dikaitkan dengan file ini dan Make hanya akan menjalankannya ketika file tersebut tampaknya tidak mutakhir sehubungan dengan dependensinya.

Target khusus ini disebut palsu dan Anda dapat secara eksplisit memberi tahu Make mereka tidak terkait dengan file, misalnya:

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

Sekarang make cleanakan berjalan seperti yang diharapkan bahkan jika Anda memiliki file bernama clean.

Dalam hal Make, target palsu hanyalah target yang selalu kedaluwarsa, jadi setiap kali Anda bertanya make <phony_target>, itu akan berjalan, terlepas dari keadaan sistem file. Beberapa umum maketarget yang sering palsu adalah: all, install, clean, distclean, TAGS, info, check.

Eli Bendersky
sumber
49
@ eSKay: 'mengapa ini disebut' palsu '?' - karena itu bukan target nyata. Yaitu, nama target bukanlah file yang dihasilkan oleh perintah dari target itu.
Bernard
96
@ Lazer: Saya tidak tahu apakah Anda seorang penutur asli bahasa Inggris. Bukan saya. kata palsu tidak berarti seperti apa bunyinya. en.wiktionary.org/wiki/phony mengatakan: Penipuan; palsu; memiliki penampilan yang menyesatkan.
Bahbar
57
Jawaban ini tidak sepenuhnya lengkap - meskipun mungkin dibahas dalam tutorial yang ditautkan. .PHONY memaksa label / file dalam Makefile untuk dibangun jika itu adalah bagian dari jenis topologi apa pun target Anda. Artinya, jika Anda memiliki label 'pembersihan:' yang diatur palsu, dan label instalasi Anda didefinisikan dengan pembersihan sebagai prasyarat - yaitu 'instal: pembersihan', pembersihan akan selalu dijalankan ketika Makefile mencoba membangun 'Install'. Ini berguna untuk langkah-langkah yang selalu ingin Anda ambil terlepas dari apakah berhasil - itu akan mengabaikan cap waktu dan memaksanya.
synthesizerpatel
9
Perhatikan bahwa Anda tidak perlu menggunakan .PHONY selama Anda tidak memiliki file dengan nama yang sama dengan tugas. Lagi pula, tugas itu akan selalu dieksekusi, dan Makefile akan lebih mudah dibaca.
Bernard
15
"target palsu hanyalah target yang selalu ketinggalan zaman" - penjelasan yang bagus!
Danijel
730

Mari kita asumsikan Anda memiliki installtarget, yang sangat umum di makefile. Jika Anda tidak menggunakan .PHONY, dan file bernama installada di direktori yang sama dengan Makefile, maka make installtidak akan melakukan apa pun . Ini karena Make menafsirkan aturan berarti "menjalankan resep ini-dan-itu untuk membuat file bernama install". Karena file sudah ada di sana, dan dependensinya tidak berubah, tidak ada yang akan dilakukan.

Namun jika Anda membuat installtarget PHONY, itu akan memberi tahu alat make bahwa target tersebut fiktif, dan yang membuat tidak boleh mengharapkannya untuk membuat file yang sebenarnya. Karenanya ia tidak akan memeriksa apakah installfile itu ada, artinya: a) perilakunya tidak akan diubah jika file itu ada dan b) ekstra stat()tidak akan dipanggil.

Secara umum semua target di Makefile Anda yang tidak menghasilkan file output dengan nama yang sama dengan nama target harus PHONY. Hal ini biasanya meliputi all, install, clean, distclean, dan sebagainya.

George Y.
sumber
6
@PineappleUndertheSea Jawaban yang diterima telah meningkat secara signifikan dari tingkat ketidakberdayaan awalnya, dan sekarang sama baiknya dengan yang ini. Saya harus melihat riwayat revisinya untuk memahami komentar Anda.
Mark Amery
2
Ini sepertinya tidak ada gunanya karena saya tidak akan pernah memiliki file bernama 'install' atau sejenisnya di basis kode saya. Sebagian besar file akan memiliki ekstensi file, dan file tanpa ekstensi file biasanya dalam huruf besar semua, seperti 'README'. Kemudian lagi, jika Anda memiliki skrip bash bernama 'install' dan bukannya 'install.sh', Anda akan memiliki waktu yang buruk.
nucleartide
6
@JasonTu Ini belum tentu benar. Konvensi skrip Bash meminta Anda untuk menghapus .shatau .bashekstensi untuk "program" yang berjalan seperti mereka memiliki fungsi utama dan cadangan menambahkan ekstensi untuk perpustakaan yang Anda sertakan ( source mylib.sh). Bahkan, saya sampai pada pertanyaan SO ini karena saya punya skrip di direktori yang sama dengan Makefile saya dipanggilinstall
Kyle
10
@Kyle Ya, aku tidak yakin apa arti masa laluku. Hari ini saya menggunakan .PHONYsemua waktu ...
nucleartide
2
@JasonTu Solusinya di sini sederhana: membangun mesin waktu dan "mengganti" diri masa lalu Anda. Saya sarankan membawa sekop bersama Anda sehingga tidak ada yang menyadari bahwa Anda adalah .PHONYversinya.
Mateen Ulhaq
120

CATATAN : Alat make membaca makefile dan memeriksa stempel waktu modifikasi file di kedua sisi simbol ':' dalam aturan.

Contoh

Dalam direktori 'test' file berikut ada:

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

Dalam makefile aturan didefinisikan sebagai berikut:

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

Sekarang asumsikan file 'halo' adalah file teks yang berisi beberapa data, yang dibuat setelah file 'hello.c'. Jadi cap waktu modifikasi (atau kreasi) 'halo' akan lebih baru daripada 'hello.c'. Jadi ketika kita akan memanggil 'make hello' dari baris perintah, itu akan dicetak sebagai:

make: `hello' is up to date.

Sekarang akses file 'hello.c' dan letakkan beberapa spasi putih di dalamnya, yang tidak memengaruhi sintaksis atau logika kode lalu simpan dan keluar. Sekarang cap waktu modifikasi hello.c lebih baru daripada 'hello'. Sekarang jika Anda memanggil 'make hello', itu akan menjalankan perintah sebagai:

cc hello.c -o hello

Dan file 'halo' (file teks) akan ditimpa dengan file biner baru 'halo' (hasil dari perintah kompilasi di atas).

Jika kita menggunakan .PHONY di makefile sebagai berikut:

.PHONY:hello

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

dan kemudian memanggil 'make hello', itu akan mengabaikan semua file yang ada di pwd 'test' dan menjalankan perintah setiap waktu.

Sekarang anggaplah, bahwa target 'halo' tidak memiliki ketergantungan menyatakan:

hello:
    cc hello.c -o hello

dan file 'halo' sudah ada di pwd 'test', maka 'make hello' akan selalu ditampilkan sebagai:

make: `hello' is up to date.
prerit jain
sumber
3
Tidak hanya ini membuat perintah yang saya jalankan masuk akal, ini akhirnya menyebabkan makesecara keseluruhan masuk akal, ini semua tentang file! Terima kasih atas jawaban ini.
Kzqai
80
.PHONY: install
  • berarti kata "instal" tidak mewakili nama file di Makefile ini;
  • berarti Makefile tidak ada hubungannya dengan file bernama "install" di direktori yang sama.
YourBestBet
sumber
45

Ini adalah target bangun yang bukan nama file.

JohnMcG
sumber
33

Penjelasan terbaik adalah GNU make manual sendiri: 4,6 bagian Target Phony .

.PHONYadalah salah satu dari Nama Target Built-in Khusus make . Ada target lain yang mungkin Anda minati, jadi ada baiknya membaca sekilas referensi ini.

Ketika tiba saatnya untuk mempertimbangkan target .PHONY, make akan menjalankan resepnya tanpa syarat, terlepas dari apakah file dengan nama itu ada atau berapa waktu modifikasi terakhirnya.

Anda mungkin juga tertarik dengan Target Standar make seperti alldan clean.

James Wald
sumber
11

Ada juga satu trik rumit yang penting dari ".PHONY" - ketika target fisik bergantung pada target palsu yang tergantung pada target fisik lain:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Anda hanya berharap bahwa jika Anda memperbarui TARGET2, maka TARGET1 harus dianggap basi terhadap TARGET1, sehingga TARGET1 harus dibangun kembali. Dan itu benar-benar bekerja seperti ini .

Bagian yang sulit adalah ketika TARGET2 tidak basi terhadap TARGET1 - dalam hal ini Anda harus mengharapkan bahwa TARGET1 tidak boleh dibangun kembali.

Ini mengejutkan tidak berfungsi karena: target palsu dijalankan pula (seperti yang biasanya dilakukan target palsu) , yang berarti bahwa target palsu dianggap diperbarui . Dan karena itu TARGET1 dianggap basi terhadap target palsu .

Mempertimbangkan:

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

Anda dapat bermain-main dengan ini:

  • pertama-tama lakukan 'buat persiapan' untuk menyiapkan "file sumber"
  • bermain-main dengan itu dengan menyentuh file tertentu untuk melihatnya diperbarui

Anda dapat melihat bahwa file semua tergantung pada file1 secara tidak langsung melalui target palsu - tetapi selalu dibangun kembali karena ketergantungan ini. Jika Anda mengubah ketergantungan dalam filealldari filefwdmenjadi file, sekarang filealltidak bisa dibangun kembali setiap kali, tetapi hanya ketika salah satu dari target bergantung basi terhadap itu sebagai file.

Ethouris
sumber
5

Target khusus .PHONY:memungkinkan untuk mendeklarasikan target palsu, sehinggamake tidak akan memeriksanya sebagai nama file yang sebenarnya: itu akan berfungsi sepanjang waktu walaupun file tersebut masih ada.

Anda dapat menempatkan beberapa .PHONY:di Makefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

Ada cara lain untuk mendeklarasikan target palsu: sederhananya '::'

all :: prog1 prog2

...

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

'::' memiliki arti khusus: target palsu ditambah mereka dapat muncul beberapa kali:

clean ::
    rm file1

...


clean ::
    rm file2

Blok perintah akan dipanggil satu demi satu.

Edouard Thiel
sumber
3

Saya sering menggunakannya untuk memberi tahu target default untuk tidak menembak.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Tanpa palsu, make supercleanakan memecat clean, andsomethingelsedan catcher superclean; tetapi dengan PHONY, make supercleantidak akan memecat catcher superclean.

Kita tidak perlu khawatir untuk mengatakan bahwa cleantargetnya adalah PHONY, karena itu tidak sepenuhnya palsu. Meskipun tidak pernah menghasilkan file bersih, ia memiliki perintah untuk diaktifkan sehingga membuat akan berpikir itu adalah target akhir.

Namun, supercleantarget tersebut benar-benar palsu, jadi make akan mencoba menumpuknya dengan hal lain yang menyediakan deps untuk supercleantarget - ini termasuk supercleantarget lain dan% target.

Perhatikan bahwa kami tidak mengatakan apa-apa tentang andsomethingelseatau blah, jadi mereka jelas pergi ke penangkap.

Outputnya terlihat seperti ini:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
jettero
sumber