Statik ve Dinamik Kütüphanelerin Beraber Kullanılması

Bazı kütüphanelerin hem statik hem de dinamik halleri bulunabilmektedir. Bağlayıcı seçim olanağı varsa dinamik kütüphaneleri seçmektedir. Örneğin, kütüphanenin -lXXX şeklinde gösterilmesi durumunda, bağlayıcı libXXX.a dosyasını değil libXXX.so dosyasını seçmektedir.

Bazı durumlarda dinamik kütüphaneler yerine statik hallerini kullanmayı tercih edebiliriz. Bir örnek üzerinden bu durumu inceleyelim.

driver.c:

void foo();
void bar();

int main() {
    foo();
    bar();
    return 0;
}

foo.c:

void foo() {
    puts(__func__);
}

bar.c:

void bar() {
    puts(__func__);
}

foo ve bar için sırasıyla statik ve dinamik kütüphaneler oluşturalım.

$ gcc -c foo.c
$ gcc -c bar.c
$ ar rcs libfoo.a foo.o
$ ar rcs libbar.a bar.o
$ gcc -fPIC -shared -olibfoo.so foo.c
$ gcc -fPIC -shared -olibbar.so bar.c

Uygulamayı aşağıdaki gibi derlediğimizde kütüphanelerin dinamik hallerinin seçildiğini görmekteyiz.

$ gcc -odriver driver.c -L. -lfoo -lbar
$ readelf -d driver | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libfoo.so]
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Statik kütüphanelerin seçilmesi için aşağıdaki yöntemler uygulanabilir.

1. Kütüphane ismi tam adıyla kullanılabilir.

$ gcc -odriver driver.c -L. libfoo.a -lbar
$ readelf -d driver | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

2. gcc, -static seçeneği kullanılabilir.

$ gcc -odriver driver.c -L. -lfoo -lbar -static
$ readelf -d driver | grep NEEDED

Bu durumda uygulamanın dinamik bir bağımlılığı olmadığını görüyoruz. Bu seçeneğin kullanılabilmesi için tüm kütüphanelerin statik hallerinin bulunması gerekmektedir. Bu durumu test etmek için bar kütüphanesinin statik halinin olmadığını varsayalım, libbar.a dosyasını silip uygulamayı yeniden derlemeye çalışalım.

$ rm libbar.a
$ gcc -odriver driver.c -L. -lfoo -lbar -static
/usr/bin/ld: cannot find -lbar
collect2: error: ld returned 1 exit status

Bağlayıcının yaptığı işlemlere daha yakından bakmak için --verbose seçeneğini kullanabilirsiniz.

$ gcc -odriver driver.c -L. -lfoo -lbar -static -Wl,--verbose | grep libfoo.a
attempt to open ./libfoo.a failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/4.9/libfoo.a failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libfoo.a failed
attempt to open /usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib/libfoo.a failed
...

Bağlayıcının libfoo.a dosyasını bulamadığını ve nerelerde arama yaptığını görmekteyiz.

3. Tüm uygulamayı statik olarak derlemek yerine, bağlayıcının istenilen kütüphanelerin statik hallerini kullanması sağlanabilir. Statik halleri kullanılmak istenen kütüphaneler -Wl,-Bstatic -lXXX -lYYY -Wl,-Bdynamic şeklinde gösterilebilir. Bu durumda foo kütüphanesinin statik, bar kütüphanesinin ise dinamik halini kullanabiliriz.

$ gcc -odriver driver.c -L. -Wl,-Bstatic -lfoo -Wl,-Bdynamic -lbar
$ readelf -d driver | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libbar.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Bağlayıcı Bstatic seçeneğini gördüğünde Bdynamic seçeneğini görene kadar yalnız statik kütüphaneleri kullanmaktadır, statik kütüphane bulunamaması durumunda dinamik hali kullanılmamaktadır.

Last updated