タイムテーブル Timetable

タイムテーブルに戻る
Go における FFI のこれまでとこれから
FFI ( Foreign Function Interface ) とは、他言語で実装された機能を呼び出すための仕組みです。とりわけ、C/C++言語で実装されたライブラリの機能を別の言語から呼び出す用途で広く利用されています。
ある言語から他の言語で実装された機能を呼び出すためには、引数や返り値を変換したり、メモリ管理やコールバックのようなトランポリンを適切に処理する必要があります。
加えて、C/C++ のような言語の場合はコンパイルが必要になるため、どのコンパイラ・リンカを使ってどのようなオプションでビルドし、その成果物をどうやって利用するかを考える必要があります。
Go 言語では cgo を利用することで C/C++ 言語の機能を利用することができ、C/C++言語向けのコンパイラやリンカの設定を適切に行うことで、Go のビルド時に同時に C/C++ 言語のコンパイルやリンク処理を行うことができます。
それだけでなく、コンパイルに必要な C/C++ のソースコードを Go コードと一緒に配布し、Go ビルド時に同時にコンパイルしたC/C++の成果物を Go コードの成果物と合わせて静的リンクすることで、単一バイナリとして配布することも可能です。
このような仕組みは、RubyやPerlのように動的リンクが必要なスクリプト言語でFFIを利用する場合と比べて、ポータビリティが高く、シングルバイナリを作成することが得意な Go との相性も抜群です。
cgo が使いやすいこともあり、cgo を利用した Go のライブラリは多く作られ、広く利用されてきました。
しかし、cgo を利用する以上、Go だけでビルドが完結する世界を作ることはできません。clang などの C/C++ コンパイラがインストールされている必要があるだけでなく、Go の長所のひとつであるクロスコンパイルを利用したマルチアーキテクチャに対応することも困難です。 このことから、cgo は最良の選択肢とまでは言えませんでした。
しかし近年、WebAssembly が普及したことで、Go の FFI のあり方が変わりつつあります。
C/C++ ライブラリをあらかじめ WebAssembly に変換し、Go では WebAssembly のランタイムを組み込みつつ、変換した WebAssembly を embed パッケージを使って埋め込んで実行時にロードすることで、シングルバイナリで配布するメリットはそのままに、cgo を使わず、クロスコンパイルも可能なライブラリを作ることができるようになったのです。
これにより、WebAssembly を利用した FFI を採用した Go のライブラリが増えています。
私自身、過去にこの方法を利用してライブラリを作成しました。
しかし、このアーキテクチャも完璧とは言えません。WebAssembly を利用することによるパフォーマンス面でのオーバーヘッドやメモリ管理の問題はありますし、そもそも C/C++ ライブラリを Go から利用しやすい形の WebAssembly に変換するのも大変です。
そこで私は、C/C++ ライブラリから Go から利用しやすい形の WebAssembly を自動的に作るためのツールの作成や、生成された WebAssembly を Goコード(とPlan9 Assembly) に自動変換する仕組みを作成することで、C/C++ ライブラリから Go + asm に自動的に変換するパイプラインをCI上で完結できる仕組みを作りました。
これらを利用することで、WebAssembly の課題だったパフォーマンスの側面を解決しつつ、C/C++ の機能を Go から利用できる新しい FFI のアーキテクチャを構築できるのではないかと考えています。
本発表では、過去に Perl や Ruby、Go などいくつかの言語で FFI を利用してライブラリを開発してきた経験や、先に挙げたツールを作成したことによる知見を活かし、Go と FFI がいままでどのように付き合ってきて、これからどうなっていくのかを自分なりにまとめた結果を発表したいと考えています。
ただ、自身が開発したツールを使えばこうできます、という話ではなく、FFI とはどのようなもので、ライブラリを作るにはどのような注意が必要なのか、Go でそれを解決するにはどのように実装する必要があり、必要となる作業をできるだけ簡単にするためにどんなものを作り、それによって何が解決したのかといったように、経験から得た知見を体系的に説明します。
この発表を聞くことで、自分で Go で FFI を利用したライブラリを開発するにはどのような技術・知識が必要かを知るとともに、過去、そして未来のアーキテクチャについて理解を深めることで、自分なりの Go と FFI のあり方について考える機会になっていただければ嬉しいです。
Software Engineer
I am a software engineer at Mercari, Inc. and a member of the Engineering Productivity team. I love develop OSS and I made a lot of work (Here are examples). - [2012] gperl: a fast Perl5 language - [2013] PerlMotion: a toolchain for iOS and OS X development using the Perl5 - [2019] go-yaml: a yet another YAML parser written in Go - [2020] go-json: a fast JSON serializer in Go - [2022] bigquery-emulator: a emulator of BigQuery