Руководители проекта - Азат Абдуллин, Марат Ахин, Михаил Беляев (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
платформе)