make uygulaması çalıştırıldığında, bulunulan dizinde sırasıyla GNUmakefile, makefile ve Makefile dosyalarını arar. Alternatif olarak -f seçeneği ile Makefile olarak kullanacağınız dosyayı da belirlemeniz mümkün olsa da standartların dışına çıkmamakta fayda var. make neyi nasıl yapacağını bu dosyalardan öğrenecektir. Eğer bulunduğunuz dizinde bir Makefile yok ise aşağıdaki gibi bir çıktı alacaksınız demektir:
$ make
make: *** No targets specified and no makefile found. Stop.
| İpucu |
---|
Genel kabul görmüşlüğü ve göz alışkanlığı açısından dosya adı olarak alternatiflerin yerine Makefile kullanmanızı öneririm.
|
Bir Makefile aslında işlemlerin nasıl yapılacağını gösteren kural tanımlamalarından oluşmaktadır. Genel olarak dosyanın biçimi aşağıdaki gibidir:
hedef: bağımlılıklar
<TAB> komut
<TAB> komut
<TAB> ...
Diğer kurala geçmeden bir boş satır
...
Burada en sık yapacağımız hata <TAB> tuşuna basmayı unutmak olacaktır. Makefile dosyasını hazırladığınız metin düzenleyiciden kaynaklanan bir sorun da olabilir. En iyisi emacs kullanarak makefile-mode ile yazmaktır, böylece hata yapma olasılığınız oldukça azalacaktır.
Kurallar arasında bir satır boş bırakılması GNU make için zorunlu olmamakla birlikte bazı Unix sürümleriyle uyumluluk için boşluk bırakılması gereklidir.
İlk satırda hedef'in oluşturulmasında etkili olan, bağımlılık yaratan dosyalar birbirinden boşluk ile ayrılmış olarak tek satırda listelenir. Eğer bağımlılık kısmında yer alan dosyalardan en az birinin son değiştirilme tarihi, hedef'ten daha yeni ise, hedef yeniden oluşturulur. Diğer durumda hedefin yeniden oluşturulmasına gerek olmadığı anlaşılır, çünkü hedefin bağımlı olduğu dosyalarda son oluşturmadan sonra bir değişiklik olmamıştır. Sonraki satırlarda bağımlılık yaratan bu dosyalardan hedefin oluşturulabilmesi için gerekli komutlar yer alır. Şimdi basit bir örnek yapalım:
test: test.c
gcc -o test test.c
Bu örnekte hedef olarak test uygulaması derlenecektir. Uygulamanın bağımlı olduğu dosya test.c'dir. test.c dosyasında herhangi bir değişiklik olduğunda veya test silindiğinde, gcc -o test test.c komutu çalıştırılacak ve test yeniden oluşturulacaktır. Şimdi daha karışık bir örnek yapalım:
CC = gcc
CFLAGS = -O2 -Wall -pedantic
LIBS = -lm -lnsl
test: test.o
$(CC) $(CFLAGS) $(LIBS) -o test test.o
test.o: test.c
$(CC) $(CFLAGS) -c test.c
clean:
rm -f test *.o
install: test
cp test /usr/bin
İlk satırda CC değişkenine kullanacağımız derleyiciyi atıyoruz. Makefile dosyaları içerisinde bu şekilde değişken tanımlaması yapıp, değişkeni dosya içerisinde $(değişken) olarak kullanabiliriz. İkinci satırda ise derleyiciye vereceğimiz bazı seçenekleri CFLAGS değişkenine atıyoruz. Üçüncü satırda uygulamamızın kullandığı kütüphaneleri listeledik. Ardından ilk kuralımız geliyor. test uygulaması test.o dosyasına bağımlı olarak belirtilmiş ve test.o'dan test'in oluşturulabilmesi için gerekli komut hemen altında listelenmiştir. Değişkenlerin değerlerini yerine koyduğumuzda komutumuz gcc -O2 -Wall -pedantic -lm -lnsl -o test test.o şeklinde olacaktır.
İkinci kuralımız test.o'nun nasıl oluşturulacağını belirtmektedir. Aslında bu iki kural bir önceki örnekte olduğu gibi birleştirilebilir, ancak mantığı anlatabilmek için burada ikiye bölünmüştür. test.c dosyasında bir değişiklik olduğunda test.o dosyası hemen altında listelenen komutla yeniden oluşturulur: gcc -O2 -Wall -pedantic -c test.c
Üçüncü kuralımızda çalıştığımız dizinde nasıl temizlik yapacağımızı belirtiyoruz. make clean komutunu çalıştırdığımızda test dosyası ve .o ile biten nesne dosyaları silinecektir. Bir sonraki kuralımız ise install. Bu kuralda da test dosyasında bir değişme olduğunda cp test /usr/bin komutu ile dosyayı /usr/bin dizini altına kopyalıyoruz.
Makefile içerisindeki her bir kural make uygulamasına seçenek olarak verilebilir ve ayrıca işletilebilir. Yukarıdaki gibi bir Makefile dosyasına sahipsek make test.o komutuyla sadece test.o için verilen kuralın çalıştırılmasını sağlayabiliriz. Veya make install komutuyla sadece install kuralının çalışmasını sağlayabiliriz. Ancak install aynı zamanda test'e bağımlı olduğundan test'in kuralı da çalışır. Aynı şekilde test de test.o'ya bağlı olduğundan test.o kuralı da çalışacaktır. Komutu seçenek vermeden sadece make şeklinde çalıştırdığınızda ise Makefile dosyasını okur ve bulduğu ilk kuralı işler. Bizim örneğimizde ilk kural test olduğu için test dosyasının oluşturulabilmesi için gerekli işlemleri yapacaktır. Bu nedenle Makefile dosyalarında ilk kural çoğu zaman all: test install gibi olur. Böylece her defasında make xxx yazmak yerine sadece make yazarak hız kazanmış oluruz.
Bu örneği iyice anlamadan sonraki bölümlere devam etmeyiniz. make uygulamasının bu basit ama bir o kadar da güçlü mantığını tam olarak anladığınızda onu sadece kodunuzu derlemek için değil, çok farklı amaçlar için de kullanabileceğinizi göreceksiniz. Hemen bir örnek verelim, bir sanaldoku (web) uygulamanız var ve buradan isim:telefon şeklinde bir metin dosyasına giriş yapılıyor. Eğer bu metin dosyası değiştiğinde çalışacak şekilde bir kural tanımlarsanız, mesela metin dosyası her değiştiğinde bu dosyayı okuyup ayrıştırarak veritabanına kayıt edecek bir uygulamanın çalıştırılması sağlanabilir. Örneğimiz pek işe yarar bir şey olmadı ama eminim mantığı anlamışsınızdır.
| Not |
---|
Aslında make için verilebilecek en iyi örneklerden bir tanesi de Debian sanalyöresidir. Debian sanalyöresi, tamamen statik HTML sayfalardan oluşur. Bu sayede yansılanması daha kolay hale gelir ve statik sayfalar sanaldoku sunucusuna çok az yük getirir. Ancak binlerce sayfadan oluşan Debian sanalyöresi, statik olmasına rağmen çok hızlı güncellenebilmektedir. Aynı zamanda yöreyi ziyaret ettiyseniz farketmiş olacağınız gibi, sanaldoku istemciniz dil ayarına göre sayfanın o dile çevirilmiş bir sürümü mevcut ise karşınıza o getirilmektedir. Tüm bu dinamiklik alt tarafta kullanılan, çoğunluğu wml, binlerce dosya tarafından sağlanmaktadır. Her 3-4 saatte bir CVS'de bulunan kaynak kodu çekilerek make ile wml dosyalarından HTML dosyaları üretilmekte, sayfalar arası aşamalar düzenlenmekte, farklı dillere çevirilen sayfalar kontrol edilmekte, bazı programlar ve betikler çalıştırılmaktadır. Kısaca özetlemek gerekirse böyle ama gerçekte tüm yörenin yeniden oluşturulması için gerçekten oldukça karmaşık işlemler yapılmaktadır. İlgilenenler http://www.debian.org/devel/website/desc adresine bakabilir.
|
Yukarıdaki Makefile örneğimize tekrar dönelim. make clean komutunu çalıştırdığımızda derleme sonrasında oluşan dosyalar silinmektedir. Peki, bulunduğumuz dizinde ismi clean olan bir dosya mevcut ise ne olur?
$ make clean
make: `clean' is up to date.
Gördüğünüz gibi clean adında bir dosya var olduğu ve clean için bağımlılık listesi olmadığından dolayı kuralın güncelliğini koruduğunu ve alttaki komutların çalıştırılmaması gerektiğini düşündü. İşte bu gibi durumlar için özel bir kural mevcuttur: .PHONY
Yukarıda anlatılan sorunu giderebilmek için Makefile dosyamızın içeriğine aşağıdaki kuralı da eklemeliyiz:
Böylelikle make clean komutunun, bulunulan dizinde clean adında bir dosya olsa bile düzgün olarak çalışmasını sağlamış olduk.