メインコンテンツまでスキップ

FFI

このドキュメントは、Wave言語における外部で実装された関数を呼び出すためのFFI(外国機能インターフェース)規格を説明します。 FFIを介して、Waveプログラムは他の言語で書かれたネイティブライブラリと直接連携することができます。


概要

WaveのFFIは宣言ベースで動作します。 外部関数はWaveコードで実装されず、該当する関数がどのABI(アプリケーションバイナリインターフェース)に従うのかを明示するだけです。 実際の実装はリンク段階で外部ライブラリから解決されます。

FFIはコンパイル時に関数の存在のみを宣言し、実行ファイル生成時にリンカが実際のシンボルを接続する方法で動作します。


extern宣言

外部関数はexternキーワードを使用して宣言します。 すべての外部関数宣言にはABI指定が必須です。

extern(abi) fun 関数名(引数...) -> 返却型;

ABI指定

extern宣言には必ずABIを明示しなければなりません。 ABIは外部関数がどの呼び出し規約とシンボル規則に従うかを示します。

extern(c) fun printf(fmt: ptr<u8>);
extern(rust) fun rust_func(i32);

ABIは識別子として扱われ、言語の観点で特定のABIをデフォルトとして提供しません。 すべての外部関数は明示的にABIを指定しなければなりません。


関数単位のextern宣言

外部関数を1つ宣言する場合は次のように書きます。

extern(c) fun InitWindow(width: i32, height: i32, title: ptr<u8>);

この宣言は、C ABIに従うInitWindowシンボルが外部ライブラリーに存在することを意味します。


ブロック単位のextern宣言

同じABIを使用する外部関数が複数ある場合、ブロック形式でまとめて宣言することができます。

extern(c) {
fun InitWindow(width: i32, height: i32, title: ptr<u8>);
fun CloseWindow();
fun BeginDrawing();
fun EndDrawing();
}

ブロック単位の宣言は、関数単位の宣言と意味的に完全に同じであり、単に可読性と構造化のための文法です。


シンボル名指定

一部のABIでは、Wave関数名と実際のリンカーシンボル名が一致しない場合があります。 この場合、外部関数が接続される実際のシンボル名を文字列で明示することができます。

関数単位のシンボル指定

extern(rust, "_ZN4test10rust_func117h123abcE")
fun rust_func(i32);

この宣言は、rust_funcを呼び出す際に_ZN4test10rust_func117h123abcEシンボルを使用するように指定します。


ブロック単位のシンボル指定

ブロック単位の宣言では、各関数の後にシンボル名を個別に指定することができます。

extern(rust) {
fun rust_func1(i32) "_ZN4test10rust_func117h123abcE";
fun rust_func2(i32) "_ZN4test10rust_func217h456defE";
}

ポインタータイプ

ポインターは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では次の機能を提供しません。

  • 関数ポインター
  • コールバック関数
  • 自動メモリ管理
  • 言語間の例外処理連動

これらの機能は今後のバージョンで別途扱われる可能性があります。