Последнее обновление:2026-10-12
C++ совместимость string ABI¶
Практическая проблема проекта: как избежать проблем совместимости C++ String ABI¶
Почему многим не нравится C++ string и они предпочитают изобретать собственный велосипед? Одна из причин — проблема ABI у C++ string; вы с ней сталкивались?
Ранее при использовании conan и кроссплатформенных библиотек возникала проблема совместимости C++ string ABI; в этом разделе будет рассказано о предыстории ABI и о том, что связано с компилятором, а также о том, как избежать этой ловушки. Если вы с ней сталкивались, добро пожаловать в комментарии~
1. Предыстория изменения ABI¶
После GCC 5.1 была усилена поддержка C++11 и добавлены некоторые новые возможности. В этой версии libstdc++ представил новый библиотечный ABI и обновил реализации std::string и std::list. Эти изменения соответствуют стандарту C++11, который запрещает строки с Copy-On-Write и требует, чтобы связные списки отслеживали свой размер.
В реальных проектах при использовании Conan разработчик может выбирать используемый ABI, настраивая compiler.libcxx:
- libstdc++: используется старый ABI.
- libstdc++11: используется новый ABI.
Выбор подходящего ABI обеспечивает совместимость с другими зависимыми библиотеками, особенно при использовании разных версий компиляторов или библиотек.
2. Настройки компилятора по умолчанию¶
При компиляции с помощью GCC, если явно не указан --with-default-libstdcxx-abi=gcc4-compatible, GCC по умолчанию использует новый ABI C++11. Это означает:
- если ваш код или зависимые библиотеки скомпилированы со старым ABI, при попытке линковки вы можете столкнуться с ошибками неопределённых символов.
Например, при компиляции следующего кода:
с помощью команды:
будет сгенерирован символ __Z3fooRKSs — это формат старого ABI.
Однако при компиляции и линковке другого файла, использующего новый ABI, может возникнуть такая ошибка:
Undefined symbols for architecture x86_64:
"foo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)", referenced from:
_main in ccbWGoYh.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
3. Решения¶
Чтобы обеспечить успешную компиляцию, есть два решения:
Способ 1: вручную указать ABI
При компиляции всех исходных файлов обязательно добавляйте вручную -D_GLIBCXX_USE_CXX11_ABI=0 для совместимости со старыми библиотеками, например:
Способ 2: компилировать все файлы с новым ABI
Если вы готовы использовать новый ABI C++11, при компиляции файлов библиотеки можно применять -D_GLIBCXX_USE_CXX11_ABI=1 — тогда символы будут совпадать:
В этом случае символы при линковке совпадут, и ошибка неопределённых символов больше не появится.
4. Сравнение символов¶
Посмотрев символы в разных ABI с помощью команды nm, можно наглядно увидеть различия между ними:
g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKSs
g++-14 -D_GLIBCXX_USE_CXX11_ABI=1 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
5. Резюме¶
ABI — очень большая ловушка, в которую можно попасть при обновлении C++ и в процессе компиляции; надеюсь, эта статья помогла разобраться в этих вопросах.
Похожие темы¶
- C++ чисто виртуальные функции и абстрактные классы | C++那些事
- C++ утверждения assert | C++那些事
- C++ битовые поля | C++那些事
- Реализация полиморфизма C++ на языке C | C++那些事
- C++ константы const и его модификация | C++那些事
- C++ всё семейство const | C++那些事
- C++ оператор разыменования * | C++那些事
- C++ инициализация и присваивание | C++那些事
- C++ возврат нескольких значений | C++那些事
- C++ ключевое слово mutable | C++那些事