Giriş

Bu yazı serisinde sizlere nasıl appimage dosyası yapılacağı anlatılacakdır.

İlk bölümde çalıştırılabilir dosyaların sistemden bağımsız çalıştırılması üzerinde durulacaktır. Bu bölümü net bir şekilde anlayabilmeniz için orta düzeyde gnu/linux bilgisine sahip olmalısınız.

Static ve dynamic binary kavramı

Static olarak derlenmiş bir kod herhangi bir ek kütüphaneye ihtiyaç duymadan çalışabilir. Bir dosyanın static olup olmadığını anlamak için ldd komutu ile o dosyaya bakmamız gerekir.

$ ldd /bin/bash
linux-vdso.so.1 (0x00007ffc8f136000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007ff10adcd000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff10adc7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff10ac02000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff10af6c000)

Burada görüldüğü gibi dosyamız dynamic olarak derlendiği için bağımlılıkları listelenmektedir. Eğer dosyamız static olarak derlenseydi aşağıdaki gibi bir çıktı elde etmemiz gerekirdi.

$ ldd test.bin
not a dynamic executable

libc ve interpreter kavramı

Dynamic olarak derlenmiş bütün dosyalar temelde libc.so.6 ve ld-linux-x86-64.so.2 bağımlılıklarına ihtiyaç duyar. Bu dosyalardan libc.so.6 temel C kütüphanesidir. Bu kütüphane sayesinde program temel işlevlerini yerine getirebilir hale gelir. ld-linux-x86-64.so.2 ise interpreter olup dosyanın ne şekilde çalıştırılacağını belirler. Bir dosyanın hangi interpreter ile çalıştığını bulmak için file komutundan yararlanabiliriz. linux-vdso.so.1 ise kernel tarafından sağlanır ve herhangi bir dosya şeklinde bulunmaz.

$ file /bin/bash
/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked,
interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped

LD_LIBRARY_PATH kavramı

Bir çalıştırılabilir dosyanın bağımlılığı genellikle sistemde kurulu bulunmalıdır. Fakat bazı durumlarda sistem dizinlerinden farklı bir yerde bulunması gerekebilir. Bu gibi durumlarda LD_LIBRARY_PATH çevresel değişkeni tanımlanarak kütüphanenin aranacağı ek dizinin konumu belirtilir.

$ ldd test.bin
linux-vdso.so.1 (0x00007ffc1c5c5000)
libtest.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007feaab862000)
/lib64/ld-linux-x86-64.so.2 (0x00007feaaba76000)

Yukarıdaki örnekte libtest.so dosyası sistemde bulunamadığı için ldd çıktımızda uyarı ile karşılaştık. Şimdi de çevresel değişkenimizi tanımlayarak aynı işlemi tekrar deneyelim.

$ export LD_LIBRARY_PATH=/home/user/test/libs/
$ ldd test.bin
linux-vdso.so.1 (0x00007ffe22bbc000)
libtest.so => /home/user/test/libs/libtest.so (0x00007f4c97790000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4c97583000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4c9779c000)

Gördüğünüz gibi kütüphaneyi tanımladığımız dizinde buldu.

Bu şekilde bir dosyanın bütün bağımlılıklarını bir dizine kopyalarsak o dosyayı sistemden bağımsız şekilde çalıştırmamız mümkün olur.

$ ldd /bin/bash
linux-vdso.so.1 (0x00007fff2c359000)
libreadline.so.8 => /lib64/libreadline.so.8 (0x00007fce1e004000)
libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007fce1dfc5000)
libc.so.6 => /lib64/libc.so.6 (0x00007fce1ddcc000)
libtinfow.so.6 => /lib64/libtinfow.so.6 (0x00007fce1dd8c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fce1e154000)
# Şimdi tüm dosyaları libs adındaki bir dizine kopyalayalım.
$ mkdir libs
$ ldd /bin/bash | cut -f3 -d" " | grep "^/" | sed "s/.*/install & libs\//g" | sh
# Bağımlılıkları toplu olarak kopyalamak için yukarıdaki komutu kullanabilirsiniz.
$ ls libs
libc.so.6  libreadline.so.8  libtinfo.so.6  libtinfow.so.6
# Şimdi çevresel değişkenimizi tanımlayalım.
export LD_LIBRARY_PATH=/home/user/test/libs/
$ ldd /bin/bash
linux-vdso.so.1 (0x00007ffdeddc6000)
libreadline.so.8 => /home/user/test/libs/libreadline.so.8 (0x00007fd9ce7ea000)
libtinfo.so.6 => /home/user/test/libs/libtinfo.so.6 (0x00007fd9ce7ab000)
libc.so.6 => /home/user/test/libs/libc.so.6 (0x00007fd9ce5b2000)
libtinfow.so.6 => /home/user/test/libs/libtinfow.so.6 (0x00007fd9ce572000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd9ce926000)

Yukarıdaki örnekte bütün bağımlılıkları sistemdeki konumundan çekip ayrı bir dizine kopyaladık ve bu dizinden kullanmasını sağladık. Burada dikkat ettiyseniz interpreter kopyalamadık. Bunun sebebi interpreter dosyayı çalıştırdığımızda dosya tarafından çağırılır. Bu durumun üstesinden gelmek için interpreter ve çalıştırılacak dosyayı da kopyalayalım ve aşağıdaki gibi çalıştıralım.

$ install /bin/bash ./
$ install /lib64/ld-linux-x86-64.so.2 ./
$ ./ld-linux-x86-64.so.2 --library-path "/home/user/test/libs/" ./bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
...

Artık programımızı herhangi bir sistemde bütün bağımlılıkları ile birlikte çalıştırmamız mümkün hale geldi.

Yazımızın devamına buradan ulaşabilirsiniz.