Table of Contents
Pengantar Perjanjian Lama
Dalam pemrograman, program sering dipisah melintasi berkas sumber dan berkas header multi multiple untuk meningkatkan organisasi, kemampuan, dan kecepatan kompilasi. Namun, modularitas ini memperkenalkan tantangan: ketika perubahan berkas header, setiap berkas sumber yang menyertakan harus dikompilasi kembali. Melakukan masalah ini secara manual adalah error ⁇ prone dan time ⁇ consuming. Makefiles, didorong oleh make membuat alat otomatis membangun, memecahkan masalah ini dengan mengkoding ketergantungan dan mengotomating proses membangun. Masterfile Makes adalah sebuah rite dari sebuah jalur yang serius untuk pengembang C, namun banyak orang memperlakukan mereka sebagai kotak pendatang baru. Ini menjelaskan bagaimana cara kerja file hitam, bagaimana membuat mereka bekerja dalam struktur dan membuat mereka secara otomatis.
Apa Itu Makefiles?
Sebuah Makefile adalah berkas plain ⁇ text yang mendefinisikan satu set aturan untuk membangun sebuah proyek.]make[ utility membaca aturan ini, memeriksa berkas timestamp, dan hanya menjalankan perintah yang diperlukan untuk membawa proyek tersebut sampai saat ini. Ide inti sederhana: setiap aturan memiliki sebuah target[ (berkas untuk menghasilkan), prerequisites (berkas dibutuhkan untuk membangun target), dan [TFLT:3]] (berkas untuk menjalankan perintah yang tergantung pada berkas, yang mana[FLT][T]] hanya perlu dibangun kembali bagian tersebut.
Makefiles telah menjadi bagian dari Unix sejak 1970-an, dan GNU Make adalah standar de facto pada Linux dan macOS. Sintaksnya adalah concise tetapi dapat menjadi halus; mendapatkan hak dependensi adalah keterampilan utama yang dibutuhkan pengembang C.
Pengertian Ketergantungan
Dalam sebuah proyek C, dependensi tidak terbatas pada berkas . Setiap berkas sumber termasuk satu atau lebih berkas header (misalnya, ). Jika sebuah header dimodifikasi, semua berkas yang termasuk itu harus dikompilasi kembali. Serupa dengan itu, berkas objek bergantung pada berkas yang sesuai dengan mereka, dan executable terakhir tergantung pada semua berkas objek.
Eksploitasi vs Ketergantungan Implisit
Dalam Makefile awal, programmer mencantumkan semua prasyarat secara manual. Pendekatan tersebut rapuh: melupakan sebuah header berarti membangun basi, sementara mendaftar terlalu banyak pemicu yang tidak perlu dikompilasi ulang. Lebih buruk, seiring dengan pertumbuhan proyek, daftar manual menjadi tidak dapat dipertahankan. Solusi modern adalah memiliki kompiler menghasilkan ketergantungan secara otomatis, mengubahnya menjadi implisit, mesin ⁇ dicek prasyarat.
Sebuah Makefile yang dibuat dengan baik memperlakukan ketergantungan sebagai perhatian kelas ⁇ pertama. Tujuannya adalah jangan pernah membangun kembali apapun yang tidak perlu dibangun kembali, dan untuk selalu membangun kembali segala sesuatu yang dilakukan. Ini adalah esensi dari koreksi dan efisien dalam membangun inkremental.
Struktur Dasar dari Makefile
Sebuah Makefile tipikal yang mengandung definisi, aturan, dan sasaran palsu. Berikut adalah contoh minimal namun fungsional untuk sebuah proyek dengan dan :
CC = gcc
CFLAGS = -Wall -Wextra -O2
main: main.o utils.o
$(CC) $(CFLAGS) -o main main.o utils.o
main.o: main.c
$(CC) $(CFLAGS) -c main.c
utils.o: utils.c
$(CC) $(CFLAGS) -c utils.c
clean:
rm -f main main.o utils.o
Makefile ini memiliki empat target: (perlaksanaan), dua berkas objek, dan sebuah target palsu . Baris dependensi setelah colon tel]make berkas mana yang harus diperiksa sebelum memutuskan untuk membangun kembali target.
Target - Sasaran yang Berpotek
Target-target seperti atau tidak mewakili berkas. Untuk mencegah make dari membingungkan mereka dengan nama berkas, mereka harus dinyatakan sebagai foni:
.PHONY: clean all
Tanpa ini, jika sebuah berkas bernama ada, make[ akan menganggapnya up ⁇ to ⁇ date dan skip resep.
Memanenkan Ketergantungan Efektif
Pemeliharaan CS1: Makefile manual di atas memiliki kekurangan serius: dependensi pada benar, tetapi bagaimana dengan header? Jika berubah, (yang mencakupnya) harus dibangun kembali, namun aturan mengatakan hanya bergantung pada . Perbaikannya adalah membiarkan kompiler menghasilkan daftar ketergantungan yang sebenarnya.
Generasi Kebergantungan Otomatis dengan GCC
Woedon GCC (dan Clang) dapat menghasilkan informasi dependensi menggunakan keluarga bendera. Kombinasi paling praktis untuk kebanyakan proyek adalah :
- [5] toolname ]]]] ⁇ tulis sebuah berkas dependensi (]) selama kompilasi, daftar hanya pengguna ⁇ defined header (bukan header sistem).
- [5] ]][ ⁇ menentukan nama berkas dependensi.
- [[Efleksif:0]]] ⁇ menambahkan target palsu untuk setiap header, mencegah kesalahan ketika sebuah header dihapus.
Caranya menggabungkan ketergantungan otomatis pelacakan ke dalam Makefile:
CC = gcc
CFLAGS = -Wall -Wextra -O2 -MMD -MP
SRCDIR = src
OBJDIR = obj
SRCS = $(wildcard $(SRCDIR)/*.c)
OBJS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS))
DEPS = $(OBJS:.o=.d)
all: myprogram
myprogram: $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
$(OBJDIR)/%.o: $(SRCDIR)/%.c
@mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@
-include $(DEPS)
.PHONY: all clean
clean:
rm -rf $(OBJDIR) myprogram
Penjelasan:
- [[LLT:25]] mengumpulkan semua berkas di direktori sumber.
- mengubahnya menjadi jalur berkas objek.
- [[EfLT:28]] daftar berkas dependensi (e.g., ).
- Aturan pola kompile masing-masing berkas dan, karena , menghasilkan berkas sebagai efek samping.
- Garis everyid [ dibaca berkas yang dihasilkan , mengubahnya menjadi prasyarat Makefile yang nyata. Sengkang () menekan kesalahan ketika berkas belum ada (misalnya, pada build pertama).
Sekarang, jika dimodifikasi, invokasi berikutnya dari akan dikompilasi ulang secara otomatis karena berkas untuk mencakup sebagai prasyarat.
Teknik Teknik Lanjutan Teknik
Penanganan yang Dihasilkan Bergantung pada Kebergantungan Aman
Ketika header dihapus, berkas masih mungkin mengacunya, menyebabkan make[ gagal dengan kesalahan target yang hilang. Berkas bendera alamat ini dengan menambahkan aturan palsu kosong untuk setiap header dependensi. Jika headernya hilang, make[ hanya menjalankan aturan palsu (yang tidak melakukan apa-apa) dan melanjutkan.
Termasuk file dependensi setelah perubahan sumber
Satu kehalusan: jika berkas sumber menambahkan atau menghapus suatu , berkas yang bersangkutan harus diregenerasi. Karena berkas adalah dirinya sendiri prasyarat berkas objek, make akan memperhatikan timestamp yang berubah dan rekompilasi, yang meregenerasi berkas . Rekursi ini bekerja secara otomatis setelah build pertama selesai.
Hanya Orang yang Berwatak
Kadang kala anda perlu direktori untuk ada sebelum membangun, tetapi anda tidak ingin waktu setem waktunya untuk memicu sebuah membangun kembali. Itulah peran order ⁇ only prasyarat[] (dipisahkan dengan ). Dalam aturan pola di atas, kita menggunakan di dalam resep; sebuah alternatif adalah:
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR):
mkdir -p $@
Ini memastikan direktori dibuat sebelum kompilasi apapun, tetapi perubahan ke direktori itu sendiri (misalnya, berkas baru di dalam) tidak akan memicu rekompilasi.
Praktek Terbaik untuk Bergantung pada Ketergantungan yang Bermanaging
- [OblesFLT:0]] Gunakan generasi ketergantungan otomatis dari hari pertama. Bahkan untuk proyek tunggal ⁇ file, itu kebiasaan yang baik. Ini tidak dikenakan biaya dan mencegah kesalahan di masa depan.
- [[GANDAFLT:0]] Jaga berkas dependensi terpisah dari berkas sumber. Letakkan mereka dalam sebuah atau direktori. Hal ini membuat pembersihan lebih mudah dan menghindari pemborosan pohon sumber.
- [[ZOLT:0]]Include the terjana berkas setelah aturan yang menciptakannya. Direktif tidak apa-apa, tetapi menempatkannya setelah aturan pola memastikan bahwa make pertama tahu bagaimana membangun berkas objek sebelum mencoba membaca berkas .
- [[OGAL:0]]Gunakan target palsu untuk housekeeping.[, , , dan adalah hal yang umum. Selalu menyatakannya dengan .
- [[EFAILFLT:0]]Leverage variabel untuk bendera kompiler, direktori sumber, dan daftar berkas. Hal ini membuat Makefile dapat digunakan kembali di seluruh proyek dan lebih mudah untuk menyesuaikan.
- ¡ZUZEFLT:0]]Uji Makefile Anda dengan perubahan header yang disengaja. Ubah header, jalankan , dan konfirmasi hanya berkas objek yang terpengaruh yang dikompilasi kembali. Jika sebuah pembangunan kembali penuh terjadi, sesuatu salah dengan pelacakan dependensi.
- [[EfolfLT:0]] Pertahankan Makefile sederhana tetapi tidak lebih sederhana dari yang diperlukan. Over ⁇ engineering dengan fungsi canggih seperti dapat membuat debugging menyakitkan. Mulai dengan pola yang ditampilkan dalam artikel ini; ini menskalakan baik ke puluhan berkas.
Sumber Daya Luaran LUAR
Untuk memperdalam pemahaman Anda, berkonsultasi dengan referensi berwibawa ini:
- [[GNU Buat Manual]] Panduan definitif untuk Membuat sintaks, fungsi, dan fitur lanjutan.
- Parameter url-status= yang tidak diketahui akan diabaikan (bantuan)[pranala nonaktif]]GCC Preprosesor Options] ⁇ Dokumentasi untuk , , , dan bendera terkait.
- [[CharleFLT:0]]Makefile Tutorial oleh Chase Lambert ⁇ Tutorial praktis, baik ⁇ terstruktur meliputi banyak kasus penggunaan nyata ⁇ dunia.
Kekecualian Kesimpulan
Kebergantungan program C dengan Makefiles bukanlah suatu kemewahan tetapi kebutuhan untuk proyek apapun yang outflow sebuah berkas tunggal. Dengan menggabungkan aturan pola, generasi dependensi otomatis dengan , dan inklusi hati-hati dari berkas yang dihasilkan, anda dapat membuat sistem build yang baik dan benar. Teknik yang ditampilkan di sini menghilangkan pelacakan manual, mengurangi waktu build, dan mencegah kutu halus yang disebabkan oleh berkas objek basi. Setelah anda internalisasi pola ini, anda tidak akan pernah menulis daftar ketergantungan manual. Investasi dalam pembelajaran manajemen ketergantungan yang tepat membayar off setiap kali anda menjalankan [[TFL:70] dan hanya mengubah file kompilasi.