[インデックス 10480] ファイルの概要
このコミットでは、Go言語のcgo
ツールにおいて、動的ライブラリからのコールバックをサポートするための変更が導入されました。具体的には、以下のファイルが変更または新規追加されています。
misc/cgo/testso/Makefile
: 新規追加。動的ライブラリとテスト実行のためのMakefile。misc/cgo/testso/cgoso.go
: 新規追加。Go側でCから呼び出されるコールバック関数を定義。misc/cgo/testso/cgoso_c.c
: 新規追加。動的ライブラリとしてビルドされるCコードで、Goのコールバックを呼び出す。misc/cgo/testso/main.go
: 新規追加。テスト用のGoプログラム。src/Make.pkg
: 変更。_cgo1_.o
の依存関係にCGO_DEPS
を追加。src/cmd/cgo/out.go
: 変更。#pragma dynexport
ディレクティブの追加。src/run.bash
: 変更。misc/cgo/testso
のテスト実行を追加。
コミット
commit 11e73b89ca8ca5ca80df431e1c78565a9c9028ae
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Tue Nov 22 17:57:49 2011 +0300
cgo: add support for callbacks from dynamic libraries
R=golang-dev, rsc
CC=golang-dev, mpimenov
https://golang.org/cl/5375042
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/11e73b89ca8ca5ca80df431e1c78565a9c9028ae
元コミット内容
cgo: add support for callbacks from dynamic libraries
変更の背景
Go言語はcgo
ツールを通じてC言語との相互運用性を提供していますが、これまでのcgo
は主にGoからCの関数を呼び出すことに焦点を当てていました。しかし、より複雑なシステム連携、特に既存のC言語で書かれた動的ライブラリ(Shared Object: .so
やDynamic Link Library: .dll
など)とGoプログラムを連携させる場合、Cライブラリ側からGoの関数を呼び出す、いわゆる「コールバック」の機能が必要となります。
このコミットの背景には、GoプログラムがCの動的ライブラリを利用する際に、Cライブラリが特定のイベント発生時や処理完了時にGo側の関数を呼び出すようなシナリオを可能にするという目的があります。これにより、GoとCの間のより柔軟で双方向的な連携が実現され、既存のC資産をGoプロジェクトに統合する際の障壁が低減されます。
前提知識の解説
Cgo
cgo
はGo言語に組み込まれているツールで、GoプログラムからC言語のコードを呼び出したり、逆にC言語のコードからGoの関数を呼び出したりすることを可能にします。Goのソースファイル内でimport "C"
と記述することでcgo
が有効になり、Cの関数宣言やGoの関数をCにエクスポートするための特別なコメントディレクティブ(//export
など)を使用します。
動的ライブラリ (DLL/SO)
動的ライブラリ(Dynamic Link Library: DLL - Windows, Shared Object: SO - Linux/Unix系)は、複数のプログラムで共有される再利用可能なコードとデータの集合体です。プログラムのコンパイル時に実行ファイルに直接埋め込まれる静的ライブラリとは異なり、動的ライブラリはプログラムの実行時またはロード時にメモリに読み込まれます。これにより、メモリ効率の向上、ディスクスペースの削減、そしてライブラリの更新が容易になるという利点があります。
コールバック
プログラミングにおけるコールバックとは、ある関数に引数として別の関数を渡し、その渡された関数が後で(特定のイベント発生時や処理完了時などに)呼び出される仕組みです。非同期処理、イベントハンドリング、または関数の振る舞いをカスタマイズする際によく利用されます。動的ライブラリの文脈では、CのライブラリがGoの関数を呼び出すことで、Goプログラムに処理の完了や状態の変化を通知するメカニズムとして機能します。
//export
ディレクティブ
Goの関数をC言語から呼び出せるようにするために、cgo
では//export
ディレクティブを使用します。Goの関数定義の直前に//export FunctionName
と記述することで、cgo
はそのGo関数に対応するC言語のラッパー関数を生成し、Cコードから呼び出し可能にします。
#pragma dynexport
#pragma dynexport
はcgo
が生成するCコード内で使用されるディレクティブで、Goの関数をCのシンボルとしてエクスポートし、特に共有ライブラリとしてビルドされた際にCコードから呼び出し可能にするために利用されます。これは//go:cgo_export_dynamic
のエイリアスであり、動的リンクのシナリオにおいて、Goのシンボルを実行時のプログラムのシンボルテーブルで利用可能にするために重要です。
技術的詳細
このコミットの核心は、Goの関数をCの動的ライブラリからコールバックとして呼び出せるようにするメカニズムの確立です。これは主に以下の要素によって実現されます。
- Go関数のCへのエクスポート:
misc/cgo/testso/cgoso.go
では、//export goCallback
というディレクティブを使ってgoCallback
というGo関数をCにエクスポートしています。cgo
はこのディレクティブを認識し、Cコードから呼び出し可能なラッパー関数を生成します。 #pragma dynexport
の導入:src/cmd/cgo/out.go
の変更により、cgo
はエクスポートされるGo関数に対して#pragma dynexport
ディレクティブを生成するようになりました。このディレクティブは、Goの関数が動的ライブラリの外部から参照可能なシンボルとして公開されることを保証します。これにより、Cの動的ライブラリがGoの関数をシンボル名で解決し、呼び出すことが可能になります。- C側でのGoコールバックの呼び出し:
misc/cgo/testso/cgoso_c.c
では、extern void goCallback(void);
としてGoからエクスポートされた関数を宣言し、sofunc
関数内でgoCallback();
を呼び出しています。このcgoso_c.c
はlibcgoso.so
という動的ライブラリとしてビルドされます。 - ビルドプロセスの調整:
misc/cgo/testso/Makefile
は、cgoso_c.c
をlibcgoso.so
としてコンパイルし、Goのテストプログラムmain.go
がこの動的ライブラリをリンクして実行できるように設定しています。src/Make.pkg
の変更は、cgo
が生成するオブジェクトファイルに動的ライブラリの依存関係を適切に含めるためのものです。 - テストの追加:
misc/cgo/testso
ディレクトリ全体が、この新しいコールバック機能が正しく動作するかを検証するためのテストケースとして機能します。src/run.bash
にこのテストの実行が追加され、Goのビルドシステムの一部として自動的に検証されるようになります。
この一連の変更により、GoプログラムはCの動的ライブラリをロードし、そのライブラリがGoの関数をコールバックとして呼び出すという、双方向の連携が可能になります。
コアとなるコードの変更箇所
misc/cgo/testso/Makefile
(新規追加)
# Copyright 2011 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
include ../../../src/Make.inc
TARG=cgosotest
CGO_DEPS+=libcgoso.so
CGO_LDFLAGS+=-lcgoso -L.
CLEANFILES+=out libcgoso.so
CGOFILES=\
cgoso.go\
include ../../../src/Make.pkg
libcgoso.so: cgoso_c.c
gcc cgoso_c.c -fPIC -o $@ $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS))
out: install main.go
$(GC) main.go
$(LD) -o $@ main.$O
libcgoso.so
という動的ライブラリをcgoso_c.c
からビルドするルールを定義。CGO_DEPS
にlibcgoso.so
を追加し、Goプログラムがこのライブラリに依存することを指定。CGO_LDFLAGS
でリンクオプションを設定。
misc/cgo/testso/cgoso.go
(新規追加)
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgosotest
//void sofunc(void);
import "C"
func Test() {
C.sofunc()
}
//export goCallback
func goCallback() {
}
//export goCallback
により、goCallback
関数がCから呼び出し可能になる。Test
関数はCのsofunc
を呼び出す。
misc/cgo/testso/cgoso_c.c
(新規追加)
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
void sofunc(void)
{
extern void goCallback(void);
goCallback();
}
extern void goCallback(void);
でGoからエクスポートされたgoCallback
関数を宣言。sofunc
関数内でgoCallback
を呼び出す。
misc/cgo/testso/main.go
(新規追加)
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "cgosotest"
func main() {
cgosotest.Test()
}
cgosotest
パッケージをインポートし、その中のTest
関数を呼び出す。
src/Make.pkg
(変更)
--- a/src/Make.pkg
+++ b/src/Make.pkg
@@ -162,7 +162,7 @@ endif
# After main we have to define all the symbols that will be provided
# by Go code. That's crosscall2 and any exported symbols.
-_cgo1_.o: _cgo_main.o $(CGO_OFILES)\
+_cgo1_.o: _cgo_main.o $(CGO_OFILES) $(CGO_DEPS)\
$(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS) $(_CGO_LDFLAGS)\
_obj/_cgo_import.c: _cgo1_.o
_cgo1_.o
の依存関係に$(CGO_DEPS)
を追加。これにより、cgo
が生成するオブジェクトファイルが動的ライブラリに依存することを明示。
src/cmd/cgo/out.go
(変更)
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -501,6 +501,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {\
\t\tif fn.Recv != nil {\
\t\t\tgoname = \"_cgoexpwrap\" + cPrefix + \"_\" + fn.Recv.List[0].Names[0].Name + \"_\" + goname\
\t\t}\
+\t\tfmt.Fprintf(fc, \"#pragma dynexport %s %s\\n\", goname, goname)\
\t\tfmt.Fprintf(fc, \"extern void ·%s();\\n\", goname)\
\t\tfmt.Fprintf(fc, \"\\nvoid\\n\")\
\t\tfmt.Fprintf(fc, \"_cgoexp%s_%s(void *a, int32 n)\\n\", cPrefix, exp.ExpName)\
writeExports
関数内で、エクスポートされるGo関数に対して#pragma dynexport
ディレクティブを出力するように変更。これにより、Go関数が動的ライブラリの外部から参照可能なシンボルとして公開される。
src/run.bash
(変更)
--- a/src/run.bash
+++ b/src/run.bash
@@ -73,6 +73,15 @@ gomake clean
gotest
) || exit $?\
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+[ "$GOHOSTOS" == darwin ] ||
+(xcd ../misc/cgo/testso
+gomake clean
+gomake out
+LD_LIBRARY_PATH=. ./out
+) || exit $?\
+
(xcd ../doc/progs
time ./run
) || exit $?\
misc/cgo/testso
ディレクトリでのテスト実行を追加。LD_LIBRARY_PATH
を設定して動的ライブラリが正しくロードされるようにしている。
コアとなるコードの解説
このコミットの主要な目的は、Goの関数をCの動的ライブラリからコールバックとして呼び出せるようにすることです。そのために、cgo
ツールとGoのビルドシステムにいくつかの重要な変更が加えられています。
-
misc/cgo/testso
ディレクトリの追加:- このディレクトリは、動的ライブラリからのGoコールバックをテストするための最小限の実行可能な例を提供します。
cgoso.go
はGo側で定義されたコールバック関数goCallback
を含みます。この関数は//export
ディレクティブによってCから呼び出し可能にマークされています。また、Cのsofunc
を呼び出すTest
関数も含まれています。cgoso_c.c
はC言語で書かれた部分で、libcgoso.so
という動的ライブラリとしてコンパイルされます。このファイルはextern void goCallback(void);
という宣言を通じてGoのgoCallback
関数を参照し、sofunc
関数内で実際にgoCallback
を呼び出します。main.go
はGoのメインプログラムで、cgosotest.Test()
を呼び出すことで、Cの動的ライブラリ内のsofunc
を間接的に実行します。これにより、sofunc
がGoのgoCallback
を呼び出すというコールバックの流れがテストされます。Makefile
は、これらのファイルをビルドし、libcgoso.so
を生成し、テストを実行するための手順を定義しています。特に、LD_LIBRARY_PATH=.
を設定して、生成された動的ライブラリが実行時に見つけられるようにしています。
-
src/cmd/cgo/out.go
の変更:- このファイルは
cgo
コマンドの出力生成ロジックを扱います。 writeExports
関数にfmt.Fprintf(fc, "#pragma dynexport %s %s\\n", goname, goname)
という行が追加されました。これは、//export
ディレクティブでエクスポートされたGo関数に対応するCのラッパー関数が生成される際に、そのシンボルが動的にエクスポートされるように#pragma dynexport
ディレクティブをCのソースコードに挿入することを意味します。#pragma dynexport
は、Goの関数が共有ライブラリの外部から参照可能なシンボルテーブルに登録されることを保証します。これにより、Cの動的ライブラリがGoの関数をシンボル名で解決し、実行時に呼び出すことが可能になります。
- このファイルは
-
src/Make.pkg
の変更:_cgo1_.o
のビルドルールにおいて、依存関係に$(CGO_DEPS)
が追加されました。CGO_DEPS
はMakefile
で定義される動的ライブラリのリスト(この場合はlibcgoso.so
)を含みます。- この変更により、
cgo
が生成する中間オブジェクトファイルが、Goプログラムが依存する動的ライブラリの存在を考慮するようになり、ビルドプロセスがより堅牢になります。
-
src/run.bash
の変更:- Goのテストスイートに
misc/cgo/testso
のテスト実行が追加されました。これにより、動的ライブラリからのGoコールバック機能がGoの公式テストの一部として継続的に検証されるようになります。
- Goのテストスイートに
これらの変更が連携することで、Go言語はCの動的ライブラリとの間で、より高度な相互作用、特にC側からのGo関数へのコールバックをサポートするようになりました。
関連リンク
- Go cgo documentation: https://go.dev/cmd/cgo/
- Go build modes: https://go.dev/cmd/go/#hdr-Build_modes
参考にした情報源リンク
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGImyk2_g6npsBV1Sx_-ZhNZayy_S8L_RkZ4aDQN5vNDM2CgblXFI20UtQUAIGUUO9WER5wojQ1NGkGalZUdewa6YOK0PeSwdAt0aJLU2oCVZM=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFQOOm79snJKxPtqjyE4osMa7E8sRhg6vDWDoedVmPn43W_u4W_wIylFu-5q1argrE1fKwwLbqkMka_YdaW3Hk7gB8NHVrltdqLOE1ngFkl2GoXzDNn3ZA7wBiE7kJ3LiYQfVC1f2MkUXGhGK-uL4nUlzR1LDewqwTb-3GE
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEV-wsvDLLXa-Xt7_rtROUS0Yn6J13x2XC0wCkPLEQs6K-NEWM6BwBqTw08xx0Y_pCXtDq0L8tu-aIEiOYGIWm6PnnaLtSX4VQNh3NE7jQHlYw1eZo=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFV8CyrD_cvwMMAQLL8FoUHYkrqpjbS2VYzBxTqm0MvlZqJRIpRpti8TzfIXKm9wvyUk0yQNAXagp0GSKIONHOC0pLdzx1thKtlik69edH0cKCJbECIftBAqIjBNl4j1SrKGdpC8oI2bJt-glzILY4dcYW-zq9k9S3rg5hub2dCTy7HxpigSoTGOPk036xXiWbtiqPacfJu5Z0R
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGjVzK3wsnLW-S8hVyU-GEsKqINJck7n1JcLB21V7zjOFvj_pxfXIGO-g8p8HiwPabczfewXR61JKcLCyu-y79yLIPOButSjqAlrKwKjPw5c56C_dGabezDjQ4ffA3QvE1MJ2KuPeGfnV8gKju8DG8a4vg_2X54Oslh2RpI2Gv1nuzI6nrcy7bf3169HY556UzguAOIoyl6
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG5tfNggwioRb0h69P8HxuT5CXdA1VtlHVHEPKdEwoWF5OW64fBgg9z2d4vo7Pb9rnr_wgBvs7TXmg-sc7hvJwZ6iRD-P9yFRB484yGQFOLdv3r8ScHT-UMubEnYMeZf1YSJ3j-SKMOfeIVwkLXcOnXHLuSMLMY3eDU3gCaQy-iiDXcQrMGPFS73Qhu5yqOxAIVZpo3nXoCFwXBGk-026PLE0A==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGiblqJz_OvqgQGltpIzuUrgeoXq9J8ooEVUoc1wIIG6v8KHD6Z2lupBaFeXXW7Gm4SCQ4ZlAzDyCHmqsQY26FSbTfz1qAkBrtHGmUMM0TgqttNOcssieOmkxD5B-4oYAKnmgboimpgizpKbUkxC71DGeXtRog6VwGBJxQmHiYn4g2VIw==
- [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG1TNdvrsAgsA5I-sgIC1OsWjqD1Z98qzRLeR6qeaLxGDWtv7XNLSyaorgQUlqSf8eHaqFjsQUR5xNWe8BFuymyiYDejsWHvVSh6fa8qGw4lel8AkeX1emmdeq0l2uYzi6X2BI=](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG1TNdvrsAgsA5I-sgIC1OsWjqD1Z98qzRLeR6qeaLxGDWtv7XNLSyaorgQUlqSf8eHaqFDOB_w_F-VVmXXTAeuUjrXopiTjtbUwRb-0QycSgUbPn7TKl2Dwxeo8q64Rhm6vxNG4Kn1Pm39IWgyRkotJcy4PXZlQYun6YfuFMEUHY-OZeOAtCvBV8DrD_rX-JGwHqSEgcNmRidsVfPi-Fk](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG1TNdvrsAgsA5I-sgIC1OsWjqD1Z98qzRLeR6qeaLxGDWtv7XNLSyaorgQUlqSf8eHaqFDOB_w_F-VVmXXTAeuUjrXopiTjtbUwRb-0QycSgUbPn7TKl2Dwxeo8q64Rhm6vxNG4Kn1Pm39IWgyRkotJcy4PXZlQYun6YfuFMEUHY-OZeOAtCvBV8DrD_rX-JGwHqSEgcNmRidsVfPi-Fk)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEIYBQYUxoTTAEb0DlpKiZ_OwhTrJvKTEhDAKcrgHHv2iwWEArisL384v9oLABAedBuGKKJDjiHDf8lI2Fhw1W_PLnG-SNoJIgBbgd68xgcbsg27tieFaFT2HIGFyLBsD_TK90c86N1zsD46AgdOzZQz7W_bPlgA0NXHLRqL0M8jiiI3_WeSYTGFyIIyRM=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG4ggh4KFa9-xyF0e9Gu-Mu4FYfkP1ElqTG5zrTDTaocMKHIS8CF1Syw7q_0sB9CUB4cCgtWvz71j7qHJusY_mhfwLCuHEJFDjP7Y6qUtJ0aAeYO_MMcpksHKTl-cYF0br7EeWynSQsAALrafQt
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFP0vjUSoSHsXqUNLsO9WpBtCqFmLKPmV5rqdpjySrRMI_W4kEiAzT_-hsLeix4ZpdovVz3amlNLvONOcL4UlIAsqy3oyT7NFMgN3OAcKoOd9hFTDhfL0nkC596zmpu1Wdwd2Pe3c6ZXBChwRr2xkDVw_GtcEPaEXw=
- [https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFOAODr8fqdJw6e5etKWhMnI2I1kB3SF87SA0VrFKmMJ8DzO74JeiiuDwfVxWafEG_Lkh1QazB42OhkjeWfwyG_Gssq49IfN209GokNbIzRnmMrQMnTqYWSiIcshtAbCUrxXYpDJWGEiMHj1XLW66Y4GBQfSNZuDyrXqGM_H2zq9bVvk_csuuUYha0=](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFOAODr8fqdJw6e5etKWhMnI2I1kB3SF87SA0VrFKmMJ8DzO74JeiiuDwfVxWafEG_Lkh1QazB42OhkjeWfwyG_Gssq49IfN209GokNbN_w_F-VVmXXTAeuUjrXopiTjtbUwRb-0QycSgUbPn7TKl2Dwxeo8q64Rhm6vxNG4Kn1Pm39IWgyRkotJcy4PXZlQYun6YfuFMEUHY-OZeOAtCvBV8DrD_rX-JGwHqSEgcNmRidsVfPi-Fk](https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFOAODr8fqdJw6e5etKWhMnI2I1kB3SF87SA0VrFKmMJ8DzO74JeiiuDwfVxWafEG_Lkh1QazB42OhkjeWfwyG_Gssq49IfN209GokNbN_w_F-VVmXXTAeuUjrXopiTjtbUwRb-0QycSgUbPn7TKl2Dwxeo8q64Rhm6vxNG4Kn1Pm39IWgyRkotJcy4PXZlQYun6YfuFMEUHY-OZeOAtCvBV8DrD_rX-JGwHqSEgcNmRidsVfPi-Fk)
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG5kMZ7Mw3T_pM9MaoZ5on_GFdiQru6hp-Aj6fTgcA9U10Y71EovJFymm-wVDSpns7DjB8J9emq0GWy4iwd1rw71PbiXe0ooOsA71qKgBQ_NiZ3NgiGGE2hYWsnyN90AlTtDEGFwE8KmYUp4VEH6o5xsfIC8bfDzANIoBAcUgZAM0rntchkqL8A7FVRftHH0xZGYkykAe6qbRfNAeRioi10s_jtpu8wZGe4QQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHHpr5pEnkVn4IFRtBKhkFSADq0oRHGrqjtQw5tcV-HRRjV2dQ6aTrOhfmwp8VW2Jt1nUAEGwbTGcNKgwQ6AnXB9LUvi7D3Gp0ZW_-0HO-QufQJYFoE9N_1ScjWFNwi_YZOSHup4lS8KSweBznrvYLT3nwdQY09bVAPPm8vyJ7LB57-qUkBpGhIjzL7zmi2Gpanp3V5w6oq