rzaripov.kz

Статическая библиотека Delphi в приложении Swift

Сборка статической библиотеки на Delphi и её использование из Swift позволяют встроить проверенную бизнес-логику в нативное приложение Apple. Такое решение полезно, когда переносить весь проект нецелесообразно, но важно сохранить существующие алгоритмы, обработку данных и доменные правила. Swift отвечает за интерфейс, жизненный цикл приложения и интеграцию с системными API.

Статическая библиотека Delphi превращает выбранные функции в машинный код, который линкер Swift подключает во время сборки Xcode. Вызовы идут напрямую, без сетевого запроса и без загрузки отдельного модуля. Это особенно удобно для вычислительных операций, криптографии, преобразования форматов или общей логики, которую уже трудно надёжно повторить.

Подход требует строгой инженерной дисциплины: бинарные файлы должны соответствовать платформе и архитектуре, а типы Delphi не должны напрямую пересекать границу с Swift. Кроме того, обе стороны должны заранее определить владение памятью, обработку ошибок и правила вызова. При таком контроле старый компонент становится надёжным внутренним модулем, а не чёрным ящиком.

Когда стоит связывать Delphi и Swift

Связывать экосистемы имеет смысл, если общая часть не зависит от VCL или FireMonkey и может работать без визуальных компонентов. В модуль переносят чистые вычисления, файловые операции и бизнес-правила, а платформенный код остаётся в Swift. Такой монолит проще контролировать: у каждого сценария появляется один источник истины.

На сайте разработчика можно увидеть более широкий контекст разработки кроссплатформенных решений и выбора технологий под конкретную задачу. Здесь смешение Delphi и Swift выглядит не экзотикой, а continuation уже сложившийся стек: нативный код Delphi дополняет экосистему Apple, не заставляя переписывать проверенную доменную часть.

Статическое связывание также избавляет от поиска динамической библиотеки во время запуска. Однако каждый вызов всё равно имеет стоимость, а изменение общей логики требует новой сборки и повторного распространения приложения. Если модуль должен обновляться независимо, лучше рассматривать динамическую библиотеку или удалённый сервис.

Проектирование API в Delphi

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

Публичный интерфейс лучше строить на простых типах: целых числах, числах с плавающей точкой, логических значениях, массивах байт и непрозрачных дескрипторах. Объект или запись Delphi не следует отдавать как готовую структуру, поскольку её внутреннее представление зависит от компилятора, выравнивания и параметров сборки. Безопаснее создать контекст функциями create и destroy, а команды передавать через отдельные методы.

Функции, видимые из Swift, объявляют с соглашением cdecl. Именам лучше давать короткий общий префикс, чтобы избежать случайных пересечений. Экспорт проверяют по готовому архиву: компоновщик мог исключить неиспользуемый символ из-за настроек оптимизации или видимости. Заголовочный файл для Swift должен содержать только объявления, не включая внутренние модули Delphi.

Сборка архитектурно совместимой библиотеки

Сборку необходимо разделить по платформам и архитектурам. Для iOS-устройства нужен вариант arm64, для симулятора — подходящая архитектура процессора, а для macOS может потребоваться отдельный вариант для Intel и Apple Silicon. Универсальный архив для macOS создают из подготовленных частей, но этот процесс не устраняет различия между iOS и macOS.

Отдельно проверяют режим Debug или Release, уровень оптимизации, минимальную версию операционной системы и используемую модель управления памятью. Пути поиска должны содержать все модули исходного кода. Статическая библиотека не заменяет системные зависимости: если Delphi использует Objective-C, криптографические API или другие платформенные механизмы, Xcode должен получить необходимые framework и параметры линковки.

Перед подключением полезно изучить содержимое архива утилитами ar и nm, а на macOS проверить состав командами lipo -info и nm. Особое внимание уделяют ожидаемым именам функций и разрядности объектных файлов. Ошибка на этом этапе часто проявляется только при линковке Xcode как несовместимый архив или неопределённый символ.

Подключение архива к Swift

