我們在 Ubuntu 18.04 上使用 CMake 3.18 編譯和鏈接我們的代碼。程式的結構是這樣的:
有一個帶有 main 函式的應用程式,它在運行時加載一個共享庫,比如 lib_a.so。在運行時,該庫會加載另外兩個庫 lib_b.so 和 lib_c.so 并使用其中的符號。lib_b.so 也使用 lib_c.so 中的符號。
lib_b.so 和 lib_c.so 是從 A 的子模塊 B 和 C 編譯而來的。
在某些系統上,代碼運行良好。然而,在某些系統上,我們會得到未定義的符號錯誤,當使用 c filt 對無法找到的符號進行分解時,它看起來像這樣:
Unable to load lib_a.so : lib_b.so: undefined symbol: D::E::Get(std::initializer_list<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >)
命名空間 D 和類 D::E 位于 C 的子模塊下。該子模塊不包含 CMakeLists.txt,并且不會從中生成共享或靜態庫。它是一個目錄,僅包含源檔案和頭檔案。
當我們使用 nm --defined-only lib_c.so 查看 lib_c.so 的定義符號時,我們看到有這個符號:
D::E::Get(std::initializer_list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >)
我們的 G 版本是 7.5.0,CMake 版本是 3.18.0。
由此,我們推測這是一個 CXX11 ABI 問題。所以,這些是我們分別嘗試過的事情:
在定義目標之前,將 add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=1) 添加到編譯和鏈接 lib_b.so 的 CMakeLists.txt。
在定義目標之前,將集合 (CMAKE_CXX_STANDARD 11) 添加到編譯和鏈接 lib_a.so 的 CMakeLists.txt。由于這是頂級模塊,我們認為這會將其所有子模塊的 c 標準設定為 11。
在定義目標之前,將 target_compile_features(target PUBLIC cxx_std_11) 添加到編譯和鏈接 lib_b.so 的 CMakeLists.txt。
都沒有解決問題。而且,沒有任何變化。lib_b.so 再次查找相同的符號。
但是,當我們撰寫一個 Makefile 來編譯源代碼并按照說明鏈接共享庫時,問題就消失了。
uj5u.com熱心網友回復:
原來這是第三方庫問題。
正如@Someprogrammerdude 所建議的那樣,使用 VERBOSE=1 運行 CMake 顯示 lib_b.so 與 -D_GLIBCXX_USE_CXX11_ABI=0 鏈接。
我在 B/CMakeFiles/B.dir/flags.cmake 中手動將其更改為 -D_GLIBCXX_USE_CXX11_ABI=1。這次之前的錯誤消失了。
然而,這給 cxx11_abi 帶來了另一個關于我們使用的第三方庫的未定義符號錯誤。
將庫更新到使用 CXX11 ABI 編譯的版本解決了該問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/460430.html
上一篇:boost::process::system可以支持用分號分隔的bash命令嗎?
下一篇:此指標不能在建構式中使用別名:
