В Си я привык писать общую библиотеку, которую можно вызывать из любого клиентского кода, который хочет использовать ее, просто связывая библиотеку и включая связанные заголовочные файлы. Тем не менее, я прочитайте, что C ++ ABI просто слишком нестабильно и нестандартно, чтобы надежно вызывать функции из других источников.
Это заставило бы меня поверить, что создание действительно общих библиотек, которые столь же универсальны, как C, невозможно в C ++, но реальные реализации, кажется, указывают на обратное. Например, Node.js предоставляет очень простую модульную систему, которая позволяет простые функции C ++ (без extern "C"
) быть экспортируется динамически с использованием NODE_SET_METHOD
функция.
Какие элементы API C ++ безопасно раскрыть, если таковые имеются, и каковы общие методы, позволяющие коду C ++ взаимодействовать с другими частями кода C ++? Можно ли создавать общие библиотеки, которые могут предоставлять классы C ++? Или эти классы должны быть отдельно перекомпилированы для каждой программы из-за несовместимого ABI?
Да, взаимодействие C ++ сложно и заполнено ловушками. Холодные жесткие правила таковы, что вы должен используйте точно такую же версию компилятора с точно такими же настройками компилятора для сборки модулей и убедитесь, что они используют одни и те же библиотеки CRT и стандартные библиотеки C ++. Нарушение этих правил приводит к тому, что классы C ++ не имеют одинакового макета на обоих концах раздела, и возникают проблемы с управлением памятью, когда один модуль выделяет объект с помощью другого распределителя из модуля, удаляющего объект. Проблемы, которые приводят к очень сложной диагностике сбоя во время выполнения, когда код использует неправильное смещение для доступа к члену класса и утечки памяти или повреждает кучу.
Node.js избегает этих проблем в первую очередь не экспортировать что угодно. NODE_SET_METHOD () не делает то, что вы думаете, он просто добавляет символ в таблицу символов движка Javascript вместе с указателем функции, который вызывается, когда функция вызывается в скрипте. Кроме того, это проект с открытым исходным кодом, поэтому создание все с тем же компилятором и библиотекой времени выполнения не проблема.
это
Например, 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"
были бы глобальными функциями, так как они являются единственным способом обращения к незарегистрированному имени.
Ни стандарты C, ни стандарты C ++ не определяют ABI. Это полностью зависит от реализации. Причина, по которой труднее получить разделяемые / динамические библиотеки, работающие на C ++, заключается в том, что в C ++ добавлены такие вещи, как классы, полиморфизм, шаблоны, исключения, перегрузка функций, STL, …
Таким образом, реальным источником информации для вас является документация ваших компиляторов, а также соответствующий набор рекомендаций для API вашей библиотеки, чтобы избежать каких-либо проблем с любой из реализаций, для которых будет создана ваша библиотека. В C ++ это сложнее (набор рекомендаций, вероятно, будет немного больше, чем в C, и вам, возможно, придется работать с подмножеством C ++), но не невозможно.