Руководители проекта - Азат Абдуллин, Марат Ахин, Михаил Беляев (JetBrains Research)
Участники проекта - Александрина Стрельцова (СП, третий курс).
В проектах на Kotlin часто возникает необходимость использовать нативные библиотеки (например, в исследовательских проектах, SMT-солверы). При этом на каждой платформе способ обращения к нативным библиотекам свой (cinterop tool для Kotlin/Native, JNA для JVM, различные варианты для JS в зависимости от того, фронтенд или бекенд разрабатывается).
Целью проекта является объединение этих способов в единый мультиплатформенный интерфейс и оформление этого интерфейса в плагин для системы сборки (в данном случае для gradle).
Немного о том, как проходил процесс работы до момента написания отчёта.
Cначала я разбиралась с тем, как устроены мультиплатформенные проекты на Kotlin и как использовать cinterop и JNA.
После этого началось продумывание чернового варианта будущего интерфейса; придумать свой собственный
интерфейс для обращения к нативным бибилотекам - сложная задача, к тому же такой подход подразумевает,
что пользователи плагина должны сначала ознакомиться с этим интерфейсом, поэтому было решено использовать
kotlinx.cinterop или com.sun.jna в качестве базы; в конечном итоге был выбран kotlinx.cinterop
(он обладает более подробной и понятной документацией и более строгой системой типов)
Так как было решено ориентироваться на то, как нативные библиотеки используются в Kotlin/Native, подключение
библиотек на jvm и native осуществляется через .def файлы (на данный момент с использованием написаной
для будущего gradle плагина функцией processDefFiles)
Таким образом, что сделано:
- продуман черновой вариант будущего интерфейса
- осуществлено подключение нативных библиотек к
jvmиnativeс помощью системы сборки через.defфайлы
Основной трудностью является разный подход в отображении типов из C в Java/Kotlin на jvm и native.
Подходы в отображении примитивных типов и указателей удалось объединить без проблем, но например для массивов,
а также для callback-ов общего подхода придумать пока не удалось.
Для того чтобы использовать JNA, необходимо сначала написать интерфейс, содержащий объявления нативных функций,
которые мы планируем вызывать из нашего кода на jvm. Для нашего проекта такие интерфейсы должны
генерироваться, а не создаваться вручную. Сейчас одной из задач является определение оптимального способа для
генерации таких интерфейсов (одним из вариантов является использование инструмента JNAerator)
Что в целом ожидается от будущего плагина: подключение нативной библиотеки с использованием плагина должно приводить
к генерации файла с функциями из этой библиотеки в common модуле с реализациями в платформенных модулях (jvm и native),
использующими тот способ обращения к нативной библиотеке, который существует для данной платформы.
Таким образом, что еще нужно сделать:
- научиться генерировать интерфейсы, необходимые для JNA
- генерировать
expectфункции вcommonмодуле сactualфункциями в платформенных модулях (эти функции по сути обертки, которые просто пробрасывают вызов функции до вызова с использованием технологии, используемой для данной платформы)
Весь код проекта написан на Kotlin.
Используемые технологии:
- мультиплатформенные проекты Kotlin
- Gradle
- библиотеки
kotlinx.cinteropиcom.sun.jna
Каждую неделю встречаемся командой по видеосвязи. Обсуждаем сделанное и планируем задачи на следующую неделю.
Внутри есть пример проекта,
использующий нативную библиотеку SMT-солверов. В проекте функции из нативной библиотеки использованы в common модуле (example.c переписан на Kotlin, функция main из src/commonMain/kotlin/main.kt может
быть вызвана как на jvm, так и на native платформе)