Make'i Anlamak

August 1, 2026 · ziyaretçi

make, dokunduğum neredeyse her gömülü ve sistem projesinde karşıma çıkıyor — Yocto tarifleri, kernel build'leri, U-Boot, küçük firmware repoları. Aynı zamanda insanların yıllarca taklit yoluyla kullandığı araçlardan biri: bir önceki projeden bir Makefile kopyalanır, altındaki modele hiç tam oturmadan. İşte o model, doğrudan ortaya serilmiş haliyle.

Make Nedir?

Make bir build otomasyon aracıdır: bir dizi hedef (target), her hedefin bağlı olduğu ön koşullar (prerequisites) ve o hedefi ön koşullarından üretmek için gereken tarifi (recipe, shell komutları) tanımlayan bir dosyayı (Makefile) okur. Bu tanım verildiğinde, make hangi hedeflerin güncelliğini yitirdiğini bulur ve onları güncellemek için gereken tarifleri çalıştırır — fazlasını değil.

main: main.o utils.o
	gcc -o main main.o utils.o

main.o: main.c
	gcc -c main.c

make çalıştırıldığında, main.o'yu yalnızca main.c, main.o'dan daha yeniyse (veya main.o henüz yoksa) derler, ardından main'i yalnızca main.o veya utils.o değiştiyse link eder. Hiçbir şey gereksiz yere yeniden derlenmez.

Kimin İçin?

Make, Nisan 1976'da Bell Labs'ta Stuart Feldman tarafından yazıldı. Kendi anlatımına göre, tetikleyici bir meslektaşıydı — yacc'ın yazarı Steve Johnson — aslında doğru olan bir programı debug etmeye çalışırken bir sabahı kaybetmişti; binary, kaynak koddaki bir değişiklikten sonra basitçe yeniden link edilmemişti. Feldman bunun için 2003 ACM Software System Award'ını aldı. O öğleden sonra ortaya çıkan araç — bağımlılıkları bir kere takip et, neyin yeniden yapılması gerektiğini makinenin bulmasına izin ver — yazılım araçlarında en çok kopyalanan fikirlerden biri haline geldi. Bugün neredeyse herkesin kullandığı sürüm olan GNU Make, GNU Project'in ücretsiz bir yeniden implementasyonudur (1) (5) (6).

Pratikte, önemsiz olmayan bir çıktıyı — derlenmiş bir binary, bir belge, üretilmiş dosyalardan oluşan bir set — daha küçük parçalardan bir araya getiren ve her değişiklikte her şeyi sıfırdan yeniden inşa etmenin israf veya yavaş olacağı herkes için bir araçtır. Bu, C/C++ projelerini, kernel ve bootloader build'lerini, LaTeX belgelerini ve kod derlemeyle hiç ilgisi olmayan bir sürü ad-hoc otomasyonu kapsar.

Ne Zaman Kullanmalısın?

Make, üç şey aynı anda doğru olduğunda karşılığını verir:

Birbirine bağımlılığı olmayan bir avuç dosya için, bir shell script genellikle daha basit ve daha dürüsttür. Make, "bu gerçekten yeniden derlenmesi gerekiyor muydu?" sorusu elle değil otomatik olarak sorulmaya değer bir soru haline geldiğinde karşılığını vermeye başlar.

Araç Zincirinde Nerede Duruyor?

Make genellikle derleyicinin bir katman üstünde, bir insanın çalıştırdığı şeyin bir katman altında durur. Tipik bir C projesinde: kaynak dosyalar → (Make tarafından yönetilen derleyici) → nesne dosyaları → (Make tarafından yönetilen linker) → nihai binary. Make'in kendisi hiçbir şeyi derlemez veya link etmez — bunu yapan araçları, her tarifte shell komutları olarak çağırır.

Ayrıca daha üst seviye build-konfigürasyon araçlarının altında durma eğilimindedir. Örneğin CMake, Autotools ve Yocto'nun BitBake'i, Make'in yerini almaktan çok, gerçek çalıştırma backend'i olarak Makefile üretirler (veya eşdeğerini yönetirler). Yani sana hiçbir zaman doğrudan bir Makefile göstermeyen projeler bile genellikle pipeline'ın bir yerinde bir tane çalıştırıyordur.

Neden Bu Şekilde Çalışıyor?

Temel tasarım tercihi — neyin bayatladığına karar vermek için dosya değişiklik zamanlarını karşılaştırmak — Make'i büyük ağaçlarda hızlı yapan şeydir: bir zaman damgasını kontrol etmek ucuzdur, bu yüzden tek satırlık bir değişiklikten sonra devasa bir projenin yeniden derlenmesi neredeyse her şeyi atlayabilir ve yine de doğru olabilir — tabii ki kendisine verilen bağımlılık grafiği doğruysa.