Файл libRavilCore.a добавляют в Xcode через Link Binary With Libraries, после чего задают каталоги поиска заголовков и библиотек. Затем создают bridging header либо module map, который связывает объявления на C с целевым модулем Swift. Без такого описания импортировать функции в исходном коде не удастся, даже если сам архив уже успешно добавлен в проект.

Module map обычно задаёт имя модуля, путь к общему заголовку и экспортируемые объявления. Если в архиве есть дополнительные зависимые библиотеки, их также добавляют в настройках линковки. Для кода Objective-C иногда необходим флаг -ObjC, но его добавляют только после проверки символов, чтобы не менять поведение проекта без необходимости.

После настройки импорта Swift видит функции как обычные методы и процедуры C. Например, ravil_context_create() создаёт непрозрачный дескриптор, а ravil_process(context, input) выполняет вычисление. Имена и правила владения лучше перенести непосредственно из общей спецификации API, чтобы Objective-C-обёртка, Swift-код и Delphi-реализация использовали один контракт.

Строки, память и обратные вызовы

Тип string в Delphi использует управляемое Unicode-представление и собственный подсчёт ссылок, поэтому возвращать его через C ABI нежелательно. Наружу выдают нуль-终止ённую UTF-8-строку вместе с длиной либо отдельными функциями чтения и освобождения. В Swift безопасное преобразование выполняется через String(cString:) после проверки указателя; полученное значение копируется и не зависит от времени жизни буфера Delphi.

Указатели задают владельца явно. Память, выделенную Delphi, освобождают только функцией из того же модуля, а String, массив или класс Swift никогда не передаются напрямую в FreeMem. Контекст желательно сделать потокобезопасным либо документировать допустимый поток вызова. Для функций с результатом вводят коды статуса, а исключения Delphi перехватывают до пересечения границы Swift.

Обратные вызовы из Swift объявляют как обычные C-функции с @convention(c). Замыкания Swift нельзя без преобразования хранить в указателях Delphi, а перехват исключения через границу нарушает C ABI. Для событий лучше использовать слот function, который действует только во время вызова либо пока владелец явно поддерживает регистрацию. Функция должна получать копию данных, если они могут измениться после возврата.

Отладка и выпускная сборка

Проверять ошибки удобно на небольшом API-контуре: один вызов без аргументов, один со строкой Unicode, один с ошибочными данными и один с ресурсоёмкой операцией. Тесты должны выполняться с обеих сторон, включая создание контекста, обработку результата, освобождение и повторный вызов. Это выявляет несовместимые представления чисел, неверные флаги и утечки памяти на границе.

На этапе разработки сохраняют неудалённые символы и карты адресов. Утилита nm показывает наличие функций в архиве, а журнал Xcode помогает понять, на какой объект ссылается компоновщик. Если Delphi и Swift собраны с разными параметрами оптимизации или отладки, сопоставление строк может быть неполным, хотя само приложение способно работать.

Перед выпуском проверяют лицензионные условия используемого компилятора и наличие платформенных зависимостей. Дополнительные наблюдения о маршрутизации запросов и взаимодействии компонентов собраны в практических материалах. Статическую библиотеку удаляют и лишние символы обычно убирают только после успешных тестов на устройстве и симуляторе.

Альтернативы и практический выбор

Статическая библиотека подходит, когда нужен прямой вызов, стабильная производительность и единый бинарный результат. Исходный код удобнее, если команда проекта владеет Delphi и поддерживает полную пересборку, но смешивание языков на уровне исходников усложняет оформление модулей. Динамическая библиотека даёт независимое обновление, однако требует управления версиями, загрузкой и совместимостью во время запуска.

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

Подход Граница интеграции Сильная сторона Основная цена
Статическая библиотека Машинный код Delphi Прямые вызовы и автономная работа Отдельная сборка под платформу и архитектуру
Исходный код Уровень языков и типов Простая отладка и изменение логики Требуется Delphi-оснащённый инструментарий
Динамическая библиотека Загрузчик и ABI процесса Независимое обновление модуля Версии, подпись и путь загрузки
Удалённый сервис Сетевой протокол Один сервер для разных клиентов Задержка, доступность и обработка отказов