разделяемые библиотеки — может ли код C ++ надежно взаимодействовать с другим кодом C ++?

В Си я привык писать общую библиотеку, которую можно вызывать из любого клиентского кода, который хочет использовать ее, просто связывая библиотеку и включая связанные заголовочные файлы. Тем не менее, я прочитайте, что C ++ ABI просто слишком нестабильно и нестандартно, чтобы надежно вызывать функции из других источников.

Это заставило бы меня поверить, что создание действительно общих библиотек, которые столь же универсальны, как C, невозможно в C ++, но реальные реализации, кажется, указывают на обратное. Например, Node.js предоставляет очень простую модульную систему, которая позволяет простые функции C ++ (без extern "C") быть экспортируется динамически с использованием NODE_SET_METHOD функция.

Какие элементы API C ++ безопасно раскрыть, если таковые имеются, и каковы общие методы, позволяющие коду C ++ взаимодействовать с другими частями кода C ++? Можно ли создавать общие библиотеки, которые могут предоставлять классы C ++? Или эти классы должны быть отдельно перекомпилированы для каждой программы из-за несовместимого ABI?

5

Решение

Да, взаимодействие C ++ сложно и заполнено ловушками. Холодные жесткие правила таковы, что вы должен используйте точно такую ​​же версию компилятора с точно такими же настройками компилятора для сборки модулей и убедитесь, что они используют одни и те же библиотеки CRT и стандартные библиотеки C ++. Нарушение этих правил приводит к тому, что классы C ++ не имеют одинакового макета на обоих концах раздела, и возникают проблемы с управлением памятью, когда один модуль выделяет объект с помощью другого распределителя из модуля, удаляющего объект. Проблемы, которые приводят к очень сложной диагностике сбоя во время выполнения, когда код использует неправильное смещение для доступа к члену класса и утечки памяти или повреждает кучу.

Node.js избегает этих проблем в первую очередь не экспортировать что угодно. NODE_SET_METHOD () не делает то, что вы думаете, он просто добавляет символ в таблицу символов движка Javascript вместе с указателем функции, который вызывается, когда функция вызывается в скрипте. Кроме того, это проект с открытым исходным кодом, поэтому создание все с тем же компилятором и библиотекой времени выполнения не проблема.

4

Другие решения

это

Например, Node.js предоставляет очень простую систему модулей, которая позволяет
обычные функции C ++ (без внешнего «C») для динамического экспорта
используя функцию NODE_SET_METHOD.

Это неправильно, вы можете видеть, что они используют extern "C" там в init() функция, которая явно является то, что вызывает node.js, который затем перенаправляет функцию на любую функцию C ++, которую они хотят, которая не предоставляется.

Как объяснено в этом вопросе Как экстерн "С" декларация работает? — Когда компилятор компилирует код, он обрабатывает имена функций, имена классов и имена пространств имен. Это происходит потому, что очень легко могут возникнуть конфликты имен, например с перегруженными функциями.

Подробнее об этом читайте здесь: http://en.wikipedia.org/wiki/Name_mangling

Единственный способ ссылаться и искать функцию, если extern "C" используется объявление, которое заставляет компилятор не искажать имя. То есть в приведенном выше примере функция init будет называться init где как функция foo будет называться что-то вроде _ugAGE (Я сделал это, потому что это не имеет значения, это не для потребления человеком)

Таким образом, вы можете открыть любой C ++ для любого другого языка, но точка входа в библиотеку должна быть одна или несколько extern "C"были бы глобальными функциями, так как они являются единственным способом обращения к незарегистрированному имени.

1

Ни стандарты C, ни стандарты C ++ не определяют ABI. Это полностью зависит от реализации. Причина, по которой труднее получить разделяемые / динамические библиотеки, работающие на C ++, заключается в том, что в C ++ добавлены такие вещи, как классы, полиморфизм, шаблоны, исключения, перегрузка функций, STL, …

Таким образом, реальным источником информации для вас является документация ваших компиляторов, а также соответствующий набор рекомендаций для API вашей библиотеки, чтобы избежать каких-либо проблем с любой из реализаций, для которых будет создана ваша библиотека. В C ++ это сложнее (набор рекомендаций, вероятно, будет немного больше, чем в C, и вам, возможно, придется работать с подмножеством C ++), но не невозможно.

0