export
export публикует функцию, реализованную на Wave, как внешний символ компоновщика. Если extern импортирует внешнюю функцию в Wave, то export делает функцию Wave доступной из C, Rust, C++, Zig или другого нативного языка через объектный файл.
Обзор
FFI в Wave работает в двух направлениях.
extern(c)объявляет функцию из внешней библиотеки, чтобы код Wave мог ее вызвать.export(c)выводит тело функции Wave как внешний ABI-символ.
Обе формы используют похожий ABI-заголовок, но смысл у них противоположный. При extern тело функции находится вне Wave. При export тело функции находится внутри Wave.
Сейчас поддерживается только ABI экспорта c.
Экспорт отдельной функции
Базовая форма:
export(c) fun add(a: i32, b: i32) -> i32 {
return a + b;
}
Этот код создает публичный символ add. Полученный объектный файл можно скомпоновать с внешним кодом, ожидающим C ABI.
Имена символов
Имя функции в Wave и экспортируемое имя символа могут различаться.
export(c, "wave_add_i32") fun add_i32(a: i32, b: i32) -> i32 {
return a + b;
}
Здесь имя в Wave — add_i32, но объектный файл экспортирует wave_add_i32. Внешний язык должен объявлять и вызывать именно это имя символа.
Экспорт блоком
Несколько функций с одним ABI можно сгруппировать в блок.
export(c) {
fun wave_inc_i32(a: i32) -> i32 {
return a + 1;
}
fun wave_dec_i32(a: i32) -> i32 {
return a - 1;
}
}
Экспорт блоком использует имя каждой функции как публичный символ. export(c, "symbol") { ... } запрещен, потому что один alias для нескольких функций вызвал бы конфликт символов.
Вызов из C
Соберите файл Wave как объектный файл.
wavec build math.wave --emit=obj -o math.o
Объявите экспортированный символ в C.
#include <stdio.h>
extern int wave_add_i32(int a, int b);
int main(void) {
printf("%d\n", wave_add_i32(40, 2));
return 0;
}
Затем скомпонуйте C-код и объект Wave обычным компоновщиком.
cc main.c math.o -o app
extern и export
extern(c) означает, что Wave использует внешний символ.
extern(c) fun puts(s: ptr<i8>) -> i32;
export(c) означает, что внешний код может использовать символ Wave.
export(c) fun answer() -> i32 {
return 42;
}
Оба механизма относятся к FFI, но направление разное.
Ограничения
- Поддерживается только
export(c). - Экспортируемые функции не могут быть generic.
- Экспорт блоком не может использовать общий alias символа.
- Для стабильной совместимости пока рекомендуется использовать целые числа, числа с плавающей точкой, bool и указатели.
- Агрегатные типы, такие как structs и arrays, требуют более строгих ABI-правил и могут быть стабилизированы позже.
exportв основном полезен для объектных файлов и библиотек, а не для обычного исполняемого файла.
Рекомендуемые случаи использования
- Предоставлять утилитарные функции Wave как библиотеку C ABI.
- Вызывать функции Wave из Rust, C, C++, Zig или другого нативного языка.
- Постепенно подключать написанные на Wave модули
front,utilsили нативные модули без runtime к существующей системе сборки. - Позволить Vex или другому инструменту сборки линковать объектные файлы Wave во внешний проект.
