Saya perlu menerapkan aplikasi C ++ yang dibangun di Ubuntu 12.10 dengan libstdc ++ GCC 4.7 ke sistem yang menjalankan Ubuntu 10.04, yang hadir dengan versi libstdc ++ yang jauh lebih lama.
Saat ini, saya sedang mengkompilasi -static-libstdc++ -static-libgcc
, seperti yang disarankan oleh posting blog ini: Menghubungkan libstdc ++ secara statis . Penulis memperingatkan agar tidak menggunakan kode C ++ yang dimuat secara dinamis saat mengompilasi libstdc ++ secara statis, yang merupakan sesuatu yang belum saya periksa. Namun, semuanya tampaknya berjalan lancar sejauh ini: Saya dapat menggunakan fitur C ++ 11 di Ubuntu 10.04, yang saya cari.
Saya perhatikan bahwa artikel ini berasal dari tahun 2005, dan mungkin banyak yang berubah sejak saat itu. Apakah nasihatnya masih berlaku? Apakah ada masalah tersembunyi yang harus saya waspadai?
-static-libstdc++
opsi, Anda hanya akan menggunakan-static
kernel too old
kesalahan di beberapa sistem ubuntu 1404. Glibc.so sepertikernel32.dll
di jendela, ini adalah bagian dari antarmuka sistem operasi, kita tidak boleh menyematkannya di biner kita. Anda dapat menggunakanobjdump -T [binary path]
untuk melihatnya dimuat secara dinamislibstdc++.so
atau tidak. Untuk programer golang, Anda dapat menambahkan#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
sebelum mengimpor "C"-static-libstdc++
tidak-static
begitulibc.so
tidak akan ditautkan secara statis.Jawaban:
Posting blog itu sangat tidak akurat.
Tidak benar. Satu-satunya perubahan C ++ ABI yang diperkenalkan sejak GCC 3.4 telah kompatibel dengan versi sebelumnya, yang berarti C ++ ABI telah stabil selama hampir sembilan tahun.
Perbedaan antara versi GCC yang ditambal dari distribusi kecil, dan bukan ABI yang berubah, misalnya Fedora 4.6.3 20120306 (Red Hat 4.6.3-2) adalah ABI yang kompatibel dengan rilis FSF 4.6.x upstream dan hampir pasti dengan semua 4.6. x dari distro lain.
Pada pustaka runtime GNU / Linux GCC menggunakan versi simbol ELF sehingga mudah untuk memeriksa versi simbol yang dibutuhkan oleh objek dan pustaka, dan jika Anda memiliki
libstdc++.so
yang menyediakan simbol-simbol itu, itu akan berfungsi, tidak masalah jika itu versi tambalan yang sedikit berbeda dari versi lain distro Anda.Ini juga tidak benar.
Meskipun demikian, menautkan ke secara statis
libstdc++.a
adalah salah satu opsi untuk Anda.Alasan mengapa ini mungkin tidak berfungsi jika Anda secara dinamis memuat pustaka (menggunakan
dlopen
) adalah karena simbol libstdc ++ yang bergantung padanya mungkin tidak diperlukan oleh aplikasi Anda saat Anda (secara statis) menautkannya, jadi simbol itu tidak akan ada dalam file yang dapat dieksekusi. Itu dapat diselesaikan dengan secara dinamis menautkan pustaka bersama kelibstdc++.so
(yang merupakan hal yang benar untuk dilakukan jika bergantung padanya.) Interposisi simbol ELF berarti simbol yang ada dalam eksekusi Anda akan digunakan oleh pustaka bersama, tetapi yang lain tidak hadir di executable Anda akan ditemukan di mana punlibstdc++.so
ia tertaut. Jika aplikasi Anda tidak menggunakandlopen
Anda tidak perlu peduli tentang itu.Opsi lain (dan yang saya sukai) adalah menerapkan yang lebih baru di
libstdc++.so
samping aplikasi Anda dan memastikannya ditemukan sebelum sistem defaultlibstdc++.so
, yang dapat dilakukan dengan memaksa penaut dinamis untuk mencari di tempat yang tepat, baik menggunakan$LD_LIBRARY_PATH
variabel lingkungan saat dijalankan- waktu, atau dengan mengaturRPATH
di eksekusi pada link-time. Saya lebih suka menggunakanRPATH
karena tidak bergantung pada lingkungan yang disetel dengan benar agar aplikasi berfungsi. Jika Anda menghubungkan aplikasi Anda dengan'-Wl,-rpath,$ORIGIN'
(perhatikan tanda kutip tunggal untuk mencegah shell mencoba untuk memperluas$ORIGIN
) maka eksekusi akan memilikiRPATH
dari$ORIGIN
yang menceritakan linker dinamis untuk mencari shared library di direktori yang sama dengan eksekusi itu sendiri. Jika Anda menempatkan yang lebih barulibstdc++.so
dalam direktori yang sama dengan yang dapat dieksekusi, itu akan ditemukan pada waktu proses, masalah terpecahkan. (Pilihan lain adalah memasukkan file yang dapat dieksekusi/some/path/bin/
dan libstdc ++ yang lebih baru. Jadi/some/path/lib/
dan menautkan dengan'-Wl,-rpath,$ORIGIN/../lib'
atau lokasi tetap lainnya yang relatif terhadap yang dapat dieksekusi, dan mengatur RPATH relatif ke$ORIGIN
)sumber
libstdc++.so.6
symlink yang diatur pada waktu instalasi untuk menunjuk ke lib yang dibundel atau ke sistem jika lebih baru. Ada model hubungan campuran yang lebih rumit, seperti yang digunakan oleh Red Hat DTS, tetapi sulit dilakukan sendiri.Satu tambahan untuk jawaban luar biasa Jonathan Wakely, mengapa dlopen () bermasalah:
Karena kumpulan penanganan pengecualian baru di GCC 5 (lihat PR 64535 dan PR 65434 ), jika Anda membuka dan menutup pustaka yang secara statis ditautkan ke libstdc ++, Anda akan mendapatkan kebocoran memori (dari objek kumpulan) setiap saat. Jadi, jika ada kemungkinan Anda pernah menggunakan dlopen, sepertinya ide yang buruk untuk menautkan libstdc ++ secara statis. Perhatikan bahwa ini adalah kebocoran nyata dibandingkan dengan kebocoran jinak yang disebutkan dalam PR 65434 .
sumber
__gnu_cxx::__freeres()
tampaknya menyediakan setidaknya beberapa bantuan untuk masalah ini, karena ini membebaskan buffer internal objek kumpulan. Tapi bagi saya agak tidak jelas implikasi mana yang dimiliki panggilan ke fungsi ini sehubungan dengan pengecualian yang secara tidak sengaja dilemparkan setelahnya.Tambahan untuk jawaban Jonathan Wakely tentang RPATH:
RPATH hanya akan berfungsi jika RPATH yang dimaksud adalah RPATH dari aplikasi yang sedang berjalan . Jika Anda memiliki perpustakaan yang secara dinamis menautkan ke perpustakaan mana pun melalui RPATH-nya sendiri, RPATH perpustakaan akan ditimpa oleh RPATH dari aplikasi yang memuatnya. Ini adalah masalah ketika Anda tidak dapat menjamin bahwa RPATH aplikasi sama dengan perpustakaan Anda, misalnya jika Anda mengharapkan dependensi Anda berada di direktori tertentu, tetapi direktori itu bukan bagian dari RPATH aplikasi.
Misalnya, Anda memiliki aplikasi App.exe yang memiliki dependensi yang ditautkan secara dinamis di libstdc ++. So.x untuk GCC 4.9. App.exe memiliki ketergantungan ini diselesaikan melalui RPATH, yaitu
App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)
Sekarang katakanlah ada library lain Dependency.so, yang memiliki dependensi yang ditautkan secara dinamis pada libstdc ++. So.y untuk GCC 5.5. Ketergantungan di sini diselesaikan melalui RPATH perpustakaan, yaitu
Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)
Ketika App.exe memuat Dependency.so, itu tidak menambahkan atau menambahkan RPATH perpustakaan . Itu tidak berkonsultasi sama sekali. Satu-satunya RPATH yang dipertimbangkan akan menjadi aplikasi yang berjalan, atau App.exe dalam contoh ini. Artinya, jika pustaka mengandalkan simbol yang ada di gcc5_5 / libstdc ++. So.y tetapi tidak di gcc4_9 / libstdc ++. So.x, pustaka tersebut akan gagal dimuat.
Ini hanya sebagai peringatan, karena saya sendiri pernah mengalami masalah ini di masa lalu. RPATH adalah alat yang sangat berguna tetapi implementasinya masih memiliki beberapa kendala.
sumber
Anda mungkin juga perlu memastikan bahwa Anda tidak bergantung pada glibc dinamis. Jalankan
ldd
pada hasil yang dapat dieksekusi dan catat setiap dependensi dinamis (libc / libm / libpthread adalah tersangka yang digunakan).Latihan tambahan akan membangun banyak contoh C ++ 11 yang terlibat menggunakan metodologi ini dan benar-benar mencoba biner yang dihasilkan pada sistem 10,04 nyata. Dalam kebanyakan kasus, kecuali Anda melakukan sesuatu yang aneh dengan pemuatan dinamis, Anda akan langsung tahu apakah program itu bekerja atau macet.
sumber
printf
) tetapi selama glibc di Ubuntu 10.04 menyediakan semua fitur yang dibutuhkan oleh libstdc ++ yang lebih baru tidak ada masalah dengan bergantung pada glibc dinamis, sebenarnya sangat disarankan untuk tidak pernah menautkan secara statis ke glibcSaya ingin menambahkan jawaban Jonathan Wakely berikut ini.
Bermain-main
-static-libstdc++
di linux, saya menghadapi masalahdlclose()
. Misalkan kita memiliki aplikasi 'A' yang ditautkan secara statislibstdc++
dan dimuat secara dinamis kelibstdc++
plugin 'P' saat runtime. Tidak apa-apa. Tetapi ketika 'A' membongkar 'P', terjadi kesalahan segmentasi. Asumsi saya adalah setelah bongkarlibstdc++.so
, 'A' tidak bisa lagi menggunakan simbol yang berhubungan denganlibstdc++
. Perhatikan bahwa jika 'A' dan 'P' ditautkan secara statislibstdc++
, atau jika 'A' ditautkan secara dinamis dan 'P' secara statis, masalah tidak terjadi.Ringkasan: jika aplikasi Anda memuat / mengeluarkan plugin yang mungkin ditautkan secara dinamis
libstdc++
, aplikasi tersebut juga harus ditautkan secara dinamis. Ini hanya pengamatan saya dan saya ingin mendapatkan komentar Anda.sumber
sbrk
) membuat asumsi tertentu dan cukup banyak berharap untuk sendirian dalam satu proses ... tidak yakin apakah ini terbatas pada a versi glibc tertentu atau apa pun.