[インデックス 17230] ファイルの概要
このコミットは、cmd/cgo
ツールにおけるWindowsビルドの問題を修正するものです。具体的には、共有ライブラリの変更によってWindows環境でのビルドが失敗するようになった問題に対し、WindowsのGCCがサポートしていない __attribute__ ((visibility ("hidden")))
属性を削除することで対応しています。この属性は共有ライブラリをビルドする際にのみ必要とされるものであり、WindowsのGCCでは不要であるため削除されました。
コミット
commit a5f257a042f19dfe0023a0e5ad7dd673b32ad087
Author: Elias Naur <elias.naur@gmail.com>
Date: Wed Aug 14 12:47:06 2013 -0400
cmd/cgo: fix windows build
The shared library changes broke the windows build because __attribute__ ((visibility ("hidden"))) is not supported in windows gcc. This change removes the attribute, as it is only needed when building shared libraries.
R=rsc
CC=golang-dev
https://golang.org/cl/12829044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a5f257a042f19dfe0023a0e5ad7dd673b32ad087
元コミット内容
元のコミットメッセージは「cmd/cgo: fix windows build」であり、その詳細として「共有ライブラリの変更がWindowsビルドを壊した。なぜなら __attribute__ ((visibility ("hidden")))
がWindowsのGCCでサポートされていないためである。この変更は、共有ライブラリをビルドする際にのみ必要とされるこの属性を削除する。」と述べられています。
変更の背景
この変更の背景には、Go言語の cgo
ツールがC言語のコードとGo言語のコードを連携させる際に、特定のコンパイラ属性を使用していたことがあります。特に __attribute__ ((visibility ("hidden")))
というGCC拡張属性は、シンボルの可視性を制御するために使用されます。これは、共有ライブラリ(ダイナミックリンクライブラリ)をビルドする際に、外部に公開したくないシンボルを隠蔽するために非常に有用です。
しかし、この属性はGCCの拡張機能であり、すべてのGCCコンパイラやプラットフォームで等しくサポートされているわけではありません。特に、Windows環境でGoのビルドに使用されるGCC(MinGWなど)では、この visibility
属性がサポートされていませんでした。
以前の共有ライブラリに関する変更が cgo
の出力するCコードにこの属性を含めるようになった結果、Windows環境でGoのコードをビルドしようとすると、GCCが認識できない属性に遭遇し、コンパイルエラーが発生するようになりました。このコミットは、このWindowsビルドの破損を修正するために行われました。
前提知識の解説
- cgo: Go言語の標準ツールの一つで、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのメカニズムを提供します。
cgo
は、GoとCの間のデータ変換や関数呼び出しのラッパーコードを生成します。 - GCC (GNU Compiler Collection): C、C++、Objective-C、Fortran、Ada、Goなど、多くのプログラミング言語をサポートするコンパイラ群です。Go言語のツールチェーンは、Cコードとの連携(
cgo
)や、一部のプラットフォームでのアセンブリコードの生成にGCCを利用することがあります。 __attribute__ ((visibility ("hidden")))
: これはGCCの拡張機能であり、C/C++の関数や変数のシンボル可視性を制御するために使用されます。- シンボル可視性 (Symbol Visibility): プログラムがコンパイルされ、リンクされる際に、関数や変数の名前(シンボル)が他のモジュール(例えば共有ライブラリ)から参照可能かどうかを決定する概念です。
default
: シンボルは共有ライブラリの外部から参照可能です。hidden
: シンボルは共有ライブラリの内部でのみ参照可能で、外部からは参照できません。これにより、ライブラリの内部実装の詳細を隠蔽し、APIの安定性を高めることができます。protected
: シンボルは共有ライブラリの外部から参照可能ですが、同じ共有ライブラリ内の他のシンボルによるオーバーライドを防ぎます。internal
: シンボルは現在のオブジェクトファイル内でのみ参照可能です。
- 共有ライブラリ (Shared Libraries / Dynamic Link Libraries - DLLs): 複数のプログラムで共有されるコードやデータを含むファイルです。WindowsではDLL (Dynamic Link Library)、Linux/UnixではSO (Shared Object) ファイルとして知られています。プログラムの実行時にロードされ、メモリを節約し、モジュール性を高めます。
技術的詳細
この問題の核心は、Goの cgo
ツールが生成するCコードに、WindowsのGCCがサポートしていない __attribute__ ((visibility ("hidden")))
属性が含まれていたことです。
cgo
は、GoとCの間のインターフェースを生成する際に、Goの関数をCから呼び出すためのラッパー関数を生成します。これらのラッパー関数は、通常、Goの内部的なメカニズムの一部であり、外部のCコードから直接呼び出されることを意図していません。そのため、シンボル可視性を hidden
に設定することで、これらの内部関数が共有ライブラリの外部に誤って公開されるのを防ぐのが一般的なプラクティスです。
しかし、Windows環境でGoのビルドに使用されるMinGWなどのGCCディストリビューションは、visibility
属性をサポートしていませんでした。これは、WindowsのDLLモデルがUnix系の共有ライブラリとは異なるシンボルエクスポートメカニズム(__declspec(dllexport)
や .def
ファイルなど)を使用しているためです。WindowsのGCCは、通常、これらのWindows固有のメカニズムを優先し、Unix系の visibility
属性を実装していません。
結果として、cgo
が生成したCコードに __attribute__ ((visibility ("hidden")))
が含まれていると、WindowsのGCCはこれを構文エラーとして扱い、コンパイルが失敗していました。
このコミットの解決策はシンプルかつ効果的です。__attribute__ ((visibility ("hidden")))
属性は、共有ライブラリをビルドする際にシンボルを隠蔽するためにのみ必要です。Goの cgo
が生成するラッパー関数は、通常、Goの内部的なリンケージに使用されるため、共有ライブラリとしてエクスポートされる必要はありません。したがって、Windows環境ではこの属性を削除しても機能的な問題は発生しません。この属性を削除することで、WindowsのGCCがコードを正常にコンパイルできるようになり、ビルドが成功するようになります。
コアとなるコードの変更箇所
変更は src/cmd/cgo/out.go
ファイルの1箇所のみです。
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -494,7 +494,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
- fmt.Fprintf(fgcc, "__attribute__ ((visibility (\"hidden\"))) void\\n\")
+ fmt.Fprintf(fgcc, "void\\n\")
fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\\n", cPrefix, n.Mangle)
fmt.Fprintf(fgcc, "{\\n")
if n.AddError {
具体的には、fmt.Fprintf(fgcc, "__attribute__ ((visibility (\"hidden\"))) void\\n\")
の行が fmt.Fprintf(fgcc, "void\\n\")
に変更されています。
コアとなるコードの解説
この変更は、cgo
ツールがCコードを生成する際に、Goのラッパー関数の定義から __attribute__ ((visibility ("hidden\")))
属性を削除することを意味します。
src/cmd/cgo/out.go
は、cgo
がCのラッパーコードを生成するロジックを含んでいます。writeOutputFunc
関数は、Goの関数をCから呼び出すためのラッパー関数をCコードとして出力する役割を担っています。
変更前のコードでは、生成されるCコードの関数定義の前に __attribute__ ((visibility ("hidden\")))
が付加されていました。これは、生成される _cgo
プレフィックスを持つ関数が、共有ライブラリの外部からは見えないようにするための意図がありました。
変更後のコードでは、この属性が完全に削除されています。これにより、WindowsのGCCは、この属性に関する構文エラーを発生させることなく、コードを正常にコンパイルできるようになります。この修正は、Windows環境でのビルドの互換性を確保しつつ、Goの内部的なリンケージメカニズムには影響を与えないため、適切な解決策と言えます。
関連リンク
- Go issue tracker: https://github.com/golang/go/issues (このコミットに関連する特定のissueはコミットメッセージには記載されていませんが、Goのissue trackerで関連する議論が見つかる可能性があります。)
- Go CL (Change List): https://golang.org/cl/12829044 (このコミットの元のコードレビューページ)
参考にした情報源リンク
- GCC Manual - Declaring Attributes of Functions: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
- GCC Manual - Visibility: https://gcc.gnu.org/onlinedocs/gcc/Visibility-Pragmas.html
- MinGW (Minimalist GNU for Windows): https://www.mingw-w64.org/
- Microsoft Docs - dllexport, dllimport: https://learn.microsoft.com/en-us/cpp/cpp/dllexport-dllimport?view=msvc-170
- Go cgo documentation: https://pkg.go.dev/cmd/cgo
- Stack Overflow discussions on
__attribute__ ((visibility ("hidden")))
on Windows/MinGW. (具体的なURLは省略しますが、この属性がWindows GCCでサポートされていないことに関する多くの議論があります。)