田海立@CSDN 2020-12-12
《Android原始碼中的C++ STL》與《Android原始碼中C++ STL的namespace》以及《Android NDK中的C++ STL》分別介紹了Android原始碼中以及NDK環境下有哪些STL有些什么區別,本文主要講述怎么選擇STL,靜態庫/動態庫如何選,有哪些注意點,本文雖針對Android講解,其中觀點亦適用于其他場景,
一、STL的選擇
Android原始碼中
Android原始碼中的c++ STL:內置的llvm libc++/libc++_static/system;內置的NDK版本中的libc++_shared/libc++_static/system(system也就是android原始碼中的libstdc++),其中的內置的libc++ stl與NDK中的libc++ STL并不兼容,它們用namespace都做了隔離,
- Android原始碼中盡量用內置的lib++;
- 只有在預置外來包的,并且外來包是要兼容多個Android 版本的情況下,才考慮用NDK里的STL,而且,要不違背后面的一個STL原則,
Android NDK中
Android NDK中的STL:libc++_shared / libc++_static / system,其中libc++(靜態與動態)是完整的STL,目前基于Android NDK編譯,完整STL只有一個可選,靜態庫與動態庫的選擇遵循后面的原則,
二、靜態庫 vs 動態庫
靜態庫
程式鏈接STL靜態庫時,會把所用到的函式與物件等直接放進編譯目標里,這會使得編譯的目標變大(與動態鏈接相比),但是這樣編譯出來的結果是可獨立發布的,與動態鏈接要與libc++一起發布比其大小又是小的(動態編譯還要算上libc++的尺寸),而且編譯時刻可以做很多優化作業,也沒有運行時動態加載的開銷以及Android舊版本里的bug,
不過也考慮下面情況(注:由于所用工具不支持名稱為libc++_static.a,其中的libcpp_static.a應為libc++_static.a):

libfoo用到c++_static;libbar也用到c++_static;libbar依賴于libfoo,
這種情況下,c++ STL的一些全域的資料和建構式會被編譯進libbar和libfoo,使用它們的程式的行為是未知的,可能會有的問題:
- 記憶體在一個庫里申請卻在另一個庫里被釋放,引起記憶體泄漏或堆疊破壞;
- Exceptions在
libfoo.so里發生,卻被libbar.so捕獲而導致程式崩潰; std::cout緩沖buffer出現問題,
當然,問題可能還不限于上面幾種,
所以,只有在程式中有且僅有一個共享庫時,該共享庫才用c++ STL的靜態版,
動態庫
程式里用到多個共享庫的時,應該用c++ STL的動態版,
Android NDK里的libc++(libc++_shared.so)不同于Android原始碼中的libc++(libc++.so),用NDK里的c++編譯應用程式,c++的共享庫(libc++_shared.so)會被打包進apk里,如果是支持多架構的程式,程式的尺寸會變得比較大, 不過也就因為不同于Android原始碼中的實作,發布節奏也不一樣,NDK中的c++ STL有其feature,也可能解決了某些Android原始碼中的問題,
所以,關于靜態庫與動態庫:
- Android NDK開發如果程式只有一個編譯目標時,建議用靜態STL,
- Android原始碼開發是另外一種情況,如果未指定,所以默認編譯動態庫用動態STL;編譯靜態庫用靜態STL,
三、一個STL原則
一個程式的所有庫只能使用一個兼容的STL,
Android NDK里以前有多個STL并存:GNU libstdc++、STLport和libc++,這些STL之間彼此并不兼容,特別是具體內部實作都是用不同的namespace分割的,
所以,如果程式依賴的編譯好(prebuilt)的庫,而這些庫用到的c++ STL,要保證這些STL是兼容版本,因為不同STL之間并不兼容,這里的兼容看來也就是同一STL的不同版本而已,
如果你的程式依賴于一個第三方閉源庫,你就沒得選擇,只能選擇它所用的STL,最好也是同一個版本的STL,如果這個閉源庫有合作者,也可以要求他/她來基于你所用的STL編譯一個版本,
四、總結
使用STL時:
- Android原始碼里編譯,盡量用原始碼中的libc++;
- Android NDK編譯,程式中有且僅有一個共享庫時,該共享庫才用c++ STL的靜態版;
- Android NDK編譯,用c++ STL共享庫時,該c++庫會被編譯進apk里,這個STL也不同于Android原始碼中的c++ STL;
- 無論如何,一個程式里只能有一個STL:要么你跟隨別的庫采用的STL;要么別的庫跟隨你要采用的STL——取決于你們的合作機制與話語權了,
附1:參考及進一步閱讀
- NDK c++ Library Support https://developer.android.google.cn/ndk/guides/cpp-support
官方介紹 - Android原始碼中的c++ STL https://haili-tian.blog.csdn.net/article/details/109864831
Android原始碼中的STL:內置的libc++/libc++_static/system;內置的NDK版本中的libc++_shared/libc++_static/system(system也就是android原始碼中的libstdc++) - Android原始碼中c++ STL的namespace https://haili-tian.blog.csdn.net/article/details/109920740
namespace in libc++【頭檔案: external/libcxx/include/】:std::__1
namespace in libc++_shared【頭檔案: prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/include/】:std::__ndk1 - Android NDK中的c++ STL https://haili-tian.blog.csdn.net/article/details/110148527
Android NDK中的STL:libc++_shared / libc++_static / system,其中libc++是完整的STL
附2:其他文章
- gnustl_static vs gnustl_shared https://blog.csdn.net/matrix_laboratory/article/details/79217973
靜態庫與動態庫的觀點是正確的,選擇靜態庫還是動態庫的結論卻是偏頗的
CSDN認證博客專家
系統分析師
Android
人工智能
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/233901.html
標籤:其他
