外部関数インターフェース
外部関数インターフェイス( FFI )は、あるプログラミング言語で書かれたプログラムが、別のプログラミング言語で記述またはコンパイルされたルーチンを呼び出したり、サービスを利用したりできるようにするメカニズムです。FFI は、バイナリダイナミック リンク ライブラリへの呼び出しが行われるコンテキストでよく使用されます。
ネーミング
この用語はCommon Lispの仕様に由来し、言語間呼び出しを可能にするプログラミング言語機能を明示的に指しています。[要出典]この用語はHaskell [ 1] Rust [ 2] PHP [ 3] Python、LuaJIT ( Lua ) [4] [5]の インタープリタおよびコンパイラの ドキュメントでも公式によく使用されています。[6]他の言語では他の用語が使用されています。Adaには言語バインディングがあり、Java にはJava Native Interface (JNI) またはJava Native Access (JNA)があります。外部関数インターフェースは、このようなサービスを提供するメカニズムの一般的な用語になっています。
手術
外部関数インターフェースの主な機能は、あるプログラミング言語 (ホスト言語、または FFI を定義する言語)のセマンティクスと呼び出し規則を、別のプログラミング言語 (ゲスト言語) のセマンティクスと規則と組み合わせることです。このプロセスでは、両方のランタイム環境とアプリケーション バイナリ インターフェースも考慮する必要があります。これは、いくつかの方法で実行できます。
- ホスト言語から呼び出し可能なゲスト言語関数は、多くの場合、何らかの互換性ライブラリを使用して、特定の方法で指定または実装する必要があります。
- 必要な翻訳を実行する適切なグルーコードを使用してゲスト言語関数を自動的にラップするツールの使用。
- ラッパーライブラリの使用
- 言語間で使用できるホスト言語機能のセットを制限します。たとえば、C から呼び出される C++ 関数には、(一般に) 参照パラメータを含めたり、例外をスローしたりすることはできません。
FFI は、以下の考慮事項によって複雑になる可能性があります。
- 一方の言語がガベージ コレクション(GC)をサポートし、もう一方の言語がサポートしていない場合、非 GC 言語コードがもう一方の言語の GC の失敗の原因にならないように注意する必要があります。たとえば、JNI では、Java から受信したオブジェクト参照を「保持する」C コードは、この情報を Java仮想マシンまたはJava ランタイム環境(JRE) に正常に伝達する必要があります。そうしないと、C がオブジェクトの使用を終了する前に Java がオブジェクトを削除する可能性があります。(C コードは、C がそのオブジェクトを必要としなくなったら、そのオブジェクトへのリンクを明示的に解放する必要があります。)
- 複雑または非自明なオブジェクトやデータ型は、ある環境から別の環境にマッピングするのが難しい場合があります。
- 上記のマッピングの問題により、両方の言語で可変オブジェクトの同じインスタンスへの参照を維持できない可能性があります。
- 1 つの言語または両方の言語が仮想マシン(VM)上で実行される場合があります。また、両方の言語が実行される場合、これらは異なる VM であることが多いです。
- 言語間の継承や、型システム間やオブジェクト構成モデル間などのその他の違いは、特に難しい場合があります。
FFI の例としては、次のようなものがあります。
- Ada言語バインディングでは、外部関数を呼び出すだけでなく、その関数とメソッドをエクスポートして非Adaコードから呼び出すこともできます。[7]
- C++とCは重要な共通サブセットを共有しているため、 FFI はわずかです。C ++ でのextern "C"宣言の主な効果は、C++ の名前マングリングを無効にすることです。他の言語では、別のユーティリティまたはミドルウェアが使用されます。例:
- GNOME プロジェクト: GObject イントロスペクション
- スウィグ
- Chromiumプロジェクト: BlinkとV8エンジンは、標準の JavaScript インターフェース用のインターフェース記述言語(IDL) コンパイラを使用します。
- その他のIDLコンパイラ
- CleanはC言語またはstdcall呼び出し規約に従うすべての言語との双方向FFIを提供します。[8] [9]
- コモンリスプ
- コンパイル済みネイティブ インターフェイス(CNI)。GNU コンパイラ環境で使用される JNI の代替です。
- コンポーネント オブジェクト モデルの基盤の 1 つは、文字列と配列にVisual Basicと同じ型をネイティブで使用する共通インターフェイス形式です。
- DはC++と同じように、extern "C"からextern (C++)まで行います。
- Dartにはモバイル、コマンドライン、サーバーアプリケーション用のネイティブCコードを呼び出すためのdart:ffi [10]ライブラリが含まれています。
- Python、Perl、Tcl、Rubyなどの動的プログラミング言語はすべて、C、C++、または C/C++ 呼び出し規則に従うその他の言語で記述されたネイティブ コードに簡単にアクセスできます。
- Factor には、 C、Fortran、Objective-C、Windows COM 用の FFI があり、これらすべてにより、任意の共有ライブラリを動的にインポートして呼び出すことができます。
- Fortran 2003には、相互運用可能なデータ型(組み込み型とPOD構造体の両方)、相互運用可能なポインタ、相互運用可能なグローバルデータストア、FortranからCを呼び出すメカニズム、およびCからFortranを呼び出すメカニズムを提供するモジュールISO_C_BINDINGがあります。 [11] Fortran 2018標準ではこれが改良されました。
- Goは擬似パッケージを介してCコードを直接呼び出すことができます
"C"
。[12] - Java が JavaScript にコンパイルされるGoogle Web Toolkit (GWT) には、Javaソース コードから任意の JavaScript 関数を呼び出したり、JavaScript から Java にコールバックしたりできる JSNI という FFI があります。
- ハスケル
- Java Native Interface (JNI) は、Java が展開されているほとんどのシステムで推奨されるシステム言語であるJavaと C/C++ 間のインターフェイスを提供します。Java Native Access (JNA) は、グルーコードを記述せずにネイティブライブラリとのインターフェイスを提供します。別の例としては、JNR があります。
- Luaのジャストインタイム実装であるLuaJITには、外部C関数の呼び出しや純粋なLuaコードからのCデータ構造の使用を可能にするFFIがあります。[4] [5] : 35
- Nimには、 C、C++、Objective-Cのソースを使用できる FFI があります。また、 JavaScript とのインターフェースも可能です。
- JavaScript は通常、システム ライブラリや実行するコマンドに直接アクセスできない
Web ブラウザーランタイム内で実行されますが、例外もいくつかあります。
- Node.js は、事前コンパイルされたモジュールを開く関数を提供し
.node
、それによって非組み込みリソースへのアクセスが可能になります。 - Denoは関数を介して一種のFFIインターフェースを提供する
dlopen(...)
。[13] - Bunは
bun:ffi
JavaScriptからネイティブライブラリを効率的に呼び出すための組み込みモジュールを提供しています。 [14]
- Node.js は、事前コンパイルされたモジュールを開く関数を提供し
- Juliaには
ccall
C(およびFortranなどの他の言語)を呼び出すキーワードがあります。 [15]一方、同様の定型句のないサポートを提供するパッケージは、Python [16](OOサポートやGCサポートなどを提供する)、Java(Scalaなどの他のJDK言語をサポート)、Rなどの言語で利用できます。Cxx.jlパッケージを使用すると、C++との対話型使用も可能です。 - PhoneGap(以前はApache Callbackという名前でしたが、現在はApache Cordovaになっています)は、HTML、CSS、JavaScriptを使用してネイティブモバイルアプリケーションを構築するためのプラットフォームです。また、加速度計、カメラ(PhotoLibraryとSavedPhotoAlbumも)、コンパス、ストレージ(SQLデータベースとlocalStorage)、通知、メディアとキャプチャ(再生と録音、またはオーディオとビデオ)、ファイル、連絡先(アドレス帳)、イベント、デバイス、接続情報など、携帯電話のネイティブ機能のメソッドとプロパティにアクセスするためのJavaScriptコールバック関数を介したFFIも備えています。[1]、[2]。
- PHPはCにFFIを提供する。[17]
- Python はctypes モジュールと cffi モジュールを提供します。たとえば、ctypes モジュールは、共有ライブラリまたはダイナミックリンクライブラリ(DLL) から C 関数をオンザフライで読み込み、次のように単純なデータ型を Python と C のセマンティクス間で自動的に変換できます。
import ctypes libc = ctypes . CDLL ( '/lib/libc.so.6' ) # Linux/Unix の場合 t = libc . time ( None ) # 同等の C コード: t = time(NULL) print ( t )
- P/Invokeは、Microsoft共通言語ランタイムとネイティブ コード間のインターフェイスを提供します。
- RacketにはマクロをベースにしたネイティブFFIがあり、任意の共有ライブラリを動的にインポートすることができます。[18] [19]
- RakuはRuby、Python、Perl、Brainfuck、Lua、C、C++、Go、Scheme(Guile、Gambit)、Rustを呼び出すことができる[20] [21]
- Ruby は、ffi gem または標準ライブラリ fiddle を通じて FFI を提供します。
「フィドル」が必要 libm =フィドル。dlopen ( '/lib/libm.so.6' ) # 以下と同等: double floor(double x); floor = Fiddle :: Function . new ( libm . sym ( 'floor' ), # ptr は Fiddle::Handle の参照関数 (またはシンボル) です。[ Fiddle :: TYPE_DOUBLE ] , # args は ptr 関数に渡される引数の配列です。Fiddle :: TYPE_DOUBLE # ret_typeは関数の戻り値の型です) # 以下と同等: floor(3.14159); floor . call ( 3 . 14159 ) #=> 3.0
- Rustは、様々な標準アプリケーションバイナリインターフェース(ABI)を持つ関数への外部関数インターフェースを定義します。[22] Elixirとのインターフェース用のライブラリであるRustlerもあります。
- Visual Basic には、非 Unicode C 関数を呼び出すことができる宣言型構文があります。
- Wolfram Language は、C++、Java、 .NETなどの言語とのバインディングを使用して、他の言語間でのコードの双方向呼び出しを可能にする Wolfram Symbolic Transfer Protocol (WSTP) というテクノロジーを提供します。
- Zigは組み込み
cImport
関数を使用してCにFFIを提供します。[23]
さらに、多くのFFIは自動的に生成できます。たとえば、SWIGです。ただし、拡張言語の場合、ゲストとホストの関係の意味の反転が発生する可能性があります。これは、拡張言語の小さな部分が、より大きなホスト言語のサービスの呼び出し元となるゲストである場合です。たとえば、GIMP用の小さなプラグイン[24]を作成する場合などです。[25]
一部の FFI は独立した関数に制限されていますが、他の FFI ではオブジェクトまたはクラスに埋め込まれた関数の呼び出し (メソッド呼び出しと呼ばれることが多い) も許可されます。さらに、言語の境界を越えて複雑なデータ型またはオブジェクトの移行を許可する FFI もあります。
ほとんどの場合、FFI は高水準言語で定義されるため、低水準言語(通常はCやC++などのシステム プログラミング言語)で定義および実装されたサービスを使用できます。これは通常、 OS API が定義されている言語でオペレーティング システム(OS) サービスにアクセスするため、またはパフォーマンス目標のために使用されます。
多くの FFI は、呼び出された言語がホスト言語でサービスを呼び出す手段も提供します。
外部関数インターフェイスという用語は、一般的に、Microsoft Common Language Runtime などの多言語ランタイムを説明するために使用されません。Microsoft Common Language Runtimeでは、共通の基盤が提供され、CLR 準拠の言語であればどれでも、他の言語で定義されたサービスを使用できます。(ただし、この場合、CLR にはランタイム外部を呼び出すための FFI であるP/Invoke が含まれています。) さらに、Java リモート メソッド呼び出し(RMI)、RPC、CORBA、SOAP、D-Busなどの多くの分散コンピューティング アーキテクチャでは、異なるサービスを異なる言語で記述できます。このようなアーキテクチャは、一般的に FFI とは見なされません。
特別なケース
ClojureとJava 、 ElixirとErlangのように、言語が同じバイトコード VM にコンパイルされる特殊なケースがいくつかあります。インターフェースがないため、厳密に言えば FFI ではありませんが、ユーザーには同じ機能を提供します。
参照
- 言語の相互運用性
- インターフェース定義言語
- 呼び出し規約
- 名前のマングリング
- アプリケーションプログラミングインターフェース
- アプリケーションバイナリインターフェース
- アプリケーション仮想マシンの比較
- スウィグ
- リモートプロシージャコール
- libffi
参考文献
- ^ 「FFI 入門」。HaskellWiki。2015年6 月 19 日閲覧。Haskell
の FFI は、他の言語 (この時点では基本的に C) から関数を呼び出すために、また C が Haskell 関数を呼び出すために使用されます。
- ^ "std::ffi". Rust-lang.org . 2021年4月1日閲覧。
このモジュールは、他のプログラミング言語や基盤となるオペレーティングシステムなど、非Rustインターフェース間でデータを処理するためのユーティリティを提供します。主にFFI(Foreign Function Interface)バインディングや、Cのような文字列を他の言語と交換する必要があるコードに使用されます。
- ^ 「PHP FFI マニュアル」。PHPマニュアル。2023年8 月 31 日閲覧。
定義された C 変数は、FFI インスタンスのプロパティとして使用できます。
- ^ ab Mike Pall. 「FFI ライブラリ」。Luajit.org。2013年 9 月 29 日閲覧。
- ^ abハインツ、ヨアキム、ホフマン、アレックス、マッカーディ、イアン (2013)。Ways Ahead: Proceedings of the First International Csound Conference。ニューカッスル・アポン・タイン: Cambridge Scholars Publishing。ISBN 978-1-4438-5122-0. OCLC 855505215。
- ^ 「CFFI ドキュメント」 。2015年6 月 19 日閲覧。Python
用 C 外部関数インターフェイス。目標は、C で記述されたインターフェイス宣言を使用して、コンパイルされた C コードを Python から呼び出す便利で信頼性の高い方法を提供することです。
- ^ 「他の言語へのインターフェース」 Adaic.org . 2013年9月29日閲覧。
- ^ 「Foreign Export」 . 2020年5月25日閲覧。
- ^ 「Clean から C を呼び出す」 。2018年 4 月 25 日閲覧。
- ^ 「dart:ffi library」. 2020年1月1日閲覧。
- ^ 「'fortran-iso-c-binding' タグ wiki」. Stack Overflow .
- ^ "cgo". Goプログラミング言語. 2015年8月23日閲覧。
- ^ 「Foreign Function Interface | マニュアル」。Deno 。 2023年2月8日閲覧。
- ^ 「FFI API」。Bun Docs。
- ^ 「C および Fortran コードの呼び出し」。JuliaLang.org。2018年 2 月 11 日閲覧。
- ^ PyCall.jl: Julia 言語から Python 関数を呼び出すパッケージ、JuliaPy、2018-02-08、2018-02-11取得
- ^ 「PHP: FFI - マニュアル」。PHP グループ。2019年6 月 13 日閲覧。
- ^ Eli Barzilay. 「Racket Foreign Interface」. Docs.racket-lang.org . 2013 年 9 月 29 日閲覧。
- ^ "TR600.pdf" (PDF) . 2009年9月2日時点のオリジナル(PDF)よりアーカイブ。 2013年9月29日閲覧。
- ^ 「インライン実装」。2017年8月15日閲覧。
- ^ 「Native Call」 。 2017年8月15日閲覧。
- ^ 「extern 関数を使用して外部コードを呼び出す」。2019年 6 月 1 日閲覧。
- ^ 「C ヘッダーファイルからのインポート」。Zig Software Foundation。2021年 3 月 11 日閲覧。
- ^ 「4. サンプルスクリプト」Gimp.org. 2001-02-04 . 2013-09-29閲覧。
- ^ 「Script-Fu と GIMP 用プラグイン」Gimp.org 。2013年 9 月 29 日閲覧。
外部リンク
- c2.com: 外部関数インターフェース
- Haskell 98 外部関数インターフェース
- アレグロ コモンリスプ FFI
- occam-pi 用の外部関数インターフェースジェネレーター
- UFFI: Lisp ユニバーサル外部関数インターフェース
- CFFI: Common Lisp 用の共通外部関数インターフェース
- Java ネイティブ インターフェース: プログラマーズ ガイドと仕様
- JNI仕様
- JSNI (JavaScript ネイティブ インターフェース)
- さまざまなプロセッサ、OS、呼び出し規約に対応したアセンブリ呼び出しカーネルを使用する dyncall ライブラリ
- FFCALL
- C/呼び出し
- libffi