FFI
Этот документ описывает спецификацию FFI (интерфейс внешней функции) для вызова функций, реализованных извне, в языке Wave. С помощью FFI программы на Wave могут напрямую взаимодействовать с нативными библиотеками, написанными на других языках.
Обзор
FFI языка Wave работает на основе деклараций. Внешние функции не реализуются в коде Wave, а просто указывают на поддержку определенного ABI (Application Binary Interface). Фактическая реализация разрешается на этапе связывания из внешней библиотеки.
FFI функционирует за счёт декларации существования функции во время компиляции, а линковщик связывает фактический символ при создании исполняемого файла.
Объявление extern
Внешние функции объявляются с использованием ключевого слова extern.
В настоящее время в Wave требование указания ABI является обязательным, и поддерживается только extern(c).
extern(c) fun function_name(args...) -> return_type;
Указание ABI
В объявлениях extern необходимо указывать ABI.
В настоящее время поддерживается только ABI c.
extern(c) fun printf(fmt: ptr<u8>);
Объявление наподобие extern(rust) будет проанализировано, но вызовет ошибку на этапе семантического анализа.
Объявление extern на уровне функции
Для объявления одной внешней функции используйте следующий синтаксис.
extern(c) fun InitWindow(width: i32, height: i32, title: ptr<u8>);
Это объявление показывает, что символ InitWindow, следующий C ABI, присутствует во внешней библиотеке.
Объявление extern на уровне блока
Если несколько внешних функций используют одинаковый ABI, их можно объявить в виде блока.
extern(c) {
fun InitWindow(width: i32, height: i32, title: ptr<u8>);
fun CloseWindow();
fun BeginDrawing();
fun EndDrawing();
}
Объявления на уровне блока семантически полностью совпадают с объявлениями на уровне функции и являются синтаксисом, улучшающим читаемость и структуризацию.
Указание имени символа
В некоторых ABI имя функции Wave и фактическое имя символа линковки может не совпадать. В этом случае действительное имя символа, с которым будет связано внешняя функция, можно указать в виде строки.
Указание символа на уровне функции
extern(c, "puts")
fun rust_func(i32);
Это объявление определяет, что при вызове rust_func фактически используется символ puts в линковке.
Указание символа на уровне блока
В объявлениях на уровне блока имя символа можно указать отдельно после каждой функции.
extern(c) {
fun my_puts(ptr<i8>) "puts";
fun my_strlen(ptr<i8>) "strlen";
}
Тип указателя
Указатели представлены как ptr<T>.
ptr<u8>
ptr<MyStruct>
ptr<T> напрямую соответствует указателю внешнего языка, и управление правами владения памятью или жизненным циклом не осуществляется Wave.
Использование структуры
Структуры могут быть использованы в качестве аргументов или возвращаемых значений внешней функции.
struct Color {
r: u8,
g: u8,
b: u8,
a: u8,
}
При использовании структуры в FFI порядок полей сохраняется в соответствии с декларированным, и соблюдается необходимое ABI ра сположение памяти.
Вызов внешней функции
Функции, объявленные с помощью extern, вызываются тем же способом, что и обычные функции.
fun main() -> i32 {
InitWindow(800, 600, "Wave");
BeginDrawing();
EndDrawing();
CloseWindow();
return 0;
}
При вызове нет синтаксических различий, соглашение о вызове и связывание символов осуществляется полностью через ABI и линковку.
Линковка
Реальная реализация внешней функции предоставляется из внешней библиотеки на этапе линковки. Компилятор Wave создает объектные файлы с включением вызовов внешних функций и разрешает символы с помощью указанной библиотекой линкера.
Метод указания библиотеки осуществляется со помощью инструментов сборки и опций CLI.
Ограничения
Wave не предоставляет следующие функции.
- Указатель на функцию
- Функция обратного вызова
- Автоматическое управление памятью
- Интеграция обработки исключений между я зыками
Эти функции могут быть рассмотрены в последующих версиях.
