Perbedaan antara objek yang dibagikan (.so), perpustakaan statis (.a), dan DLL (.so)?

273

Saya telah terlibat dalam beberapa perdebatan sehubungan dengan perpustakaan di Linux, dan ingin mengkonfirmasi beberapa hal.

Ini untuk pemahaman saya (tolong perbaiki saya jika saya salah dan saya akan mengedit posting saya nanti), bahwa ada dua cara menggunakan perpustakaan ketika membangun aplikasi:

  1. Pustaka statis (file .a): Pada waktu tautan, salinan seluruh pustaka dimasukkan ke dalam aplikasi akhir sehingga fungsi-fungsi di dalam pustaka selalu tersedia untuk aplikasi panggilan.
  2. Objek bersama (file .so): Pada waktu tautan, objek baru diverifikasi terhadap API-nya melalui file header (.h) yang sesuai. Perpustakaan tidak benar-benar digunakan sampai runtime, di mana dibutuhkan.

Keuntungan yang jelas dari perpustakaan statis adalah bahwa mereka memungkinkan seluruh aplikasi untuk mandiri, sedangkan manfaat perpustakaan dinamis adalah bahwa file ".so" dapat diganti (yaitu: jika perlu diperbarui karena keamanan bug) tanpa memerlukan aplikasi dasar untuk dikompilasi ulang.

Saya telah mendengar beberapa orang membedakan antara objek yang dibagikan dan pustaka tautan dinamis (DLL), meskipun keduanya adalah file ".so". Apakah ada perbedaan antara objek yang dibagikan dan DLL ketika datang ke pengembangan C / C ++ di Linux atau OS yang memenuhi POSIX lainnya (yaitu: MINIX, UNIX, QNX, dll)? Saya diberitahu bahwa satu perbedaan utama (sejauh ini) adalah bahwa objek yang dibagikan hanya digunakan saat runtime, sedangkan DLL harus dibuka terlebih dahulu menggunakan panggilan dlopen () dalam aplikasi.

Akhirnya, saya juga mendengar beberapa pengembang menyebutkan "shared arsip", yang, menurut pemahaman saya, juga merupakan perpustakaan statis sendiri, tetapi tidak pernah digunakan oleh aplikasi secara langsung. Sebagai gantinya, pustaka statis lain akan terhubung dengan "arsip bersama" untuk menarik beberapa (tapi tidak semua) fungsi / sumber daya dari arsip bersama ke pustaka statis yang sedang dibangun.

Terima kasih sebelumnya atas bantuan Anda.

Memperbarui


Dalam konteks di mana istilah-istilah ini diberikan kepada saya, itu istilah yang keliru secara efektif digunakan oleh tim pengembang Windows yang harus belajar Linux. Saya mencoba untuk memperbaikinya, tetapi norma-norma bahasa (salah) macet.

  1. Shared Object: Pustaka yang secara otomatis ditautkan ke program ketika program dimulai, dan ada sebagai file mandiri. Perpustakaan termasuk dalam daftar penautan pada waktu kompilasi (yaitu: LDOPTS+=-lmylibuntuk file perpustakaan bernama mylib.so). Perpustakaan harus ada pada waktu kompilasi, dan ketika aplikasi dimulai.
  2. Static Library: Suatu perpustakaan yang digabung ke dalam program aktual itu sendiri pada waktu membangun untuk satu aplikasi (lebih besar) yang berisi kode aplikasi dan kode perpustakaan yang secara otomatis ditautkan ke dalam suatu program ketika program dibangun, dan biner akhir berisi keduanya program utama dan perpustakaan itu sendiri ada sebagai file biner tunggal yang berdiri sendiri. Perpustakaan termasuk dalam daftar penautan pada waktu kompilasi (yaitu: LDOPTS+=-lmylibuntuk file perpustakaan bernama mylib.a). Perpustakaan harus ada pada waktu kompilasi.
  3. DLL: Pada dasarnya sama dengan objek bersama, tetapi bukannya dimasukkan dalam daftar tautan pada waktu kompilasi, pustaka dimuat melalui dlopen()/ dlsym()perintah sehingga pustaka tidak perlu ada pada saat membangun untuk mengkompilasi program. Juga, perpustakaan tidak perlu hadir (harus) pada startup aplikasi atau waktu kompilasi , karena hanya diperlukan pada saat dlopen/ dlsympanggilan dibuat.
  4. Shared Archive: Pada dasarnya sama dengan perpustakaan statis, tetapi dikompilasi dengan flag "export-shared" dan "-fPIC". Perpustakaan termasuk dalam daftar penautan pada waktu kompilasi (yaitu: LDOPTS+=-lmylibSuntuk file perpustakaan bernama mylibS.a). Perbedaan antara keduanya adalah bahwa bendera tambahan ini diperlukan jika objek bersama atau DLL ingin secara statis menghubungkan arsip bersama ke dalam kode sendiri DAN dapat membuat fungsi dalam objek bersama tersedia untuk program lain, daripada hanya menggunakannya internal ke DLL. Ini berguna jika seseorang menyediakan Anda dengan perpustakaan statis, dan Anda ingin mengemasnya kembali sebagai SO. Perpustakaan harus ada pada waktu kompilasi.

