Statik Kütüphaneler
Statik kütüphaneleri incelemeden önce bir C kodunun çalıştırılabilir hale gelene kadar geçtiği aşamalara kısaca bakalım.
test.c adıyla sakladığımız basit bir örneği, gcc uygulamasına --save-temps anahtarını geçirerek, aşağıdaki gibi derleyebiliriz.
--save-temps anahtarı ile derleyicinin ürettiği ara kodlar uygun ad ve uzantılarla dosya sistemine kaydedilmektedir. test.c için derleyici aşağıdaki dosyaları üretecektir.
Dosya Adı
İçerik
test.i
Önişlemcinin ürettiği kod
test.s
Derleyicinin ürettiği sembolik makina kodları
test.o
Gerçek makina kodlarını içeren ELF formatlı amaç kod
test
Çalıştırılabilir ELF formatlı kod
Bir C kodu çalıştırılabilir hale gelene kadar, temel olarak, aşağıdaki aşamalardan geçmektedir.
Önişlem aşaması
Derleyeci tarafından sembolik makina kodlarının üretilmesi
Assembler tarafından gerçek makina kodlarının üretilmesi
Bağlayıcı tarafından çalıştırılan dosyanın üretilmesi
Not: Komut satırından kullandığımız gcc uygulaması aslında derleyici değil, derleme sürecinde gerekli olan uygulamaları uygun sıra ve parametrelerle çağıran bir sürücü (driver) programdır.
Fakat çoğu zaman detaya girmeden bütün süreçten derleme işlemi olarak bahsedeceğiz.
Bağlayıcı .o uzantılı amaç dosyaları (object file) birleştirerek nihai çalıştırılabilir dosyayı oluşturmaktadır. Bu durumda ihtiyaç duyulacak tüm fonksiyonları tek bir amaç dosyada toplamak mümkündür. Bir önceki örnek kodumuza foo fonksiyonu çağrısını eklediğimizi ve foo ile beraber diğer tüm fonksiyon tanımlarının liball.o amaç dosyasında olduğunu varsayalım.
Kodu aşağıdaki gibi derleyebiliriz.
Bu yöntemde bir problemle karşılaşmaktayız, bağlayıcı tarafından, liball.o içeriğinin tamamı çalışabilir dosyaya kopyalanacak ve test uygulaması gereksiz yere büyüyecektir. Diğer bir alternatif ise birbiriyle ilişkili olduğu düşünülen fonksiyonları aynı amaç dosyada toplamak olabilir. Tek bir liball.o yerine lib1.o, lib2.o,..., libN.o dosyalarına sahip olduğumuzu ve foo tanımının lib1.o içinde olduğunu kabul edelim. Bu durumda daha küçük bir çalışabilir kod elde etmek mümkündür.
Fakat bu yöntemde de çok sayıda amaç dosyayı yönetmek zorlaşacaktır. Hangi fonksiyonun hangi amaç dosya içinde olduğu bilinmeli ve çoğu durumda komut satırına birden çok amaç dosya geçirilmelidir.
Statik kütüphaneler bu problemleri gidermek için geliştirilmiştir. Birbiriyle ilişkili olan fonksiyonları içeren amaç dosyalar tek bir dosya halinde arşivlenerek saklanmaktadır. Statik kütüphane içinden yalnız gerekli amaç dosyalar çalıştırılabilir koda kopyalanmaktadır. Statik kütüphane oluşuturmak için Linux altında ar aracı kullanılmaktadır. Örnek bir statik kütüphane aşağıdaki gibi oluşturulabilir.
Kütüphane dosyalarına, bir zorunluluk olmamasına karşın geleneksel olarak, .a (archive) uzantısı verilmektedir. Şimdi statik kütüphane kullanımı göstermek için basit bir örnek yapalım.
Örnek Kütüphane Kullanımı
Aşağıdaki örnek kodları sırasıyla test.c, foo.c ve bar.c isimleriyle saklayalım.
foo.c ve bar.c dosyalarını kullanarak statik bir kütüphaneyi aşağıdaki gibi oluşturabiliriz. gcc uygulamasına geçirilen -c (compile) anahtarı, amaç dosyalar oluşturulduktan sonra bağlayıcının çağrılmasını engelemektedir.
test.c adıyla sakladığımız uygulamamız, foo fonksiyonun tanımına gereksinim duymaktadır. Kütüphane dosyamızı gcc uygulamasına geçirerek uygulamamızı derleyebilir ve çalıştırabiliriz. Bu örnek için kütüphane dosyasının çalıştığımız dizinde olduğunu varsayıyoruz.
Daha önce kütüphane içinden yalnız gerekli modüllerin çalışabilir dosyaya kopyalandığını söylemiştik. Bu durumda yalnız, foo fonksiyonunun tanımının bulunduğu, foo.o dosyasının test uygulamasına kopyalanmasını bekliyoruz. test uygulaması içindeki sembollere bakarak bu durumu gözleyebiliriz. Bu amaçla nm uygulamasını kullanabiliriz.
nm çıktısındaki T (Text) harfi, fonksiyon tanımının dosya içinde bulunduğunu göstermektedir. Uygulama içinde bar fonksiyonuna ilişkin herhangi bir sembol dolayısıyla taşınmış kod bulunmamaktadır.
Burada bir noktaya dikkatinizi çekmek istiyoruz. Statik kütüphanelerin komut satırındaki sıralaması önem taşımaktadır. Aynı örneği şimdi kütüphane dosyasını uygulama kodundan daha önce geçirerek derleyelim. Bu durumda aşağıdaki gibi bir hata ile karşılaşmaktayız.
foo fonksiyonunun tanımı liball.a içinde bulunmasına karşın, bağlayıcı bize foo fonksiyonunun tanımını bulamadığından şikayet etmekte. Bağlayıcı komut satırında gösterilen dosyaları sırasıyla okumakta ve tanımını bulamadığı referansları, daha sonra çözümlemek üzere, kaydetmektedir. Bağlayıcı tanımsız bir referans gördüğünde bunu daha sonra gördüğü dosyalarda aramakta, geriye doğru bir arama yapmamaktadır. Hata aldığımız örnek için bağlayıcı foo çağrısıyla karşılaştığında, kütüphane dosyası üzerinden zaten geçtiği için foo fonksiyonunun tanımını bulamamaktadır. Böyle bir durumda bağlayıcı istenilen sembolleri aramaya zorlanabilir. undefined anahtarı ile tanımı aranacak referansı açık bir şekilde geçirebiliriz.
Not: gcc'ye geçirilen Wl anahtarı devam eden anahtarların bağlayıcıya geçirileceğini göstermektedir.
Last updated
Was this helpful?