makefile formatı yazılan bir kaynak kodu derlemek ve yüklemek için kullanılan ne yaygın derleme talimatı formatlarından biridir.
Bu yazıda sizlere makefile dosyası nasıl yazılır anlatacağım.
Örneğin aşağıdaki gibi bir C kodumuz olsun
#include <stdio.h> int main(){ puts("Hello world!\n"); return 0; }
Bunu aşağıdaki komutu kulanarak derleriz ve kurarız.
$ gcc -o hello hello.c $ install hello /usr/bin/hello
Makefile dosyalarının bölüm tanımlamalarında girintileme amaçlı Tab kullanılır.
Şimdi aşağıdaki makefile dosyasını inceleyelim.
PREFIX=/usr build: $(CC) -o hello hello.c install: install hello $(DESTDIR)/$(PREFIX)/bin/hello
Burada PREFIX, CC, DESTDIR gibi parametreler değişkendir. Bu değişkenler derleme esnasında değiştirilebilir.
Bu makefile dosyasını kullanarak derlemeyi ve yüklemeyi aşağıdaki gibi yaparız.
$ make $ make install
Görüldüğü gibi derleme ve yükleme işlemi daha kolay ve nasıl derleneceğini basitçe belirtmiş olduk.
Burada kullandığımız değişkenler şu şekilde açılnabilir.
Make komutuna eğer hiç parametre verimezsek ilk baştaki bölümü çalıştırır. Biz ilk başta build tanımladığımız için make komutu build çalıştırır. make komutuna parametre olarak bölüm verirsek o bölüm çalıştırılır.
Değişken tanımlamak için variable=value şeklinde tanımlanabilir. değişkeni kullanırken de $() işareti arasına alınır. Örneğin:
yazi=hello world hello: echo $(yazi)
Bu değişkeni make yazi=deneme123 şeklinde komut vererek değiştirebiliriz.
Var olan bir değişkene ekleme yapmak için += ifadesi kullanılır. := ifadesi eğer tanımlama varsa ekleme yapar. ?= sadece daha önceden tanımlanmışsa ekleme yapar.
yazi=hello yazi+=world sayi:=$(shell ls) hello: echo $(yazi)
Eğer $ işareti kullanmanız gereken bir durum oluşursa $$ ifadesi kullanabilirsiniz. Örneğin:
hello: bash -c "echo $$HOME"
Makefile yazarken bölümler tanımlanır ve eğer bölümün adı belirtilmemişse ilk bölüm çalıştırılır. Bölümler arası bağımlılık vermek için aşağıdaki gibi bir kullanım yapılmalıdır.
yazi: sayi test echo "Hello world" sayi: echo 12 test: echo test123
Yukarıdaki dosyayı çalıştırdığımızda sırasıyla sayi -> test -> yazi bölümleri çalıştırılır.
Aynı işi yapan birden çok bölüm şu şekilde tanımlanabilir.
bol1 bol2: echo Merhaba # Şuna eşittir. bol1: echo Merhaba bol2: echo Merhaba
Bölümün adını $@ kullanarak öğrenebiliriz.
bolum: echo $@
Bölümün tüm bağımlılıklarını almak için için $^ kullanabiliriz.
bolum: bol1 bol2 echo $^ bol1 bol2: true
$? ifadesi $^ ile benzerdir fakat sadece geçerli bölümden sonra tanımlanan bölümleri döndürür.
bol1: true bolum: bol1 bol2 echo $? bol2: true
$< ifadesi sadece ilk bağımlılığı almak için kullanılır.
bol1 bol2: true bolum: bol1 bol2 echo $<
Eğer xxxx.o şeklinde bir kural tanımlarsanız bu kural çalıştırıldıktan sonra gcc ile kural adındaki dosya derlenir.
main: main.o main.o: main.c test.c main.c: echo "int main(){}" > main.c %.c: touch $@
Burada main.c dosyası var olmayan bir dosyadır ve derleme esnasında oluşturulur. test.c dosyası ise daha önceden var olan bir dosyadır ve o dosyaya bir şey yapılmaz. main.c kuralı sadece main.c için çalıştırılırken %.c şeklinde belirtilen kular hem main.c hem test.c için çalıştırılır. main ile belirttiğimiz kuralda main.o bağımlılığı olduğu için bi derlemenin sonucu olarak main adında bir derlenmiş dosya üretilmektedir.
Wildcard ifadesi eşleşen dosyaları döndürür.
files := $(wildcard *.c) main: gcc -o main $(files)
Shell ifadesi ise komut çalıştırarak sonucunu döndürür.
files := $(shell find -type f -iname "*.c") main: gcc -o main $(files)
make -C xxx şeklinde alt dizindeki bir makefile dosyasını çalıştırabilirsiniz.
build: make -C src
Ayrıca include kullanarak başka bir dosyada bulunan kuralları kullanabilirsiniz.
# Makefile dosyası include build.mk build: main gcc main.c -o main # build.mk dosyası main: echo "int main(){return 0;}" > main.c
ifeq ifadesi ile koşul tanımlanabilir. aşağıdaki ifadeşi make CC=clang şeklinde çalıştırırkanız clang yazdırır, parametresiz bir şekilde çalıştırırsanız gcc yazdırır. Burada dikkat edilmesi gereken konu ifeq, else, endif girintilenmeden yazılır.
build: ifeq ($(CC),clang) echo "clang" else echo "gcc" endif
Eğer komutun başına @ işareti koyarsanız komut ekrana yazılmadan çalıştırılır. - yazarsanız komut hata alsa bile geri kalan kısımlar çalışmaya devam eder.
build: @echo "Merhaba dünya" -gcc main.c -o main
Bash betiklerinde kullandığımız for ve while yapısı makefile yazarken aşağıdaki gibi kullanılabilir. done dışındaki satırların sonuna \ işareti eklenir, do dışındaki satırların sonuna da ; işareti koyulur.
build: @for sayi in 1 2 3 $(dizi) ; do \ echo $$sayi ; \ echo "diger satir" ; \ done
SHELL değişkeni makefile altındaki komutların hangi shell kullanılarak çalıştırılacağını belirtir. Varsayılan değeri /bin/sh olarak belirlenmiştir. Örneğin debian tabanlı dağıtımlarda /bin/sh konumu /bin/dash bağlıyken archlinuxta /bin/bash bağlıdır. dash [[ kullanımını desteklemezken bash destekler. Bu sebeple uyumluluğu arttırmak için SHELL değişkenini zorla /bin/bash olarak değiştirebiliriz. Aşağıdaki örnekle konuyu daha iyi anlamak için SHELL değişkenini python3 ayarladık ve python kodu yazdık.
SHELL=/usr/bin/python3 build: import os ;\ liste = os.listdir("/") ;\ print(liste[0])