Pembaruan Tambahan

Perbedaan antara " DLL" dan " shared library" hanyalah sebuah percakapan sehari-hari (malas, tidak akurat) di perusahaan tempat saya bekerja (pengembang Windows dipaksa untuk beralih ke pengembangan Linux, dan istilah itu macet), mengikuti deskripsi yang disebutkan di atas.

Selain itu, " S" literal yang mengikuti nama perpustakaan, dalam kasus "arsip bersama" hanyalah sebuah konvensi yang digunakan di perusahaan itu, dan tidak di industri secara umum.

Awan
sumber
14
Untuk .afile, "a" sebenarnya singkatan dari "archove", dan itu hanyalah arsip dari file objek. Linker modern harus cukup baik untuk tidak perlu menyertakan perpustakaan sementara, hanya file objek dalam arsip yang diperlukan, dan bahkan mungkin hanya menggunakan bagian kode / data dalam file objek yang direferensikan.
Beberapa programmer dude
4
DLL hanyalah terminologi Windows. Itu tidak digunakan pada unices.
R .. GitHub BERHENTI MEMBANTU ICE
1
kemungkinan duplikat Mengapa pustaka tautan statis dan dinamis berbeda?
Tamás Szelei
2
Baca tldp.org/HOWTO/Program-Library-HOWTO
Basile Starynkevitch
2
@ EvNull "arch i ve" tentu saja. :)
Beberapa programmer Bung

Jawaban:

94

Saya selalu berpikir bahwa DLL dan objek bersama adalah istilah yang berbeda untuk hal yang sama - Windows menyebutnya DLL, sedangkan pada sistem UNIX mereka berbagi objek, dengan istilah umum - pustaka yang terhubung secara dinamis - mencakup keduanya (bahkan fungsi untuk buka .so pada UNIX disebut dlopen()setelah 'perpustakaan dinamis').

Mereka memang hanya ditautkan pada startup aplikasi, namun gagasan Anda tentang verifikasi terhadap file header salah. File header mendefinisikan prototipe yang diperlukan untuk mengkompilasi kode yang menggunakan pustaka, tetapi pada saat tautan linker melihat ke dalam pustaka itu sendiri untuk memastikan fungsi yang dibutuhkan benar-benar ada. Linker harus menemukan badan fungsi di suatu tempat pada waktu tautan atau itu akan menimbulkan kesalahan. Ini JUGA melakukannya saat runtime, karena ketika Anda menunjukkan perpustakaan itu sendiri mungkin telah berubah sejak program dikompilasi. Inilah sebabnya mengapa stabilitas ABI sangat penting dalam pustaka platform, karena perubahan ABI adalah apa yang merusak program yang ada dikompilasi terhadap versi yang lebih lama.

Perpustakaan statis hanyalah kumpulan file objek langsung dari kompiler, sama seperti yang Anda bangun sendiri sebagai bagian dari kompilasi proyek Anda, sehingga mereka ditarik dan diumpankan ke linker dengan cara yang persis sama, dan bit yang tidak digunakan adalah dijatuhkan dengan cara yang persis sama.

