Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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 (このコミットの元のコードレビューページ)

参考にした情報源リンク