Bu son cümlecik, insanların karşılaştığı neredeyse her "Make bozuk" şikayetinin kaynağıdır ve üzerinde durmaya değer: Make, kendisine anlatılan grafik kadar doğrudur, ne fazla ne az. Bir .c dosyası, karşılık gelen .o dosyasının ön koşulu olarak listelenmemiş bir header'ı #include ediyorsa, o header'ı düzenlemek bir yeniden derlemeyi tetiklemez — Make'in kafası karıştığı için değil, o bağımlılığın var olduğunu ona hiç kimse söylemediği için. Gerçek dünyadaki Makefile'ların neredeyse her zaman elle yazılmış header listeleri yerine derleyici tarafından üretilen bir bağımlılık adımıyla (-MMD -MP, GCC/Clang ile) eşleştirilmesinin nedeni de budur — derleyici gerçek include grafiğini zaten bilir, bu yüzden bunun için tek güvenilir kaynak odur (4).

Aslında Nasıl Çalışıyor?

Hedefler, ön koşullar, tarifler. Temel birim şudur:

target: prerequisite1 prerequisite2
	recipe line 1
	recipe line 2

Tarif satırları boşluk değil, tab ile girintilenmelidir — bugün hâlâ insanları tökezleten ünlü, tarihsel bir kusur.

Otomatik değişkenler tekrarı azaltır:

%.o: %.c
	gcc -c $< -o $@

$@ hedeftir, $< ilk ön koşuldur — tek başına bu pattern rule, dosya başına bir satır olmadan her .o'yu karşılık gelen .c dosyasından derleyebilir.

.PHONY hedefleri, gerçek dosyalara karşılık gelmeyen isimleri işaretler — clean, all, test — böylece o isimde bir dosya varsa Make'in kafası karışmaz ve zaman damgalarını kontrol etmek yerine tarifi her zaman çalıştırır: (2)

.PHONY: clean
clean:
	rm -f *.o main

Değişkenler, bayrakları her yerde tekrarlamaktan kaçınır ve projeler arası yeniden kullanımı kolaylaştırır:

CC = gcc
CFLAGS = -Wall -O2

main.o: main.c
	$(CC) $(CFLAGS) -c main.c

Otomatik bağımlılık üretimi, yukarıda tarif edilen boşluğu kapatır:

CFLAGS = -Wall -O2 -MMD -MP
-include $(wildcard *.d)

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

-MMD, derleyicinin her nesne için bir .d dosyası üretmesini sağlar; bu dosya o derleme sırasında gerçekten dahil edilen her header'ı listeler. -include, bu dosyaları Makefile'a geri katlar, böylece bağımlılık grafiği header'lar değiştikçe — kimse elle bakım yapmadan — doğru kalır (3).

Kapanış Düşüncesi

Make'in tuhaflığı gibi görünen şeylerin çoğu — zaman damgası karşılaştırmaları, tab konusundaki ısrar, eksik bir bağımlılığın yüksek sesle değil sessizce başarısız olma şekli — 1976'da alınan tek bir tasarım kararından doğar: modeli basit, kontrolü ucuz tut ve Makefile'ın gerçekliği doğru tarif ettiğine güven. Bu mercekten bakıldığında, çoğu "Make tuhaflaşıyor" anı aslında "ona verdiğim grafik eksikti" anlamına gelir — ki bu çok daha kolay düzeltilecek bir şeydir.

İlgili Yazılar

Kaynakça

  1. Feldman, S. I. (1979). Make — A Program for Maintaining Computer Programs. Software: Practice and Experience, 9(4), 255–265. — Feldman'ın Make'i tanıttığı, orijinal motivasyonu da içeren kendi makalesi.
  2. GNU Make Manual — GNU Make'in sözdizimi ve semantiği için eksiksiz, yetkin referans.
  3. GNU Make Manual: Automatic Prerequisites-MMD/-include deseni, bakımcıların kendi ifadeleriyle.
  4. GCC: Preprocessor Options (-M family)-MMD ve -MP'nin arka planda ne yaptığı.
  5. Make (software) — Wikipedia — Make implementasyonlarının (BSD Make, GNU Make, NMAKE vb.) genel tarihi ve soy ağacı.
  6. Stuart Feldman — Wikipedia — Feldman'ın Bell Labs'taki çalışmaları ve 2003 ACM Software System Award'ı hakkında arka plan bilgisi.

Yorumlar