GNU Make ile Açık Kaynak Yazılım Geliştirmede 'Makefile'lara Kısa Bir Giriş


GNU Make, belirli bir kod tabanının yeniden derlenecek kısımlarını belirleyen ve bu işlemleri kod tabanında gerçekleştirmek için komutlar verebilen bir geliştirme yardımcı programıdır. Bu özel make yardımcı programı, derlemelerinin komutlar verilerek kabuktan yapılabilmesi koşuluyla herhangi bir programlama diliyle kullanılabilir.

GNU Make'i kullanabilmek için, programımızdaki farklı dosyalar arasındaki ilişkiyi tanımlayan bazı kurallara ve her dosyayı güncellemeye yönelik komutlara ihtiyacımız var. Bunlar 'makefile' adı verilen özel bir dosyaya yazılır. 'make' komutu, karar vermek için 'makefile' veri tabanını ve dosyaların son değiştirilme zamanlarını kullanır. tüm dosyaların yeniden derlenmesi gerekiyor.

Bir Makefile'ın içeriği

Genellikle 'makefiles' 5 tür şey içerir: örtük kurallar, açık kurallar, değişken tanımları , yönergeler ve yorumlar.

  1. Açık bir kural, bir veya daha fazla dosyanın (hedef adı verilen, daha sonra açıklanacaktır) nasıl oluşturulacağını/yeniden oluşturulacağını ve aynı şeyin ne zaman yapılacağını belirtir.
  2. Örtülü kural, bir veya daha fazla dosyanın adlarına göre nasıl oluşturulacağını/yeniden oluşturulacağını belirtir. Bir hedef dosya adının, hedefe benzer ada sahip bir dosyayla nasıl ilişkili olduğunu açıklar.
  3. Değişken tanımı, daha sonra değiştirilecek bir değişkenin dize değerini belirten bir satırdır.
  4. Direktif, make dosyasını okurken özel bir şey yapmak için kullanılan bir talimattır.
  5. '#' sembolü, makefiles içindeki bir yorumun başlangıcını temsil etmek için kullanılır . '#' ile başlayan satırlar dikkate alınmaz.

Makefile'ların Yapısı

make'e bir sistemin nasıl yeniden derleneceğini söyleyen bilgiler, makefile adı verilen veri tabanının okunmasından gelir. Basit bir makefile aşağıdaki söz dizimindeki kurallardan oluşur:

target ... : prerequisites ... 
	recipe 
... 
...

Hedef, program tarafından oluşturulan çıktı dosyası olarak tanımlanır. Aşağıda açıklanacak olan sahte hedefler de olabilir. Hedef dosyalara örnek olarak yürütülebilir dosyalar, nesne dosyaları veya temiz gibi sahte hedefler verilebilir. yükleme, kaldırma vb.

Önkoşul, hedef dosyaları oluşturmak için girdi olarak kullanılan bir dosyadır.

Tarif, make'in önkoşullara göre hedef dosyayı oluşturmak için gerçekleştirdiği eylemdir. Başka bir karakteri önek olarak tanımlamak için '.RECIPEPREFIX' değişkenini belirtmediğimiz sürece, makefiles içindeki her tarifin önüne sekme karakteri koymak gerekir. yemek tarifi.

Örnek bir Makefile

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f main.o end.o inter.o start.o

Yukarıdaki örnekte, çalıştırılabilir final'i oluşturmak için 4 C kaynak dosyalarını ve iki başlık dosyasını kullandık. Burada her '.o' dosyası, makefile içinde hem bir hedef hem de bir önkoşuldur. Şimdi temiz son hedef adına bir göz atın. Bu bir hedef dosyadan ziyade yalnızca bir eylemdir.

Normalde derleme sırasında buna ihtiyacımız olmadığı için başka hiçbir kuralda ön koşul olarak yazılmamıştır. Dosyalara atıfta bulunmayan ancak yalnızca eylemlerden oluşan hedeflere sahte hedefler denir. Diğer hedef dosyalar gibi herhangi bir önkoşulları olmayacaktır.

GNU Make bir Makefile dosyasını nasıl işler?

Varsayılan olarak make, 'makefile' içindeki ilk hedefle başlar ve ' olarak adlandırılır. varsayılan hedef'. Örneğimize göre ilk hedefimiz final'dir. Önkoşulları diğer nesne dosyalarını içerdiğinden, final oluşturulmadan önce bunların güncellenmesi gerekir. Bu ön koşulların her biri kendi kurallarına göre işlenir.

Yeniden derleme, kaynak dosyalarında veya başlık dosyalarında değişiklikler yapılmışsa veya nesne dosyası hiç mevcut değilse gerçekleşir. Gerekli nesne dosyalarını yeniden derledikten sonra make, son'u yeniden bağlayıp bağlayamayacağına karar verir. final dosyası mevcut değilse veya nesne dosyalarından herhangi biri ondan daha yeniyse bu işlemin yapılması gerekir.

Bu nedenle, inter.c dosyasını değiştirirsek, make çalıştırıldığında kaynak dosyayı güncellemek üzere yeniden derleyecektir. inter.o nesne dosyasını kullanın ve ardından final'i bağlayın.

Makefiles içindeki değişkenleri kullanma

Örneğimizde, aşağıda gösterildiği gibi final kuralında tüm nesne dosyalarını iki kez listelemek zorunda kaldık.

final: main.o end.o inter.o start.o
	gcc -o final main.o end.o inter.o start.o

Bu tür tekrarları önlemek amacıyla, makefile içinde kullanılan nesne dosyalarının listesini saklayacak değişkenler tanıtabiliriz. OBJ değişkenini kullanarak makefile örneğini aşağıda gösterilene benzer şekilde yeniden yazabiliriz.

OBJ = main.o end.o inter.o start.o
final: $(OBJ)
	gcc -o final $(OBJ)
main.o: main.c global.h
	gcc -c main.c
end.o: end.c local.h global.h
	gcc -c end.c
inter.o: inter.c global.h
	gcc -c inter.c
start.o: start.c global.h
	gcc -c start.c
clean:
	rm -f $(OBJ)

Kaynak dizini temizleme kuralları

makefile örneğinde gördüğümüz gibi, derleme sonrasında istenmeyen nesne dosyalarını kaldırarak kaynak dizinitemizlemek için kurallar tanımlayabiliriz. temiz adında bir hedef dosyamız olduğunu varsayalım. Yukarıdaki iki durumu nasıl ayırt edebiliriz? Burada sahte hedefler kavramı ortaya çıkıyor.

Sahte hedef aslında bir dosyanın adı olmayan, yalnızca makefile<'den açık bir istek yapıldığında yürütülecek bir tarifin adıdır.. Sahte hedef kullanmanın ana nedenlerinden biri, aynı addaki bir dosyayla çakışmayı önlemektir. Diğer bir neden ise performansı artırmaktır.

Bu şeyi açıklamak için beklenmedik bir gelişmeyi açığa çıkaracağım. temiz tarifi, make çalıştırıldığında varsayılan olarak yürütülmeyecektir. Bunun yerine make clean komutunu vererek aynı şeyi çağırmak gerekir.

.PHONY: clean
clean:
	rm -f $(OBJ)

Şimdi kendi kod tabanınız için makefiles oluşturmaya çalışın. Şüpheleriniz varsa buraya yorum yapmaktan çekinmeyin.