makefile ile derleme -3

Kodlarımızı daha verimli bir şekilde derlemek için bazı değişiklikler yapmak gerekiyor.


Adım3: object dosyalarını kullanma

Daha verimli ile kastım, tüm dosyaları baştan derlemek yerine sadece değişen dosyaları derlemek.
Şu anki projemizde 2 c kodu var belki ama çok daha fazla sayıda kaynak kodu olduğunda, birinde yapılan değişiklik için hepsini derlemek mantıklı bir iş olmayacaktır.
makefile dosyasında bir kaç küçük değişiklik yapmak gerekiyor.


CC=gcc
CFLAGS=-I.

hellomake: hellomake.o hellofunc.o

@echo merhaba
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)

Önce derleyici .exe dosyasının adını CC makrosuna yazıyoruz. Böylece ileride derleyiciyi değiştirmek istediğimizde sadece bu kısmı değiştiriyoruz. Bu standart bir kullanım olduğundan, başka biri tarafından yazılan makefile'ın derleyicisini değiştirmek isteyince öncelikle yapacağımız yine bu satırı değiştirmek.

Sonra derleyici bayraklarını? (compiler flags) CFLAGS makrosuna giriyoruz. Daha önceden -I ile include edilecek dizinleri tanımlamıştık mesela. Onu buraya taşıyoruz.

Sonraki satırda ise bir öncekinden farklı olarak kaynak kodlarını değil object dosyalarını yazıyoruz. Böylece eğer kaynak kodlarımız değişmediyse onlar derlenerek tekrardan .o dosyaları üretilmiyor, sadece .o dosyaları linklenerek .exe dosyası oluşturuluyor.

Araya tek satırlık echo ekledim. oraya ne yazarsak, makefile çalışırken ekrana bastırılacak.

son satır işletilirken zaten ekrana komutlar basıldığında
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
şeklinde değil
gcc -o hellomake hellomake.o hellofunc.o -I.
şeklinde basıldığını görebiliyoruz.

make uygulamasını çalıştırdığımızda, .o dosyalarının oluşturulduğunu dizinde görüyoruz.
*.c dosyalarını değiştirmeden make.exe'yi tekrardan çağırırsak, .o dosyaları da değişmiyor, sadece .exe dosyasının tekrar üretildiğini (tarihi değişiyor) ve derlemenin daha kısa sürede tamamlandığını görüyoruz.
.c dosyasından birini değiştirirsem, sadece onun .o dosyasının değiştiğini ve .exe'nin tekrar üretildiğini görüyoruz.

Böylece amacımıza ulaşmış olduk.

Ancak burada şu eksik, kaynak kodu dosyalarının (*.c) değişmesini ele aldım ancak header dosyaları (*.h) için herhangi bir şey yapmadık.

Adım 4: Header dosyası ve yeni makrolar


Şimdilik bir başlık bulamadım.
Şimdiki adımda hem header dosyalarını işin içine sokmak için hem de object dosyalarını tek yerden yazmak için makrolar tanımlayacağız.

Bu arada değişiklik yaptıktan sonra denemeler yaparken .o dosyalarını siliyorum ki baştan oluşturulsunlar. yoksa onlar .c dosyaları değişmediği için değişmeyebilir ve yaptığım bir hatayı anlamayabilirim.

En basitinden, 3. satır olarak object dosyalarını tanımlasam sonra da bir sonraki satırda object dosyalarının ismini yazmak yerine bu makroyu yazsam çalışacaktır.
OBJ = hellomake.o hellofunc.o 
hellomake: $(OBJ)

Sonra header dosyalarını DEPS diye bir makroda tanımlayıp bunun için de bir kural (rule) tanımlıyorum.

DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

Böylece önce *.c dosyalarının bağlandığı .h dosyalarının bulunduğu DEPS makrosu oluşuyor. Sonrasında .o ile biten tüm dosyalar için kural oluşturuyoruz. Bu kural, .o dosyası dosyaının .c versiyonuna ve DEPS'te tanımlanan .h dosyasına bağlı olduğunu söylüyor. Sonrasında da CC makrosunda belirtilen derleyici ile .c dosyasını derleyerek .o dosyasının oluşturulacağını belirtiyor.

"-c" bayrağı (compile and ensamble) object dosyasının oluşturulmasını, "-o $@" derleme çıktısının ":" öncesindeki dosyaya atılmasını (place the output into), "$<" DEPS'teki ilk elemanı ifade ediyor (benim linkteki yazıdan anladığım).

Şimdi .h dosyasını değiştirerek tekrardan make çalıştırırsam .o dosyalarının tekrardan oluşturduğunu görebileceğim.

Burada son adım olarak son satırın düzenlenmesi var.
hellomake: $(OBJ)
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
yerine
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
giriyoruz
burada, "$@", ":" öncesindeki "$^" da ":" sonrasındaki ifade yerine kullanılıyor.
":" öncesinde "hellomake" kelimesi olduğu için, alt satırda "$@" onun yerine geçecek.
":" sonrasında "$OBJ" makrosu olduğu için alt satırda "$^" onun yerine geçecek. Yukarıda da OBJ olarak o iki .o dosyasını tanımladığımdan aynı şeyi elde etmiş oluyorum.

makefile'ın son hali:

CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
OBJ = hellomake.o hellofunc.o 

%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
@echo merhaba
$(CC) -o $@ $^ $(CFLAGS)

Peki geriye ne kaldı? Benim asıl bu işe başlama amacım olan farklı dosyaları farklı dizinlere taşıma işi. Yani .c dosyaları bir yerde, .h dosyaları bir yerde. 

Bir de baştan temiz bir build yapmak için .o dosyalarını silmek adına bir clean kuralı yazmak. Sadece make yazdığımızda gidip ilk kuralı çalıştırıyordu. Şimdi make yanına başka argümanlar ekleyerek farklı kurallar çalıştırmayı da öğreneceğiz diye umuyorum.



Yorumlar

Bu blogdaki popüler yayınlar

Nasıl yazılır

makefile ile derleme -2