Matthew Walton
sumber
1
Mengapa beberapa proyek yang saya lihat di Linux harus menggunakan panggilan dlopen () untuk mengakses fungsi dalam file ".so", dan beberapa tidak harus melakukan itu sama sekali? Ngomong-ngomong, terima kasih!
Cloud
9
Mereka yang tidak melakukan itu mendapatkan fungsi yang diserahkan kepada mereka oleh pemroses proses, yaitu pemuat peri linux. dlopen ada jika aplikasi ingin membuka dan menggunakan .so atau .dll yang tidak ada di kompilasi atau hanya menambahkan fungsionalitas tambahan, seperti plugin.
rapadura
Tetapi bukankah aplikasi tidak dapat dikompilasi sama sekali jika .so tidak ada pada saat membangun? Apakah mungkin untuk memaksa linker untuk hanya membangun program terakhir tanpa .so ada sama sekali? Terima kasih.
Cloud
1
Saya percaya itu tergantung pada bagaimana Anda menggunakan fungsi dari. Jadi, tapi di sini pengetahuan saya tentang ini berhenti: / Pertanyaan bagus.
rapadura
1
Mengenai dlopen () dan keluarga fungsi-fungsinya, ini adalah pemahaman saya bahwa ini digunakan untuk secara terprogram membuka / menutup dll sehingga tidak harus dimuat dalam memori selama seluruh menjalankan aplikasi. Jika tidak, Anda harus memberi tahu tautan di argumen baris perintah (alias makefile Anda) bahwa Anda ingin pustaka dimuat. Ini akan dimuat saat runtime dan tetap dimuat dalam memori sampai aplikasi keluar. Ada lebih banyak hal yang dapat terjadi pada level OS, tetapi inilah kira-kira yang terjadi sejauh menyangkut aplikasi Anda.
Taylor Price
198

Sebuah perpustakaan statis (.a) adalah perpustakaan yang dapat dihubungkan langsung ke eksekusi akhir yang dihasilkan oleh linker, itu terkandung di dalamnya dan tidak ada kebutuhan untuk memiliki perpustakaan ke dalam sistem di mana eksekusi akan dikerahkan.

Sebuah shared library (.so) adalah perpustakaan yang terkait tetapi tidak tertanam dalam eksekusi akhir, sehingga akan dimuat ketika eksekusi diluncurkan dan kebutuhan untuk hadir dalam sistem di mana eksekusi ini digunakan.

Sebuah perpustakaan link dinamis pada windows (.dll) adalah seperti shared library (.so) di linux tetapi ada beberapa perbedaan antara dua implementasi yang berkaitan dengan OS (Windows vs Linux):

Sebuah DLL dapat menentukan dua macam fungsi: diekspor dan internal. Fungsi yang diekspor dimaksudkan untuk dipanggil oleh modul lain, serta dari dalam DLL di mana mereka didefinisikan. Fungsi internal biasanya dimaksudkan untuk dipanggil hanya dari dalam DLL di mana mereka didefinisikan.

Sebuah SO perpustakaan di Linux tidak perlu pernyataan ekspor khusus untuk menunjukkan simbol ekspor, karena semua simbol yang tersedia untuk proses menginterogasi.

aleroot
sumber
1
+1 penjelasan sederhana yang bagus. Jika fungsi dinyatakan "Internal" dalam DLL apakah itu berarti tidak dapat dipanggil dari luar perpustakaan?
Mike
23
Tidak selalu benar bahwa semua simbol tersedia di perpustakaan SO. Simbol tersembunyi dimungkinkan dan direkomendasikan karena tidak ada alasan bagi pengguna perpustakaan untuk melihat semua simbol Anda.
Zan Lynx
3
FYI: g ++ memiliki __attribute__sintaks untuk simbol 'ekspor' secara selektif:#define DLLEXPORT __attribute__ ((visibility("default"))) #define DLLLOCAL __attribute__ ((visibility("hidden")))
Brian Haak
33

Saya dapat menguraikan rincian DLL di Windows untuk membantu mengklarifikasi misteri itu kepada teman-teman saya di * NIX-land ...

DLL seperti file Objek Bersama. Keduanya adalah gambar, siap untuk dimuat ke dalam memori oleh program loader dari OS masing-masing. Gambar disertai oleh berbagai bit metadata untuk membantu linker dan loader membuat asosiasi yang diperlukan dan menggunakan perpustakaan kode.

Windows DLL memiliki tabel ekspor. Ekspor dapat berdasarkan nama, atau dengan posisi tabel (numerik). Metode yang terakhir dianggap "sekolah lama" dan jauh lebih rapuh - membangun kembali DLL dan mengubah posisi fungsi dalam tabel akan berakhir dengan bencana, sedangkan tidak ada masalah nyata jika menghubungkan titik masuk adalah dengan nama. Jadi, lupakan itu sebagai masalah, tetapi perlu diperhatikan bahwa ada di sana jika Anda bekerja dengan kode "dinosaurus" seperti lib vendor pihak ke-3.

