Перейти к содержанию

Последнее обновление: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, при попытке линковки вы можете столкнуться с ошибками неопределённых символов.

Например, при компиляции следующего кода:

// lib.cc
#include <string>
void foo(const std::string& s) {}

с помощью команды:

g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 -c lib.cc

будет сгенерирован символ __Z3fooRKSs — это формат старого ABI.

Однако при компиляции и линковке другого файла, использующего новый ABI, может возникнуть такая ошибка:

g++-14 main.cc lib.o
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 для совместимости со старыми библиотеками, например:

g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 main.cc lib.o

Способ 2: компилировать все файлы с новым ABI

Если вы готовы использовать новый ABI C++11, при компиляции файлов библиотеки можно применять -D_GLIBCXX_USE_CXX11_ABI=1 — тогда символы будут совпадать:

g++-14 -D_GLIBCXX_USE_CXX11_ABI=1 -c lib.cc
g++-14 main.cc lib.o

В этом случае символы при линковке совпадут, и ошибка неопределённых символов больше не появится.

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++ и в процессе компиляции; надеюсь, эта статья помогла разобраться в этих вопросах.

Похожие темы

Комментарии