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:
laptop:~/docarticle/build_tools$ 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
sanaldoku yöresidir. Debian sanaldoku yö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 sanaldoku yö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?
laptop:~/ornek$ 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.