Windows DLL dibangun dengan menyusun dan menautkan, sama seperti yang Anda lakukan untuk EXE (aplikasi yang dapat dieksekusi), tetapi DLL dimaksudkan untuk tidak berdiri sendiri, seperti SO yang dimaksudkan untuk digunakan oleh suatu aplikasi, baik melalui pemuatan dinamis, atau oleh tautan-waktu mengikat (referensi ke SO tertanam dalam metadata biner aplikasi, dan pemuat program OS akan secara otomatis memuat SO yang direferensikan). DLL dapat mereferensikan DLL lain, seperti halnya SO dapat merujuk pada SO lainnya.

Di Windows, DLL hanya akan menyediakan titik masuk khusus. Ini disebut "ekspor". Pengembang dapat menggunakan kata kunci kompiler khusus untuk membuat simbol yang terlihat secara eksternal (untuk penghubung lain dan pemuat dinamis), atau ekspor dapat didaftarkan dalam file definisi modul yang digunakan pada waktu tautan ketika DLL itu sendiri sedang dibuat. Praktik modern adalah untuk menghias definisi fungsi dengan kata kunci untuk mengekspor nama simbol. Dimungkinkan juga untuk membuat file header dengan kata kunci yang akan menyatakan simbol itu sebagai salah satu yang akan diimpor dari DLL di luar unit kompilasi saat ini. Cari kata kunci __declspec (dllexport) dan __declspec (dllimport) untuk informasi lebih lanjut.

Salah satu fitur menarik dari DLL adalah mereka dapat mendeklarasikan fungsi handler standar "saat memuat / membongkar". Kapan pun DLL dimuat atau dibongkar, DLL dapat melakukan beberapa inisialisasi atau pembersihan, sesuai kasusnya. Ini memetakan dengan baik untuk memiliki DLL sebagai manajer sumber daya berorientasi objek, seperti driver perangkat atau antarmuka objek bersama.

Ketika seorang pengembang ingin menggunakan DLL yang sudah dibangun, ia harus mereferensikan "ekspor perpustakaan" (* .LIB) yang dibuat oleh pengembang DLL ketika ia menciptakan DLL, atau ia harus secara eksplisit memuat DLL pada saat run time dan meminta alamat titik entri dengan nama melalui mekanisme LoadLibrary () dan GetProcAddress (). Sebagian besar waktu, menghubungkan dengan file LIB (yang hanya berisi metadata linker untuk titik masuk yang diekspor DLL) adalah cara DLL digunakan. Pemuatan dinamis dicadangkan khusus untuk menerapkan "polimorfisme" atau "konfigurabilitas runtime" dalam perilaku program (mengakses pengaya atau fungsionalitas yang lebih baru, alias "plugin").

Cara Windows dalam melakukan sesuatu dapat menyebabkan beberapa kebingungan; sistem menggunakan ekstensi .LIB untuk merujuk ke pustaka statis normal (arsip, seperti file POSIX * .a) dan pustaka "ekspor rintisan" yang diperlukan untuk mengikat aplikasi ke DLL pada waktu tautan. Jadi, kita harus selalu melihat apakah file * .LIB memiliki file * .DLL dengan nama yang sama; jika tidak, kemungkinan besar file * .LIB adalah arsip perpustakaan statis, dan tidak mengekspor metadata yang mengikat untuk DLL.

JoGusto
sumber
4

Anda benar bahwa file statis disalin ke aplikasi pada waktu tautan, dan bahwa file bersama hanya diverifikasi pada waktu tautan dan dimuat saat runtime.

Panggilan dlopen tidak hanya untuk objek yang dibagikan, jika aplikasi ingin melakukannya pada saat runtime atas namanya, jika tidak, objek yang dibagikan akan dimuat secara otomatis ketika aplikasi dimulai. DLL dan .so adalah hal yang sama. dlopen ada untuk menambahkan kemampuan pemuatan dinamis yang lebih halus untuk proses. Anda tidak perlu menggunakan dlopen sendiri untuk membuka / menggunakan DLL, itu juga terjadi saat startup aplikasi.

rapadura
sumber
Apa yang akan menjadi salah satu contoh menggunakan dlopen () untuk kontrol pemuatan lainnya? Jika SO / DLL dimuat secara otomatis saat startup, apakah dlopen () menutup dan membukanya kembali dengan izin atau batasan yang berbeda, misalnya? Terima kasih.
Cloud
1
Saya percaya dlopen adalah untuk plugin atau fungsi serupa. Izin / pembatasan harus sama dengan untuk pemuatan otomatis, dan bagaimanapun dlopen akan memuat pustaka yang bergantung secara rekursif.
rapadura
DLL dan .soyang tidak persis hal yang sama. Lihat jawaban ini
Basile Starynkevitch