Использование libstdС++ скомпилированных библиотек с помощью clang++ -stdlib = libС++

Я работаю на С++ под Mac OS X (10.8.2), и недавно я придумал использовать возможности С++ 11, которые доступны через компилятор clang++ с помощью libС++ stdlib. Тем не менее, мне также нужно использовать некоторую библиотеку устаревших, скомпилированную и связанную с libstdС++ (исходящую от MacPorts).

При этом у меня возникли ошибки связывания, так как заголовки устаревших библиотек, использующие, например, std::string, должны были быть разрешены против std::__1::basic_string (т.е. реализации libС++ std::string) вместо std::basic_string.

Есть ли способ смешать две библиотеки в разработке (например, используя некоторые флаги препроцессоров?)

Ответ 1

То, что вы видите, это использование встроенных пространств имен для достижения версии ABI.

Что это означает:

libstdС++ std::string - это другая структура данных, чем libС++ std::string. Первый - эталонный подсчитанный дизайн, а второй - нет. Хотя они совместимы с API, они не совместимы с ABI. Это означает, что если вы построите std::string с libstdС++, а затем передадите его другому коду, связанному с libС++, код получения будет считать, что у него есть libС++ std::string. То есть у получателя не было бы намека на то, что он должен увеличивать или уменьшать количество ссылок.

Без внутренних пространств имен результатом будет ошибка времени выполнения. Лучшее, на что можно надеяться, это крушение. С внутренними пространствами имен эта ошибка времени выполнения преобразуется в ошибку времени связи.

Вам программист libstdС++ std::string и libС++ std::string выглядят одинаково. Но для компоновщика они выглядят как совершенно разные типы (ключ - это пространство имен std::__1). И изображение компоновщика правильное. Они являются совершенно разными типами.

Итак, да, вы можете манипулировать некоторыми препроцессорными флагами, чтобы связать вещи. Но тогда у вас будет дьявол времени отладки результирующих ошибок времени выполнения.

Единственный способ сделать то, что вы хотите, - сделать интерфейсы между этими dylib, не включать std:: типы, такие как string. Например, вы могли бы передавать массивы char. Вы даже можете перенести владение памятью из libstdС++ - связанного кода на libС++ - связанный код и наоборот (они оба перейдут в один и тот же пул malloc).