FFI
このドキュメントは、Wave言語における外部で実装された関数を呼び出すためのFFI(外国機能インターフェース)規格を説明します。 FFIを介して、Waveプログラムは他の言語で書かれたネイティブライブラリと直接連携することができます。
概要
WaveのFFIは宣言ベースで動作します。 外部関数はWaveコードで実装されず、該当する関数がどのABI(アプリケーションバイナリインターフェース)に従うのかを明示するだけです。 実際の実装はリンク段階で外部ライブラリから解決されます。
FFIはコンパイル時に関数の存在のみを宣言し、実行ファイル生成時にリンカが実際のシンボルを接続する方法で動作します。
extern宣言
外部関数はexternキーワードを使用して宣言します。
현재 Wave에서는 ABI 지정이 반드시 필요하며, extern(c)만 지원합니다.
extern(c) fun 함수명(인자들...) -> 반환타입;
ABI指定
extern 선언에는 ABI를 명시해야 합니다.
현재 지원되는 ABI는 c 하나입니다.
extern(c) fun printf(fmt: ptr<u8>);
extern(rust) 같은 선언은 파싱될 수 있어도 의미 분석 단계에서 에러가 발생합니다.
関数単位の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(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では次の機能を提供しません。
- 関数ポインター
- コールバック関数
- 自動メモリ管理
- 言語間の例外処理連動
これらの機能は今後のバージョンで別途扱われる可能性があります。