
Semuanya berawal, tampaknya, dengan pertanyaan sederhana yang pertama kali membuat saya pingsan - "Mengapa saya harus membuat? Mengapa saya tidak bisa bergaul dengan skrip bash ?". Dan saya pikir - Sungguh, mengapa saya harus membuatnya? (dan yang paling penting) Masalah apa yang dia pecahkan?
Kemudian saya memutuskan untuk berpikir sedikit - bagaimana kita mengumpulkan proyek-proyek kita jika kita tidak berhasil. Katakanlah kita memiliki proyek dengan kode sumber. Dari mereka Anda perlu mendapatkan file (atau pustaka) yang dapat dieksekusi. Sekilas, tugasnya tampaknya sederhana, tetapi kami melangkah lebih jauh. Misalkan pada tahap awal proyek terdiri dari satu file.

Untuk mengkompilasinya, jalankan saja satu perintah:
$ gcc main.c -o main
Sederhana saja. Tetapi beberapa waktu berlalu, proyek berkembang, beberapa modul muncul di dalamnya dan file sumber menjadi lebih besar.

Untuk mengkompilasi, Anda perlu menjalankan sejumlah perintah berikut:
$ gcc -c src0.c $ gcc -c src1.c $ gcc -c main.c $ gcc -o main main.o src0.o src1.o
Setuju, ini adalah proses yang agak panjang dan melelahkan. Untuk melakukan ini secara manual, saya tidak akan melakukannya. Saya akan berpikir bahwa proses ini dapat otomatis dengan hanya membuat skrip build.sh yang berisi perintah-perintah ini. Oke, itu jauh lebih mudah:
$ ./build.sh
Kami melaju! Proyek ini berkembang, jumlah file sumber meningkat dan ada lebih banyak baris di dalamnya juga. Kami mulai memperhatikan bahwa waktu kompilasi meningkat tajam. Di sini kita melihat cacat yang signifikan pada skrip kita - ini mengkompilasi semua 50 file kita dengan sumber-sumbernya, meskipun kita hanya memodifikasi satu.

Itu tidak akan berhasil! Waktu pengembang adalah sumber daya yang terlalu berharga. Nah, kita bisa mencoba memodifikasi skrip build sehingga sebelum kompilasi kita mengecek waktu modifikasi file source dan object. Dan kompilasi hanya sumber-sumber yang telah diubah. Dan secara kondisional, mungkin terlihat seperti ini:
Dan sekarang hanya sumber-sumber yang telah dimodifikasi yang akan dikompilasi.

Tapi apa yang terjadi ketika proyek berubah menjadi seperti ini:

Cepat atau lambat, suatu saat akan datang ketika akan sangat sulit untuk memahami proyek dan dukungan dari skrip seperti itu sendiri akan menjadi proses yang melelahkan. Dan bukan fakta bahwa skrip ini akan memeriksa semua dependensi secara memadai. Selain itu, kami dapat memiliki beberapa proyek dan masing-masing akan memiliki skrip sendiri untuk perakitan.
Tentu saja, kita melihat bahwa solusi umum untuk masalah ini muncul. Alat yang akan menyediakan mekanisme untuk memeriksa dependensi. Dan di sini kita perlahan-lahan sampai pada penemuan make . Dan sekarang, mengetahui masalah apa yang akan kita hadapi dalam proses membangun proyek, pada akhirnya saya akan merumuskan persyaratan berikut untuk membuat:
- analisis cap waktu ketergantungan dan tujuan
- jumlah minimum pekerjaan yang diperlukan untuk menjamin relevansi file yang diturunkan
- (yah, + eksekusi perintah paralel)
Makefile
Makefile digunakan untuk menggambarkan aturan perakitan proyek. Membuat Makefile, kami mendeskripsikan secara deskriptif keadaan hubungan antar file. Sifat deklaratif dari penentuan status nyaman karena kita mengatakan bahwa kita memiliki daftar file dan kita perlu mendapatkan file baru dari mereka dengan mengeksekusi daftar perintah. Dalam hal menggunakan beberapa bahasa imperatif (misalnya, shell), kita harus melakukan sejumlah besar pemeriksaan yang berbeda, mendapatkan kode yang rumit dan membingungkan dalam output, sementara make melakukannya untuk kita. Yang utama adalah membangun pohon ketergantungan yang tepat.
< > : < ... > < > ... ...
Saya tidak akan berbicara tentang cara menulis Makefiles. Di Internet ada banyak manual tentang hal ini dan jika Anda mau, Anda bisa merujuknya. Dan selain itu, beberapa orang menulis Makefiles secara manual. Dan Makefiles yang sangat kompleks dapat menjadi sumber komplikasi alih-alih menyederhanakan proses pembuatan.