Efe ÇİFTCİ

Bilgisayar Mühendisi, Özgür Yazılımcı, Trekkie.

Makefile Nedir? 11 Temmuz 2011


Biliyorum uzun zamandır bloguma gereken özeni gösteremiyorum. Geçenlerde üniversitedeki bir öğrencinin Makefile dosyalarının kullanımı hakkında attığı bir e-posta ile tekrar canlandırmış olayım burayı.

Yazının devamında referans olarak kullanacağım işletim sistemi Ubuntu olacak, eğer başka bir işletim sistemi kullanıyorsanız gerekli durumlarda alıcınızın ayarları ile oynamayı unutmayın 🙂

Makefile dosyaları genellikle bir veya birden fazla kaynak kod dosyasından oluşan yazılım projelerini derlememizi kolaylaştırmaya yarar. Örneğin yazdığınız basit bir “Merhaba dünya” programını (hello.c) düşünün, bu programı derlemek ve sistem genelinde çalışabileceği bir dizin altına yerleştirmek isteseydik terminalden şu komutları çalıştırırdık:

$ gcc -o hello hello.c
$ sudo cp hello /usr/local/bin

Daha sonra bu programı silmek isteseydik:

$ sudo rm /usr/local/bin/hello

Örneğimiz henüz sıcakken Makefile adı verilen dosyanın kullanımına gelelim. Makefile dosyaları içersinde, projeyi derlerken işimizi kolaylaştıracak olan tanımlar yer alır, örneğin yukarıdaki üç komutu uygulayan bir Makefile dosyası içeriği şöyle olabilir:

build: hello.c
    gcc -o hello hello.c

install: build
    cp hello /usr/local/bin

uninstall: /usr/local/bin/hello
    rm /usr/local/bin/hello

Öncelikle satır başlarında boşluk karakterleri değil, tab karakteri olduğunu belirtmemde fayda var aksi takdirde ilerleyen aşamalarda “missing separator. stop” şeklinde hata almak mümkün.

Bu 6 satırdan oluşan Makefile dosyasının yaptığı şey hızlıca bakıldığında anlaşılabiliyor sanırım: 3 farklı amaç için (build, install, uninstall) kullanılan komutları hazır olarak barındırmak.

Peki bu dosyayı nasıl kullanacağız? Öncelikle sistemde apt-get install make komutu ile hızlıca kurabileceğimiz make uygulamasının bulunması gerekiyor. Ardından yapmamız gereken tek şey “make” yazıp enter tuşuna basmak. Bunu yaptığınız zaman göreceksiniz ki Makefile dosyası içindeki ilk görev olan “build” otomatik olarak çalıştırılacak.

“make” komutu, her zaman Makefile dosyası içindeki ilk görevi çalıştırır ve durur. Diğer görevlerin çalışmasını sağlamak için make kelimesinden sonra hangi görevi çalıştırmak istediğimizi belirtmek gerekir, “make install” ve “make uninstall” gibi. Evet, ilk görevi “make build” şeklinde çalıştırmak da mümkün 🙂

Yani özetle yukarıdaki Makefile dosyasını kullanarak programı derlemek ve sistem genelinde çalışabileceği bir dizin altına yerleştirmek isteseydik yapacağımız şey şu olacaktı:

$ make
$ sudo make install

Ve daha sonra bu programı silmek isteseydik:

$ sudo make uninstall

Görülebileceği gibi, bir Makefile dosyasının içeriği genel olarak şu şekildedir:

[görev]: [önşart]
    [komut]

Eğer dikkat ettiysek, her görevin başladığı satırda : karakterinden sonra satır devam ediyor. : karakterinden sonra gelen şeyleri (dosya adı, görev adı, vs) o görevin çalışması için gereken ön şart olarak düşünebiliriz. Yani build görevinin çalışması için hello.c dosyasına, install görevinin çalışması için build görevinin çalışmasına, uninstall görevinin de çalışabilmesi için /usr/local/bin/hello dosyasına ihtiyacımız var. Aksi takdirde hello.c dosyası yokken neyi derleyeceğiz? hello dosyası derlenememişken neyi sisteme kopyalayacağız? Veya var olmayan bir dosyayı mı silmeye çalışacağız? Ayrıca denerseniz göreceksiniz ki, önşartları yerine getirilemeyen görevler çalışmayacaktır.

Makefile dosyaları ile yapabileceklerimiz bunlarla sınırlı değil, örneğin şöyle bir Makefile dosyası düşünelim:

circle:
    gcc -o circle circle.c

rectangle:
    gcc -o rectangle rectangle.c

square:
    gcc -o square square.c

Tamam iyi güzel, her kaynak dosyamız için farklı farklı görevlerimiz tanımlanmış ama peki ya sistemde gcc değil de başka bir C derleyici kullanılıyorsa? Bu durumda her satırda yer alan gcc kelimesini, kullanılan diğer derleyicinin adıyla değiştirmek gerekirdi (“bul / değiştir yaparım” diyenler biraz dışarı çıkıp hava alsın :)) ama kullanabileceğimiz bir kolaylık var: değişken isimleri kullanmak. Örneğin derleyicimizin adını C Compiler (kısaca CC) adlı bir değişkene verelim ve her görevde bu değişkeni kullanalım:

CC=/usr/bin/gcc

circle:
    $(CC) -o circle circle.c

rectangle:
    $(CC) -o rectangle rectangle.c

square:
    $(CC) -o square square.c

Tahmin edebileceğiniz gibi, derleyici değiştirdiğimiz zaman sadece en üstteki değişkene atadığımız değeri değiştirmek yeterli olacaktır. Makefile dosyaları içinde kullanabileceğimiz değişkenlerde herhangi bir sınırlama yok; örneğin derleyicinin, derleme parametrelerinin ve programın kurulacağı dizinin adını değişkenlere atadığımız bir Makefile dosyası şuna benzeyebilir:

CC=/usr/bin/gcc
PARAMS=-g -O0 -std=c99
PATH=/usr/local/bin

doit:
    $(CC) $(PARAMS) -o deneme deneme.c
    cp deneme $(PATH)/

Makefile dosyalarının temel özellikleri bu şekilde. Daha kapsamlı bir dökümantasyon için GNU Make sayfasına bakabilirsiniz 🙂