什麼樣的魔術在這裏?
這主要是ELF符號版本控制的魔力。我已經看到了這個最好的參考就是How to Write Shared Libraries由烏利齊·德雷珀,特別是第3節
他們怎麼能提供GCC 4.4.7,對舊版本的libstdC++鏈接?我認爲這是不可能的。
libstdC++開發人員注意ABI兼容性。這使得查看兩個不同版本的libstdC++之間引入的新符號變得相當簡單。
查看libstdC++的ABI compatibility page,可以看到GCC 4.1的libstdC++具有GLIBCXX_3.4.8,並且GCC 4.4的庫存(FSF版本)具有GLIBCXX_3.4.13。然後可以查看libstdc++ version scripts以查看在這兩個版本之間添加了哪些符號。
查看符號版本的更經驗性的途徑是使用像readelf這樣的工具。例如。我的Ubuntu系統上readelf --dyn-syms --wide /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt
這樣表示輸出(只是一對夫婦的選擇稍短的線):
223: 000000000006dbe0 2121 FUNC GLOBAL DEFAULT 12 std::ios_base::Init::Init()@@GLIBCXX_3.4
...
226: 00000000002ed920 1 OBJECT GLOBAL DEFAULT 27 std::[email protected]@GLIBCXX_3.4.11
注意符號版本在符號名稱的末尾,在@@
後。
什麼是stdC++ _非共享庫?
加入從上面的段落點,STDC++ _非共享是包含這將是股價的libstdC++。so.6.0.13但不是在的libstdC++。so.6.0.8符號靜態庫。
我不知道.so文件可能包含該文本。誰來分析它(動態鏈接器我猜),它的規範和結果是什麼?
常規鏈接器解析這個,而不是運行時鏈接程序。請參閱INPUT in a linker script的binutils文檔。因此,與這個特殊的libstdC++。so.6.0.13鏈接將導致鏈接器動態鏈接到libstdC++。so.6.0.8,並靜態鏈接到包含額外符號的庫。
這樣做的不足之處在於,以這種方式編譯的應用程序將比僅與包含所有必要符號的庫存libstdC++。so.6.0.13動態鏈接的應用程序相比稍微更臃腫。好處在於新標準庫中的功能可以用於舊系統的標準安裝,無需獨立軟件供應商需要發佈自己的libstdC++副本。
這種魔法能走多遠?我可以在libstdC++ 6.0.3中使用gcc4.7嗎?兼容性
現在的你知道神奇的是什麼譜是什麼,也許你可以明白,這個版本的GCC 4.4你僅僅是CentOS 5的(當然,原本的Red Hat 5)做了一個特殊版本。因此,可能你可以創建一個GCC 4.7,它將產生只需要libstdC++ 6.0.3的二進制文件,但它需要修補你的GCC樹以將正確的符號放入stdC++ _ nonshared.a中的工作量非常小。您至少可以查看gcc44 RPM的來源,以瞭解Red Hat如何在那裏做到這一點。
紅帽似乎繼續這種方法與他們的Red Hat Developer Toolset。在撰寫本文時,GCC 4.8.1是最新的編譯器,它可以爲EL5構建二進制文件,它仍然只需要在目標系統上安裝libstdC++。so.6.0.8。對於希望用C++ 11編寫的開發人員來說,這非常好,但需要能夠部署在EL5或EL6上。
編譯器依賴標準庫,通過生成對特定命名函數的調用,例如,當在獨立gcc環境中使用purr虛函數時,可能會產生對'__cxa_pure_virtual'的未定義引用,這幾乎是函數稱爲,每當一個非重載的純虛函數被調用時,也就是純函數的默認函數。 – Skeen
對於memcpy等,編譯器有很多這樣的例外情況。這就是編譯器如何依賴標準庫。只要標準庫包含編譯器期望的所有函數,那麼在鏈接時就不會有未定義的引用,並且它將「有效」。因此很有可能,不建議混合編譯器和庫版本。 – Skeen
至於stdC++ _noshared,我的猜測是,這是一個庫的靜態鏈接版本,這意味着所有需要的東西都將在編譯時被包含,而不是在運行時動態鏈接到動態鏈接器。 – Skeen