導入
Go言語は高い並行処理性能や標準ライブラリの充実度が魅力ですが、既存のC/C++プロジェクトやPython、Rubyなどの他言語環境から「Goで書いた特定の処理」を再利用したいという場面があります。そのような時に重要なのが、Goを共有ライブラリとして出力する「-buildmode=c-shared」です。この手法を用いることで、Goの強力なロジックを言語の垣根を超えて活用できるようになります。
基礎知識
通常、Goでプログラムを作成すると単一の実行ファイルが出力されます。しかし、-buildmode=c-sharedを指定すると、OSに応じた共有ライブラリ(Linuxなら.so、Windowsなら.dll)が生成されます。
この際、Goの関数を外部から呼び出すためには、//export 関数名 という特殊なコメント(ディレクティブ)を付与する必要があります。また、Goのランタイムを管理する必要があるため、C言語側から呼び出す際は「cgo」の仕組みを介したインターフェース設計が不可欠です。
実装/解決策
共有ライブラリを作成する手順は以下の3ステップです。
1. Goコードに「import “C”」を追加し、公開したい関数に「//export」を記述する。
2. 「go build -buildmode=c-shared -o ライブラリ名.so ソースファイル.go」を実行する。
3. 生成されたヘッダーファイル(.h)をC言語側でインクルードしてリンクする。
サンプルプログラム
以下は、整数の加算を行う単純なGoのコード例です。
// main.go
package main
import “C”
//export Add
// Add関数を外部公開するためのエクスポート宣言
func Add(a, b int) int {
return a + b
}
// main関数は必須ですが、共有ライブラリとして使う場合は空で構いません
func main() {}
// ビルドコマンド: go build -buildmode=c-shared -o libmath.so main.go
応用・注意点
現場で活用する上で注意すべき点がいくつかあります。
一つ目はメモリ管理です。Goと他言語の間でメモリをやり取りする場合、C言語側で確保したメモリをGoで解放したり、その逆を行ったりすると、ガベージコレクション(GC)の整合性が取れずクラッシュする原因になります。基本的には、データの受け渡しはプリミティブな型に留めるか、CGOのメモリ管理ルールに従うことが重要です。
二つ目はランタイムの初期化です。共有ライブラリが読み込まれた際、Goのランタイムが自動的に初期化されますが、スレッドローカルストレージの扱いに起因する制約があるため、マルチスレッド環境から頻繁に呼び出す場合は、呼び出し元の言語側でのスレッド管理にも注意を払ってください。

コメント