При разработке динамических библиотек (dylib) на Free Pascal для macOS, можно столкнуться с неожиданной проблемой: библиотека успешно загружается, но dlsym не находит экспортируемые символы, хотя они видны в таблице символов (например, через nm). Эта проблема не возникает на Windows, что делает ее особенно коварной. В этой статье мы рассмотрим причины этой проблемы и предложим решение, а также альтернативный подход.
Суть проблемы:
Проблема возникает из-за использования конструкции name в секции exports файла проекта Free Pascal. Например:
exports
GetName name 'GetName',
GetBid name 'GetBid',
GetCard name 'GetCard';
На macOS, Free Pascal при использовании name создает символы, которые появляются в статической таблице символов (видимой для nm), но не добавляются корректно в динамическую таблицу символов, необходимую для dlsym. Это приводит к тому, что библиотека загружается, nm показывает экспортированные символы, но dlsym возвращает NULL и сообщает об ошибке "symbol not found".
Решение:
Самое простое и эффективное решение – полностью удалить конструкции name из секции exports, если имя экспортируемой функции совпадает с именем функции в коде.
exports
GetName,
GetBid,
GetCard;
Почему это работает:
Функции экспортируются под своими исходными именами.
Символы корректно добавляются как в статическую, так и в динамическую таблицу символов.
Ключевой вывод: Использование name необходимо только тогда, когда вы хотите изменить имя экспортируемого символа. Если имя экспортируемой функции совпадает с именем функции в коде, отказ от name позволяет избежать этой специфичной для macOS проблемы линковки.
Альтернативное решение (использование директивы {$EXTERNAL}):
Если вам действительно необходимо изменить имя экспортируемой функции (например, для совместимости с существующим API на C), можно использовать директиву {$EXTERNAL}. Этот подход требует немного больше кода, но позволяет сохранить контроль над именами экспортируемых символов.
library player;
{$mode delphi}
uses
SysUtils;
function GetNameFunc: PChar; cdecl;
begin
Result := 'Player Name';
end;
exports
GetNameFunc name 'GetName';
begin
end.
Затем, в вашем C коде, вы будете использовать имя 'GetName':
Важно: При использовании {$EXTERNAL} убедитесь, что соглашения о вызовах (calling conventions) совпадают между Pascal и C (в данном примере cdecl).
Заключение:
Проблема с dlsym на macOS при использовании динамических библиотек Free Pascal, как правило, связана с некорректным использованием конструкции name в секции exports. Простое удаление этой конструкции, если имена совпадают, решает проблему в большинстве случаев. Если необходимо изменить имя экспортируемой функции, используйте директиву {$EXTERNAL}, тщательно следя за соглашениями о вызовах. Понимание этих нюансов позволит вам создавать кроссплатформенные динамические библиотеки на Free Pascal без лишних проблем.
В статье рассматривается проблема загрузки символов в динамической библиотеке Free Pascal на macOS, вызванная использованием конструкции `name` в секции `exports`, и предлагается решение путем ее удаления или использования директивы `{$EXTERNAL}`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.