最近,在Linux下使用CMake編譯程序的時候遇到一個問題,特此作一個記錄。c++
事情是這樣的,我編譯的程序使用了2個第三方庫,在寫好CMakeLists後,啓動編譯,而後就報連接錯誤,一直報一堆找不到定義。搜索引擎
相似這樣的一堆:code
‘***** std::__cxx11 *******’未定義的引用
我仔細檢查代碼和CMakeLists,各類修改嘗試無果。最後,在同事和搜索引擎的幫助下終於找到問題所在了。索引
問題出在我使用的GCC和第三方庫編譯的時候使用的GCC版本差別太大,二者的ABI不兼容。源碼
參考GCC提供的手冊<Dual ABI>,事情就清晰了。string
在GCC5.1發佈的libstdc++中,添加了新的特性,其中包括了std::string和std::list的新實現。新的實現使得二者都符合了C++11的標準。可是,爲了與現存代碼兼容,libstdc++保留了老的實現,與新實現並存。具體怎麼實現的呢?相比於老的實現,GCC5.1添加了__cxx11命名空間,在新的實現中的string和list,其實是std::__cxx11::string和std::__cxx11::list。新舊ABI不兼容。編譯
那麼,問題怎麼解決呢?List
也很簡單,就是統一你的程序和第三方庫使用的實現版本。若是你有第三方庫源碼,那統一從新編譯下就行。若是第三方庫是已經編譯好的那也不要緊,GCC爲咱們提供了一個選擇新舊實現的宏定義-D_GLIBCXX_USE_CXX11_ABI。搜索
-D_GLIBCXX_USE_CXX11_ABI=0 表示使用舊的實現 -D_GLIBCXX_USE_CXX11_ABI=1 表示使用新的實現
按需添加到CMakeLists中就能夠了。命名空間