Перейти к основному содержимому

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 во внешний проект.