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

[インデックス 15499] ファイルの概要

このコミットは、Go言語のcgoツールに関するドキュメント(src/cmd/cgo/doc.go)を拡張し、特にGoプログラムとC/C++コードを連携させる際の「内部リンキング」と「外部リンキング」の概念、およびそれらを制御するための新しい#pragmaディレクティブについて詳細な解説を追加しています。これにより、cgoのリンキングメカニズムの理解を深め、GoとC/C++の混在環境におけるビルドプロセスの複雑性を管理するための指針を提供しています。

コミット

  • コミットハッシュ: b89000bcabe16644d877e8d1251a3e6a784153d9
  • Author: Russ Cox rsc@golang.org
  • Date: Thu Feb 28 10:44:29 2013 -0800

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/b89000bcabe16644d877e8d1251a3e6a784153d9

元コミット内容

cmd/cgo: extend implementation comment

This is the plan for how to make host linking work with
the rest of the system.

There are two complications:

1. It is a goal to preserve the property that pure Go programs
(even ones importing "net") can be compiled without needing
gcc, so that a Go toolchain download works out of the box.
This forces the support for two linking modes: with and without
gcc.

2. It is a goal to allow users with old copies of SWIG to continue
to use those copies. This forces the support for "internal only"
packages. Perhaps it is reasonable to require a new SWIG.
I don't know.

R=iant
CC=golang-dev
https://golang.org/cl/7433043

変更の背景

このコミットは、GoプログラムがC/C++コードと連携する際に発生するリンキングの複雑性に対処するために行われました。特に、以下の2つの主要な課題が背景にあります。

  1. 純粋なGoプログラムのGCC不要なコンパイルの維持: Goの設計目標の一つに、純粋なGoプログラム(たとえnetパッケージのようにcgoを使用する可能性のあるパッケージをインポートしていても)がGCCのような外部Cコンパイラを必要とせずにコンパイルできるという特性を維持することがあります。これは、Goツールチェインをダウンロードしただけで、すぐにGoプログラムをビルドできる「箱から出してすぐに使える」体験を提供するために重要です。しかし、cgoを使用するとC/C++のリンキングが必要となり、GCCへの依存が発生する可能性があります。この矛盾を解決するためには、GCCの有無に応じて異なるリンキングモードをサポートする必要がありました。

  2. 古いSWIGバージョンのサポート: SWIG(Simplified Wrapper and Interface Generator)は、C/C++コードをGoを含む様々な言語から呼び出すためのラッパーコードを生成するツールです。古いSWIGのバージョンを使用しているユーザーが引き続きその環境で作業できるようにすることも目標とされていました。これは、特定のパッケージを「内部のみ」でリンクするモードをサポートする必要があることを意味します。ただし、コミットメッセージでは、新しいSWIGを要求することが妥当である可能性も示唆されており、この点についてはまだ検討の余地があることが伺えます。

これらの課題に対処するため、Goのリンカ(6l)がC/C++オブジェクトファイルをどのように扱うかについて、より柔軟なアプローチが必要とされました。具体的には、「内部リンキング」と「外部リンキング」という2つの異なるリンキングモードを導入し、それぞれのモードがどのような状況で適用されるべきか、そしてそれらを制御するための新しい#pragmaディレクティブを定義することが計画されました。このコミットは、これらの計画をcgoのドキュメントに明記することで、将来のcgoの動作変更に対する準備と、開発者への情報提供を目的としています。

前提知識の解説

このコミットの理解には、以下の概念に関する前提知識が役立ちます。

  • Go言語: Googleによって開発されたオープンソースのプログラミング言語。並行処理、ガベージコレクション、高速なコンパイルが特徴。
  • cgo: Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出したり、Goの関数をC言語から呼び出したりするためのメカニズムを提供します。import "C"という特殊なインポート文を使用します。
  • リンカ (Linker): コンパイラによって生成されたオブジェクトファイル(機械語コード)を結合し、実行可能なプログラムやライブラリを生成するツールです。未解決のシンボル(関数や変数の参照)を解決し、必要なライブラリをリンクします。
  • Goリンカ (6l): Go言語のツールチェインに含まれるリンカです。Goのソースコードから生成されたオブジェクトファイルをリンクして実行可能ファイルを生成します。Goのバージョンによって名前が異なる場合があります(例: go tool link)。
  • GCC (GNU Compiler Collection): C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラ群です。cgoを使用する場合、C/C++コードのコンパイルとリンキングにGCCが利用されることが一般的です。
  • オブジェクトファイル: コンパイラがソースコードをコンパイルした結果生成される中間ファイルで、機械語コードとシンボル情報を含みます。拡張子は.o(Unix/Linux)や.obj(Windows)など。
  • 動的ライブラリ (Dynamic Library): 実行時にロードされるライブラリです。プログラムの実行ファイルには、ライブラリのコードが直接含まれず、ライブラリへの参照のみが含まれます。これにより、複数のプログラムで同じライブラリを共有でき、ディスクスペースの節約やメモリ効率の向上が図れます。Unix/Linuxでは.so(Shared Object)、Windowsでは.dll(Dynamic Link Library)という拡張子が一般的です。
  • 静的ライブラリ (Static Library): リンク時にプログラムの実行ファイルに直接組み込まれるライブラリです。実行ファイルは自己完結型となり、ライブラリがシステムに存在しなくても実行できますが、ファイルサイズは大きくなります。Unix/Linuxでは.a(Archive)、Windowsでは.libという拡張子が一般的です。
  • #pragma ディレクティブ: C/C++言語において、コンパイラやリンカに対して特別な指示を与えるためのプリプロセッサディレクティブです。このコミットでは、cgoのリンキング動作を制御するための新しい#pragmaディレクティブが導入されています。
  • シンボル: プログラム内の関数や変数の名前です。リンカはこれらのシンボルを解決して、正しいメモリアドレスにマッピングします。
  • GLIBC: GNU C Libraryの略で、Linuxシステムで広く使用されている標準Cライブラリの実装です。多くのシステムコールや標準C関数を提供します。
  • SWIG (Simplified Wrapper and Interface Generator): C/C++で書かれたライブラリを、Go、Python、Java、Rubyなどの他の言語から利用できるようにするためのインターフェースコードを自動生成するツールです。

技術的詳細

このコミットで追加されたドキュメントは、cgoにおけるGoプログラムとC/C++コードのリンキングに関する重要な技術的詳細を説明しています。特に、「内部リンキング」と「外部リンキング」という2つの異なるリンキングモードと、それらを制御するための新しい#pragmaディレクティブに焦点を当てています。

内部リンキング (Internal Linking)

  • 概要: 6l(Goリンカ)が直接ホストのオブジェクトファイル(ELF, Mach-O, PEなど)を解析し、最終的な実行可能ファイルにリンクするモードです。
  • 特徴:
    • 6lがGoバイナリを単独で生成できます。
    • 6lのシンプルさを保つため、リンクできるオブジェクトの種類には制限があります(他のコードは動的ライブラリとしてのみ使用可能)。
    • 純粋なGoプログラム(netパッケージをインポートするものを含む)がGCCを必要とせずにコンパイルできるという特性を維持できます。これは、Goツールチェインをダウンロードしただけで、すぐにGoプログラムをビルドできるというGoの目標に合致します。
    • libc.soのような標準的な動的ライブラリへの依存は許容されます。
  • 適用シナリオ: netパッケージのように、cgoを使用するパッケージが標準ライブラリのホワイトリストに含まれる場合や、libc以外のライブラリへの依存が少ない場合に適しています。

外部リンキング (External Linking)

  • 概要: 6lはホストのオブジェクトファイルを処理せず、すべてのGoコードを単一のgo.oオブジェクトファイルにまとめます。その後、ホストリンカ(通常はgcc)を呼び出して、go.oファイルとサポートする非Goコードを組み合わせて最終的な実行可能ファイルを生成します。
  • 特徴:
    • 任意のオブジェクトファイルを動的ライブラリを必要とせずにリンクできます。
    • ホストリンカ(gccなど)の存在が必須となります。
    • cgoが関与する場合、コンパイルステップで既にgccが必要となるため、リンクステップでgccが必要となることは問題ありません。
    • 動的ライブラリの要件を回避できます。
  • 適用シナリオ: libc以外のライブラリへの依存がある場合や、より複雑なC/C++ライブラリをGoプログラムに組み込む場合に適しています。例えば、sqlite3のようなcgoでラップされたライブラリをビルドしてスタンドアロンの実行可能ファイルを生成する場合など。

リンキングディレクティブ (#pragma)

Goのリンカにパッケージ固有の指示を伝えるために、Cソースファイル内で6cによってコンパイルされる#pragmaディレクティブが導入されます。これらのディレクティブは.6オブジェクトファイルにコピーされ、リンカによって処理されます。

  • #pragma cgo_dynamic_import <local> [<remote> ["<library>"]]:

    • 内部リンキングモード: 未解決の参照<local>を動的ライブラリシンボルによって解決されると仮定します。オプションの<remote>はシンボルの名前とバージョンを、オプションの"<library>"はシンボルが見つかるべき特定のライブラリを指定します。
    • 例: putsシンボルをGLIBC_2.2.5バージョンのlibc.so.6からインポートする場合。
    • _ _ "<library>"とすることで、特定のシンボルをインポートせずに動的ライブラリへの依存関係を追加できます。
    • #pragma dynimport#pragma cgo_dynamic_importのエイリアスです(SWIGとの互換性のため)。
  • #pragma cgo_dynamic_linker "<path>":

    • 内部リンキングモード: 最終バイナリで<path>を動的リンカとして使用します。通常、runtime/cgoによって提供されます。
    • 例: /lib/ld-linux.so.2を動的リンカとして指定する場合。
  • #pragma cgo_export <local> <remote>:

    • 内部・外部リンキングモード両方: Goシンボル<local>をプログラムのエクスポートされたシンボルテーブルに<remote>として配置し、Cコードからその名前で参照できるようにします。これにより、CコードからGo関数を呼び出したり、Goのデータを共有したりすることが可能になります。
    • #pragma dynexport#pragma cgo_exportのエイリアスです(SWIGとの互換性のため)。
  • #pragma cgo_static_import <local>:

    • 外部リンキングモード: ホストリンカ用に準備されたgo.oオブジェクトファイル内の<local>への未解決の参照を許可します。これは、<local>go.oとリンクされる他のオブジェクトファイルによって提供されるという仮定に基づいています。
    • 例: puts_wrapperが外部から提供されることを示す場合。
  • #pragma cgo_ldflag "<arg>":

    • 外部リンキングモード: ホストリンカ(通常はgcc)を、.oファイルの後にコマンドライン引数"<arg>"を付けて呼び出します。引数はgcc用であり、ld用ではないことに注意が必要です。
    • 例: -lpthread-L/usr/local/sqlite3/libのようなリンカフラグを指定する場合。

リンキングモードの決定

  • デフォルトの動作: 6lは、cgoを使用するパッケージが標準ライブラリのホワイトリスト(net, os/user, runtime/cgo)にのみ含まれる場合、内部リンキングモードを使用します。それ以外の場合(非標準のcgoパッケージが関与する場合)、外部リンキングモードを使用します。
    • このルールにより、netのみを使用するgodocバイナリのビルドはGCCなしで実行でき、sqlite3のようなcgoラップされたライブラリのビルドはスタンドアロンの実行可能ファイルを生成できます。
  • コマンドラインでのオーバーライド: 6l -cgolink=internalまたは6l -cgolink=externalフラグを使用して、リンキングモードを明示的に指定できます。
  • 外部リンキング時のホストリンカ: 外部リンキングでは、6lは一時ディレクトリを作成し、パッケージアーカイブ内のホストオブジェクトファイルをそのディレクトリに書き込み、go.oファイルを書き込み、ホストリンカを呼び出します。ホストリンカのデフォルト値は$CCまたはgccです。6l -hostld='gcc -ggdb'フラグを使用して、特定のホストリンカコマンドラインをオーバーライドできます。

これらの変更により、Goのビルドシステムはリンキングの詳細を意識せずに6lを実行しても合理的な結果を得られるようになり、必要に応じてリンキングの詳細を制御することも可能になります。

コアとなるコードの変更箇所

このコミットによるコアとなるコードの変更は、src/cmd/cgo/doc.goファイルへの追加です。

--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -396,4 +396,230 @@
 and libcgo_thread_start to a gcc-compiled function that can be used to
 create a new thread, in place of the runtime's usual direct system
 calls.
 
+[NOTE: From here down is planned but not yet implemented.]
+
+Internal and External Linking
+
+The text above describes "internal" linking, in which 6l parses and
+links host object files (ELF, Mach-O, PE, and so on) into the final
+executable itself. Keeping 6l simple means we cannot possibly
+implement the full semantics of the host linker, so the kinds of
+objects that can be linked directly into the binary is limited (other
+code can only be used as a dynamic library). On the other hand, when
+using internal linking, 6l can generate Go binaries by itself.
+
+In order to allow linking arbitrary object files without requiring
+dynamic libraries, cgo will soon support an "external" linking mode
+too. In external linking mode, 6l does not process any host object
+files. Instead, it collects all the Go code and writes a single go.o
+object file containing it. Then it invokes the host linker (usually
+gcc) to combine the go.o object file and any supporting non-Go code
+into a final executable. External linking avoids the dynamic library
+requirement but introduces a requirement that the host linker be
+present to create such a binary.
+
+Most builds both compile source code and invoke the linker to create a
+binary. When cgo is involved, the compile step already requires gcc, so
+it is not problematic for the link step to require gcc too.
+
+An important exception is builds using a pre-compiled copy of the
+standard library. In particular, package net uses cgo on most systems,
+and we want to preserve the ability to compile pure Go code that
+imports net without requiring gcc to be present at link time. (In this
+case, the dynamic library requirement is less significant, because the
+only library involved is libc.so, which can usually be assumed
+present.)
+
+This conflict between functionality and the gcc requirement means we
+must support both internal and external linking, depending on the
+circumstances: if net is the only cgo-using package, then internal
+linking is probably fine, but if other packages are involved, so that there
+are dependencies on libraries beyond libc, external linking is likely
+to work better. The compilation of a package records the relevant
+information to support both linking modes, leaving the decision
+to be made when linking the final binary.
+
+Linking Directives
+
+In either linking mode, package-specific directives must be passed
+through to 6l. These are communicated by writing #pragma directives
+in a C source file compiled by 6c. The directives are copied into the .6 object file
+and then processed by the linker.
+
+The directives are:
+
+#pragma cgo_dynamic_import <local> [<remote> ["<library>"]]
+
+	In internal linking mode, allow an unresolved reference to
+	<local>, assuming it will be resolved by a dynamic library
+	symbol. The optional <remote> specifies the symbol's name and
+	possibly version in the dynamic library, and the optional "<library>"
+	names the specific library where the symbol should be found.
+
+	In the <remote>, # or @ can be used to introduce a symbol version.
+
+	Examples:
+	#pragma cgo_dynamic_import puts
+	#pragma cgo_dynamic_import puts puts#GLIBC_2.2.5
+	#pragma cgo_dynamic_import puts puts#GLIBC_2.2.5 "libc.so.6"
+
+	A side effect of the cgo_dynamic_import directive with a
+	library is to make the final binary depend on that dynamic
+	library. To get the dependency without importing any specific
+	symbols, use _ for local and remote.
+
+	Example:
+	#pragma cgo_dynamic_import _ _ "libc.so.6"
+
+	For compatibility with current versions of SWIG,
+	#pragma dynimport is an alias for #pragma cgo_dynamic_import.
+
+#pragma cgo_dynamic_linker "<path>"
+
+	In internal linking mode, use "<path>" as the dynamic linker
+	in the final binary. This directive is only needed from one
+	package when constructing a binary; by convention it is
+	supplied by runtime/cgo.
+
+	Example:
+	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+#pragma cgo_export <local> <remote>
+
+	In both internal and external linking modes, put the Go symbol
+	named <local> into the program's exported symbol table as
+	<remote>, so that C code can refer to it by that name. This
+	mechanism makes it possible for C code to call back into Go or
+	to share Go's data.
+
+	For compatibility with current versions of SWIG,
+	#pragma dynexport is an alias for #pragma cgo_export.
+
+#pragma cgo_static_import <local>
+
+	In external linking mode, allow unresolved references to
+	<local> in the go.o object file prepared for the host linker,
+	under the assumption that <local> will be supplied by the
+	other object files that will be linked with go.o.
+
+	Example:
+	#pragma cgo_static_import puts_wrapper
+
+#pragma cgo_ldflag "<arg>"
+
+	In external linking mode, invoke the host linker (usually gcc)
+	with "<arg>" as a command-line argument following the .o files.
+	Note that the arguments are for "gcc", not "ld".
+
+	Example:
+	#pragma cgo_ldflag "-lpthread"
+	#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
+
+A package compiled with cgo will include directives for both
+internal and external linking; the linker will select the appropriate
+subset for the chosen linking mode.
+
+Example
+
+As a simple example, consider a package that uses cgo to call C.sin.
+The following code will be generated by cgo:
+
+	// compiled by 6g
+
+	type _Ctype_double float64
+	func _Cfunc_sin(_Ctype_double) _Ctype_double
+
+	// compiled by 6c
+
+	#pragma cgo_dynamic_import sin sin#GLIBC_2.2.5 "libm.so.6"
+	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+	#pragma cgo_static_import _cgo_gcc_Cfunc_sin
+	#pragma cgo_ldflag "-lm"
+
+	void _cgo_gcc_Cfunc_sin(void*);
+
+	void
+	·_Cfunc_sin(struct{uint8 x[16];}p)
+	{
+		runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
+	}
+
+	// compiled by gcc, into foo.cgo2.o
+
+	void
+	_cgo_gcc_Cfunc_sin(void *v)
+	{
+		struct {
+			double p0;
+			double r;
+		} __attribute__((__packed__)) *a = v;
+		a->r = sin(a->p0);
+	}
+
+What happens at link time depends on whether the final binary is linked
+using the internal or external mode. If other packages are compiled in
+"external only" mode, then the final link will be an external one.
+Otherwise the link will be an internal one.
+
+The directives in the 6c-compiled file are used according to the kind
+of final link used.
+
+In internal mode, 6l itself processes all the host object files, in
+particular foo.cgo2.o. To do so, it uses the cgo_dynamic_import and
+cgo_dynamic_linker directives to learn that the otherwise undefined
+reference to sin in foo.cgo2.o should be rewritten to refer to the
+symbol sin with version GLIBC_2.2.5 from the dynamic library
+"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its
+runtime dynamic linker.
+
+In external mode, 6l does not process any host object files, in
+particular foo.cgo2.o. It links together the 6g- and 6c-generated
+object files, along with any other Go code, into a go.o file. While
+doing that, 6l will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
+is okay, because 6l also processes the cgo_static_import directive and
+knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
+object file, so 6l does not treat the missing symbol as an error when
+creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be
+provided to the host linker by foo2.cgo.o, which in turn will need the
+symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it
+knows that the eventual host link command must include the -lm
+argument, so that the host linker will be able to find 'sin' in the
+math library.
+
+6l Command Line Interface
+
+The go command and any other Go-aware build systems invoke 6l
+to link a collection of packages into a single binary. By default, 6l will
+present the same interface it does today:
+
+	6l main.a
+
+produces a file named 6.out, even if 6l does so by invoking the host
+linker in external linking mode.
+
+By default, 6l will decide the linking mode as follows: if the only
+packages using cgo are those on a whitelist of standard library
+packages (net, os/user, runtime/cgo), 6l will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and 6l
+will use external linking mode. The first rule means that a build of
+the godoc binary, which uses net but no other cgo, can run without
+needing gcc available. The second rule means that a build of a
+cgo-wrapped library like sqlite3 can generate a standalone executable
+instead of needing to refer to a dynamic library. The specific choice
+can be overridden using a command line flag: 6l -cgolink=internal or
+6l -cgolink=external.
+
+In an external link, 6l will create a temporary directory, write any
+host object files found in package archives to that directory (renamed
+to avoid conflicts), write the go.o file to that directory, and invoke
+the host linker. The default value for the host linker is $CC, split
+into fields, or else "gcc". The specific host linker command line can
+be overridden using a command line flag: 6l -hostld='gcc -ggdb'
+
+These defaults mean that Go-aware build systems can ignore the linking
+changes and keep running plain '6l' and get reasonable results, but
+they can also control the linking details if desired.
+
 */

コアとなるコードの解説

このコミットは、src/cmd/cgo/doc.goファイルに、cgoのリンキングに関する詳細なドキュメントを追加しています。このドキュメントは、GoプログラムがC/C++コードと連携する際のリンキングの複雑性を管理するための「計画」として記述されており、特に「内部リンキング」と「外部リンキング」という2つの主要なリンキングモードと、それらを制御するための新しい#pragmaディレクティブについて深く掘り下げています。

追加されたドキュメントの主要なポイントは以下の通りです。

  1. 内部リンキングと外部リンキングの導入:

    • 内部リンキング: 6l(Goリンカ)が直接C/C++のオブジェクトファイルを処理し、Goバイナリにリンクするモードです。このモードは、純粋なGoプログラムがGCCなしでコンパイルできるというGoの目標を維持するために重要です。ただし、6lのシンプルさを保つため、リンクできるオブジェクトの種類には制限があります。
    • 外部リンキング: 6lはGoコードをgo.oという単一のオブジェクトファイルにまとめ、その後、ホストリンカ(通常はgcc)を呼び出して、go.oと他のC/C++コードをリンクするモードです。このモードは、任意のオブジェクトファイルを動的ライブラリを必要とせずにリンクできる利点がありますが、ホストリンカの存在が必須となります。
  2. リンキングディレクティブ (#pragma) の詳細:

    • #pragma cgo_dynamic_import: 内部リンキングモードで、動的ライブラリからのシンボル解決を指示します。シンボルのバージョンや特定のライブラリを指定できます。SWIGとの互換性のため、#pragma dynimportというエイリアスも提供されます。
    • #pragma cgo_dynamic_linker: 内部リンキングモードで、最終バイナリで使用する動的リンカのパスを指定します。
    • #pragma cgo_export: 内部・外部リンキングモードの両方で、GoシンボルをCコードから参照できるようにエクスポートします。SWIGとの互換性のため、#pragma dynexportというエイリアスも提供されます。
    • #pragma cgo_static_import: 外部リンキングモードで、ホストリンカによって解決されるべき未解決の参照を許可します。
    • #pragma cgo_ldflag: 外部リンキングモードで、ホストリンカに渡すコマンドライン引数を指定します。
  3. リンキングモードの決定ロジック:

    • 6lはデフォルトで、netos/userruntime/cgoといった標準ライブラリのホワイトリストに含まれるパッケージのみがcgoを使用している場合は内部リンキングモードを選択します。
    • それ以外の非標準のcgoパッケージが関与する場合は、外部リンキングモードを選択します。
    • ユーザーは6l -cgolink=internalまたは6l -cgolink=externalフラグを使用して、リンキングモードを明示的にオーバーライドできます。
    • 外部リンキング時のホストリンカは、デフォルトで$CCまたはgccが使用され、6l -hostld='...'フラグでオーバーライド可能です。
  4. 具体的な例: C.sinを呼び出すcgoパッケージの例を通じて、内部リンキングと外部リンキングのそれぞれで、6g(Goコンパイラ)、6c(Cgoコンパイラ)、gccによって生成されるコードと、リンカがどのように動作するかが詳細に説明されています。これにより、開発者は新しいリンキングメカニズムがどのように機能するかを具体的に理解できます。

このドキュメントの追加は、cgoの将来の動作変更に対する透明性を提供し、GoとC/C++の混在環境で作業する開発者が、より複雑なリンキングシナリオを理解し、管理するための重要な情報源となります。特に、Goの「GCC不要なコンパイル」という目標と、cgoによるC/C++リンキングの必要性との間のバランスを取るための設計思想が明確に示されています。

関連リンク

参考にした情報源リンク

[インデックス 15499] ファイルの概要

このコミットは、Go言語のcgoツールに関するドキュメント(src/cmd/cgo/doc.go)を拡張し、特にGoプログラムとC/C++コードを連携させる際の「内部リンキング」と「外部リンキング」の概念、およびそれらを制御するための新しい#pragmaディレクティブについて詳細な解説を追加しています。これにより、cgoのリンキングメカニズムの理解を深め、GoとC/C++の混在環境におけるビルドプロセスの複雑性を管理するための指針を提供しています。

コミット

  • コミットハッシュ: b89000bcabe16644d877e8d1251a3e6a784153d9
  • Author: Russ Cox rsc@golang.org
  • Date: Thu Feb 28 10:44:29 2013 -0800

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/b89000bcabe16644d877e8d1251a3e6a784153d9

元コミット内容

cmd/cgo: extend implementation comment

This is the plan for how to make host linking work with
the rest of the system.

There are two complications:

1. It is a goal to preserve the property that pure Go programs
(even ones importing "net") can be compiled without needing
gcc, so that a Go toolchain download works out of the box.
This forces the support for two linking modes: with and without
gcc.

2. It is a goal to allow users with old copies of SWIG to continue
to use those copies. This forces the support for "internal only"
packages. Perhaps it is reasonable to require a new SWIG.
I don't know.

R=iant
CC=golang-dev
https://golang.org/cl/7433043

変更の背景

このコミットは、GoプログラムがC/C++コードと連携する際に発生するリンキングの複雑性に対処するために行われました。特に、以下の2つの主要な課題が背景にあります。

  1. 純粋なGoプログラムのGCC不要なコンパイルの維持: Goの設計目標の一つに、純粋なGoプログラム(たとえnetパッケージのようにcgoを使用する可能性のあるパッケージをインポートしていても)がGCCのような外部Cコンパイラを必要とせずにコンパイルできるという特性を維持することがあります。これは、Goツールチェインをダウンロードしただけで、すぐにGoプログラムをビルドできる「箱から出してすぐに使える」体験を提供するために重要です。しかし、cgoを使用するとC/C++のリンキングが必要となり、GCCへの依存が発生する可能性があります。この矛盾を解決するためには、GCCの有無に応じて異なるリンキングモードをサポートする必要がありました。

  2. 古いSWIGバージョンのサポート: SWIG(Simplified Wrapper and Interface Generator)は、C/C++コードをGoを含む様々な言語から呼び出すためのラッパーコードを生成するツールです。古いSWIGのバージョンを使用しているユーザーが引き続きその環境で作業できるようにすることも目標とされていました。これは、特定のパッケージを「内部のみ」でリンクするモードをサポートする必要があることを意味します。ただし、コミットメッセージでは、新しいSWIGを要求することが妥当である可能性も示唆されており、この点についてはまだ検討の余地があることが伺えます。

これらの課題に対処するため、Goのリンカ(6l)がC/C++オブジェクトファイルをどのように扱うかについて、より柔軟なアプローチが必要とされました。具体的には、「内部リンキング」と「外部リンキング」という2つの異なるリンキングモードを導入し、それぞれのモードがどのような状況で適用されるべきか、そしてそれらを制御するための新しい#pragmaディレクティブを定義することが計画されました。このコミットは、これらの計画をcgoのドキュメントに明記することで、将来のcgoの動作変更に対する準備と、開発者への情報提供を目的としています。

前提知識の解説

このコミットの理解には、以下の概念に関する前提知識が役立ちます。

  • Go言語: Googleによって開発されたオープンソースのプログラミング言語。並行処理、ガベージコレクション、高速なコンパイルが特徴。
  • cgo: Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出したり、Goの関数をC言語から呼び出したりするためのメカニズムを提供します。import "C"という特殊なインポート文を使用します。
  • リンカ (Linker): コンパイラによって生成されたオブジェクトファイル(機械語コード)を結合し、実行可能なプログラムやライブラリを生成するツールです。未解決のシンボル(関数や変数の参照)を解決し、必要なライブラリをリンクします。
  • Goリンカ (6l): Go言語のツールチェインに含まれるリンカです。Goのソースコードから生成されたオブジェクトファイルをリンクして実行可能ファイルを生成します。Goのバージョンによって名前が異なる場合があります(例: go tool link)。
  • GCC (GNU Compiler Collection): C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラ群です。cgoを使用する場合、C/C++コードのコンパイルとリンキングにGCCが利用されることが一般的です。
  • オブジェクトファイル: コンパイラがソースコードをコンパイルした結果生成される中間ファイルで、機械語コードとシンボル情報を含みます。拡張子は.o(Unix/Linux)や.obj(Windows)など。
  • 動的ライブラリ (Dynamic Library): 実行時にロードされるライブラリです。プログラムの実行ファイルには、ライブラリのコードが直接含まれず、ライブラリへの参照のみが含まれます。これにより、複数のプログラムで同じライブラリを共有でき、ディスクスペースの節約やメモリ効率の向上が図られます。Unix/Linuxでは.so(Shared Object)、Windowsでは.dll(Dynamic Link Library)という拡張子が一般的です。
  • 静的ライブラリ (Static Library): リンク時にプログラムの実行ファイルに直接組み込まれるライブラリです。実行ファイルは自己完結型となり、ライブラリがシステムに存在しなくても実行できますが、ファイルサイズは大きくなります。Unix/Linuxでは.a(Archive)、Windowsでは.libという拡張子が一般的です。
  • #pragma ディレクティブ: C/C++言語において、コンパイラやリンカに対して特別な指示を与えるためのプリプロセッサディレクティブです。このコミットでは、cgoのリンキング動作を制御するための新しい#pragmaディレクティブが導入されています。
  • シンボル: プログラム内の関数や変数の名前です。リンカはこれらのシンボルを解決して、正しいメモリアドレスにマッピングします。
  • GLIBC: GNU C Libraryの略で、Linuxシステムで広く使用されている標準Cライブラリの実装です。多くのシステムコールや標準C関数を提供します。
  • SWIG (Simplified Wrapper and Interface Generator): C/C++で書かれたライブラリを、Go、Python、Java、Rubyなどの他の言語から利用できるようにするためのインターフェースコードを自動生成するツールです。

技術的詳細

このコミットで追加されたドキュメントは、cgoにおけるGoプログラムとC/C++コードのリンキングに関する重要な技術的詳細を説明しています。特に、「内部リンキング」と「外部リンキング」という2つの異なるリンキングモードと、それらを制御するための新しい#pragmaディレクティブに焦点を当てています。

内部リンキング (Internal Linking)

  • 概要: 6l(Goリンカ)が直接ホストのオブジェクトファイル(ELF, Mach-O, PEなど)を解析し、最終的な実行可能ファイルにリンクするモードです。
  • 特徴:
    • 6lがGoバイナリを単独で生成できます。
    • 6lのシンプルさを保つため、リンクできるオブジェクトの種類には制限があります(他のコードは動的ライブラリとしてのみ使用可能)。
    • 純粋なGoプログラム(netパッケージをインポートするものを含む)がGCCを必要とせずにコンパイルできるという特性を維持できます。これは、Goツールチェインをダウンロードしただけで、すぐにGoプログラムをビルドできるというGoの目標に合致します。
    • libc.soのような標準的な動的ライブラリへの依存は許容されます。
  • 適用シナリオ: netパッケージのように、cgoを使用するパッケージが標準ライブラリのホワイトリストに含まれる場合や、libc以外のライブラリへの依存が少ない場合に適しています。

外部リンキング (External Linking)

  • 概要: 6lはホストのオブジェクトファイルを処理せず、すべてのGoコードを単一のgo.oオブジェクトファイルにまとめます。その後、ホストリンカ(通常はgcc)を呼び出して、go.oファイルとサポートする非Goコードを組み合わせて最終的な実行可能ファイルを生成します。
  • 特徴:
    • 任意のオブジェクトファイルを動的ライブラリを必要とせずにリンクできます。
    • ホストリンカ(gccなど)の存在が必須となります。
    • cgoが関与する場合、コンパイルステップで既にgccが必要となるため、リンクステップでgccが必要となることは問題ありません。
    • 動的ライブラリの要件を回避できます。
  • 適用シナリオ: libc以外のライブラリへの依存がある場合や、より複雑なC/C++ライブラリをGoプログラムに組み込む場合に適しています。例えば、sqlite3のようなcgoでラップされたライブラリをビルドしてスタンドアロンの実行可能ファイルを生成する場合など。

リンキングディレクティブ (#pragma)

Goのリンカにパッケージ固有の指示を伝えるために、Cソースファイル内で6cによってコンパイルされる#pragmaディレクティブが導入されます。これらのディレクティブは.6オブジェクトファイルにコピーされ、リンカによって処理されます。

  • #pragma cgo_dynamic_import <local> [<remote> ["<library>"]]:

    • 内部リンキングモード: 未解決の参照<local>を動的ライブラリシンボルによって解決されると仮定します。オプションの<remote>はシンボルの名前とバージョンを、オプションの"<library>"はシンボルが見つかるべき特定のライブラリを指定します。
    • 例: putsシンボルをGLIBC_2.2.5バージョンのlibc.so.6からインポートする場合。
    • _ _ "<library>"とすることで、特定のシンボルをインポートせずに動的ライブラリへの依存関係を追加できます。
    • #pragma dynimport#pragma cgo_dynamic_importのエイリアスです(SWIGとの互換性のため)。
  • #pragma cgo_dynamic_linker "<path>":

    • 内部リンキングモード: 最終バイナリで<path>を動的リンカとして使用します。通常、runtime/cgoによって提供されます。
    • 例: /lib/ld-linux.so.2を動的リンカとして指定する場合。
  • #pragma cgo_export <local> <remote>:

    • 内部・外部リンキングモード両方: Goシンボル<local>をプログラムのエクスポートされたシンボルテーブルに<remote>として配置し、Cコードからその名前で参照できるようにします。これにより、CコードからGo関数を呼び出したり、Goのデータを共有したりすることが可能になります。
    • #pragma dynexport#pragma cgo_exportのエイリアスです(SWIGとの互換性のため)。
  • #pragma cgo_static_import <local>:

    • 外部リンキングモード: ホストリンカ用に準備されたgo.oオブジェクトファイル内の<local>への未解決の参照を許可します。これは、<local>go.oとリンクされる他のオブジェクトファイルによって提供されるという仮定に基づいています。
    • 例: puts_wrapperが外部から提供されることを示す場合。
  • #pragma cgo_ldflag "<arg>":

    • 外部リンキングモード: ホストリンカ(通常はgcc)を、.oファイルの後にコマンドライン引数"<arg>"を付けて呼び出します。引数はgcc用であり、ld用ではないことに注意が必要です。
    • 例: -lpthread-L/usr/local/sqlite3/libのようなリンカフラグを指定する場合。

リンキングモードの決定

  • デフォルトの動作: 6lは、cgoを使用するパッケージが標準ライブラリのホワイトリスト(net, os/user, runtime/cgo)にのみ含まれる場合、内部リンキングモードを使用します。それ以外の場合(非標準のcgoパッケージが関与する場合)、外部リンキングモードを使用します。
    • このルールにより、netのみを使用するgodocバイナリのビルドはGCCなしで実行でき、sqlite3のようなcgoラップされたライブラリのビルドはスタンドアロンの実行可能ファイルを生成できます。
  • コマンドラインでのオーバーライド: 6l -cgolink=internalまたは6l -cgolink=externalフラグを使用して、リンキングモードを明示的に指定できます。
  • 外部リンキング時のホストリンカ: 外部リンキングでは、6lは一時ディレクトリを作成し、パッケージアーカイブ内のホストオブジェクトファイルをそのディレクトリに書き込み、go.oファイルを書き込み、ホストリンカを呼び出します。ホストリンカのデフォルト値は$CCまたはgccです。6l -hostld='gcc -ggdb'フラグを使用して、特定のホストリンカコマンドラインをオーバーライドできます。

これらの変更により、Goのビルドシステムはリンキングの詳細を意識せずに6lを実行しても合理的な結果を得られるようになり、必要に応じてリンキングの詳細を制御することも可能になります。

コアとなるコードの変更箇所

このコミットによるコアとなるコードの変更は、src/cmd/cgo/doc.goファイルへの追加です。

--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -396,4 +396,230 @@
 and libcgo_thread_start to a gcc-compiled function that can be used to
 create a new thread, in place of the runtime's usual direct system
 calls.
 
+[NOTE: From here down is planned but not yet implemented.]
+
+Internal and External Linking
+
+The text above describes "internal" linking, in which 6l parses and
+links host object files (ELF, Mach-O, PE, and so on) into the final
+executable itself. Keeping 6l simple means we cannot possibly
+implement the full semantics of the host linker, so the kinds of
+objects that can be linked directly into the binary is limited (other
+code can only be used as a dynamic library). On the other hand, when
+using internal linking, 6l can generate Go binaries by itself.
+
+In order to allow linking arbitrary object files without requiring
+dynamic libraries, cgo will soon support an "external" linking mode
+too. In external linking mode, 6l does not process any host object
+files. Instead, it collects all the Go code and writes a single go.o
+object file containing it. Then it invokes the host linker (usually
+gcc) to combine the go.o object file and any supporting non-Go code
+into a final executable. External linking avoids the dynamic library
+requirement but introduces a requirement that the host linker be
+present to create such a binary.
+
+Most builds both compile source code and invoke the linker to create a
+binary. When cgo is involved, the compile step already requires gcc, so
+it is not problematic for the link step to require gcc too.
+
+An important exception is builds using a pre-compiled copy of the
+standard library. In particular, package net uses cgo on most systems,
+and we want to preserve the ability to compile pure Go code that
+imports net without requiring gcc to be present at link time. (In this
+case, the dynamic library requirement is less significant, because the
+only library involved is libc.so, which can usually be assumed
+present.)
+
+This conflict between functionality and the gcc requirement means we
+must support both internal and external linking, depending on the
+circumstances: if net is the only cgo-using package, then internal
+linking is probably fine, but if other packages are involved, so that there
+are dependencies on libraries beyond libc, external linking is likely
+to work better. The compilation of a package records the relevant
+information to support both linking modes, leaving the decision
+to be made when linking the final binary.
+
+Linking Directives
+
+In either linking mode, package-specific directives must be passed
+through to 6l. These are communicated by writing #pragma directives
+in a C source file compiled by 6c. The directives are copied into the .6 object file
+and then processed by the linker.
+
+The directives are:
+
+#pragma cgo_dynamic_import <local> [<remote> ["<library>"]]
+
+	In internal linking mode, allow an unresolved reference to
+	<local>, assuming it will be resolved by a dynamic library
+	symbol. The optional <remote> specifies the symbol's name and
+	possibly version in the dynamic library, and the optional "<library>"
+	names the specific library where the symbol should be found.
+
+	In the <remote>, # or @ can be used to introduce a symbol version.
+
+	Examples:
+	#pragma cgo_dynamic_import puts
+	#pragma cgo_dynamic_import puts puts#GLIBC_2.2.5
+	#pragma cgo_dynamic_import puts puts#GLIBC_2.2.5 "libc.so.6"
+
+	A side effect of the cgo_dynamic_import directive with a
+	library is to make the final binary depend on that dynamic
+	library. To get the dependency without importing any specific
+	symbols, use _ for local and remote.
+
+	Example:
+	#pragma cgo_dynamic_import _ _ "libc.so.6"
+
+	For compatibility with current versions of SWIG,
+	#pragma dynimport is an alias for #pragma cgo_dynamic_import.
+
+#pragma cgo_dynamic_linker "<path>"
+
+	In internal linking mode, use "<path>" as the dynamic linker
+	in the final binary. This directive is only needed from one
+	package when constructing a binary; by convention it is
+	supplied by runtime/cgo.
+
+	Example:
+	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+#pragma cgo_export <local> <remote>
+
+	In both internal and external linking modes, put the Go symbol
+	named <local> into the program's exported symbol table as
+	<remote>, so that C code can refer to it by that name. This
+	mechanism makes it possible for C code to call back into Go or
+	to share Go's data.
+
+	For compatibility with current versions of SWIG,
+	#pragma dynexport is an alias for #pragma cgo_export.
+
+#pragma cgo_static_import <local>
+
+	In external linking mode, allow unresolved references to
+	<local> in the go.o object file prepared for the host linker,
+	under the assumption that <local> will be supplied by the
+	other object files that will be linked with go.o.
+
+	Example:
+	#pragma cgo_static_import puts_wrapper
+
+#pragma cgo_ldflag "<arg>"
+
+	In external linking mode, invoke the host linker (usually gcc)
+	with "<arg>" as a command-line argument following the .o files.
+	Note that the arguments are for "gcc", not "ld".
+
+	Example:
+	#pragma cgo_ldflag "-lpthread"
+	#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
+
+A package compiled with cgo will include directives for both
+internal and external linking; the linker will select the appropriate
+subset for the chosen linking mode.
+
+Example
+
+As a simple example, consider a package that uses cgo to call C.sin.
+The following code will be generated by cgo:
+
+	// compiled by 6g
+
+	type _Ctype_double float64
+	func _Cfunc_sin(_Ctype_double) _Ctype_double
+
+	// compiled by 6c
+
+	#pragma cgo_dynamic_import sin sin#GLIBC_2.2.5 "libm.so.6"
+	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+	#pragma cgo_static_import _cgo_gcc_Cfunc_sin
+	#pragma cgo_ldflag "-lm"
+
+	void _cgo_gcc_Cfunc_sin(void*);
+
+	void
+	·_Cfunc_sin(struct{uint8 x[16];}p)
+	{
+		runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
+	}
+
+	// compiled by gcc, into foo.cgo2.o
+
+	void
+	_cgo_gcc_Cfunc_sin(void *v)
+	{
+		struct {
+			double p0;
+			double r;\n\t\t} __attribute__((__packed__)) *a = v;\n\t\ta->r = sin(a->p0);\n\t}\n\nWhat happens at link time depends on whether the final binary is linked\nusing the internal or external mode. If other packages are compiled in\n"external only" mode, then the final link will be an external one.\nOtherwise the link will be an internal one.\n\nThe directives in the 6c-compiled file are used according to the kind\nof final link used.\n\nIn internal mode, 6l itself processes all the host object files, in\nparticular foo.cgo2.o. To do so, it uses the cgo_dynamic_import and\ncgo_dynamic_linker directives to learn that the otherwise undefined\nreference to sin in foo.cgo2.o should be rewritten to refer to the\nsymbol sin with version GLIBC_2.2.5 from the dynamic library\n"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its\nruntime dynamic linker.\n\nIn external mode, 6l does not process any host object files, in\nparticular foo.cgo2.o. It links together the 6g- and 6c-generated\nobject files, along with any other Go code, into a go.o file. While\ndoing that, 6l will discover that there is no definition for\n_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This\nis okay, because 6l also processes the cgo_static_import directive and\nknows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host\nobject file, so 6l does not treat the missing symbol as an error when\ncreating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be\nprovided to the host linker by foo2.cgo.o, which in turn will need the\nsymbol 'sin'. 6l also processes the cgo_ldflag directives, so that it\nknows that the eventual host link command must include the -lm\nargument, so that the host linker will be able to find 'sin' in the\nmath library.\n\n6l Command Line Interface\n\nThe go command and any other Go-aware build systems invoke 6l\nto link a collection of packages into a single binary. By default, 6l will\npresent the same interface it does today:\n\n\t6l main.a\n\nproduces a file named 6.out, even if 6l does so by invoking the host\nlinker in external linking mode.\n\nBy default, 6l will decide the linking mode as follows: if the only\npackages using cgo are those on a whitelist of standard library\npackages (net, os/user, runtime/cgo), 6l will use internal linking\nmode. Otherwise, there are non-standard cgo packages involved, and 6l\nwill use external linking mode. The first rule means that a build of\nthe godoc binary, which uses net but no other cgo, can run without\nneeding gcc available. The second rule means that a build of a\ncgo-wrapped library like sqlite3 can generate a standalone executable\ninstead of needing to refer to a dynamic library. The specific choice\ncan be overridden using a command line flag: 6l -cgolink=internal or\n6l -cgolink=external.\n\nIn an external link, 6l will create a temporary directory, write any\nhost object files found in package archives to that directory (renamed\nto avoid conflicts), write the go.o file to that directory, and invoke\nthe host linker. The default value for the host linker is $CC, split\ninto fields, or else "gcc". The specific host linker command line can\nbe overridden using a command line flag: 6l -hostld='gcc -ggdb'\n\nThese defaults mean that Go-aware build systems can ignore the linking\nchanges and keep running plain '6l' and get reasonable results, but\nthey can also control the linking details if desired.\n\n */\n```

## コアとなるコードの解説

このコミットは、`src/cmd/cgo/doc.go`ファイルに、`cgo`のリンキングに関する詳細なドキュメントを追加しています。このドキュメントは、GoプログラムがC/C++コードと連携する際のリンキングの複雑性を管理するための「計画」として記述されており、特に「内部リンキング」と「外部リンキング」という2つの主要なリンキングモードと、それらを制御するための新しい`#pragma`ディレクティブについて深く掘り下げています。

追加されたドキュメントの主要なポイントは以下の通りです。

1.  **内部リンキングと外部リンキングの導入**:
    *   **内部リンキング**: `6l`(Goリンカ)が直接C/C++のオブジェクトファイルを処理し、Goバイナリにリンクするモードです。このモードは、純粋なGoプログラムがGCCなしでコンパイルできるというGoの目標を維持するために重要です。ただし、`6l`のシンプルさを保つため、リンクできるオブジェクトの種類には制限があります。
    *   **外部リンキング**: `6l`はGoコードを`go.o`という単一のオブジェクトファイルにまとめ、その後、ホストリンカ(通常は`gcc`)を呼び出して、`go.o`と他のC/C++コードをリンクするモードです。このモードは、任意のオブジェクトファイルを動的ライブラリを必要とせずにリンクできる利点がありますが、ホストリンカの存在が必須となります。

2.  **リンキングディレクティブ (`#pragma`) の詳細**:
    *   `#pragma cgo_dynamic_import`: 内部リンキングモードで、動的ライブラリからのシンボル解決を指示します。シンボルのバージョンや特定のライブラリを指定できます。SWIGとの互換性のため、`#pragma dynimport`というエイリアスも提供されます。
    *   `#pragma cgo_dynamic_linker`: 内部リンキングモードで、最終バイナリで使用する動的リンカのパスを指定します。
    *   `#pragma cgo_export`: 内部・外部リンキングモードの両方で、GoシンボルをCコードから参照できるようにエクスポートします。SWIGとの互換性のため、`#pragma dynexport`というエイリアスも提供されます。
    *   `#pragma cgo_static_import`: 外部リンキングモードで、ホストリンカによって解決されるべき未解決の参照を許可します。
    *   `#pragma cgo_ldflag`: 外部リンキングモードで、ホストリンカに渡すコマンドライン引数を指定します。

3.  **リンキングモードの決定ロジック**:
    *   `6l`はデフォルトで、`net`、`os/user`、`runtime/cgo`といった標準ライブラリのホワイトリストに含まれるパッケージのみが`cgo`を使用している場合は内部リンキングモードを選択します。
    *   それ以外の非標準の`cgo`パッケージが関与する場合は、外部リンキングモードを選択します。
    *   ユーザーは`6l -cgolink=internal`または`6l -cgolink=external`フラグを使用して、リンキングモードを明示的にオーバーライドできます。
    *   外部リンキング時のホストリンカは、デフォルトで`$CC`または`gcc`が使用され、`6l -hostld='...'`フラグでオーバーライド可能です。

4.  **具体的な例**: `C.sin`を呼び出す`cgo`パッケージの例を通じて、内部リンキングと外部リンキングのそれぞれで、`6g`(Goコンパイラ)、`6c`(Cgoコンパイラ)、`gcc`によって生成されるコードと、リンカがどのように動作するかが詳細に説明されています。これにより、開発者は新しいリンキングメカニズムがどのように機能するかを具体的に理解できます。

このドキュメントの追加は、`cgo`の将来の動作変更に対する透明性を提供し、GoとC/C++の混在環境で作業する開発者が、より複雑なリンキングシナリオを理解し、管理するための重要な情報源となります。特に、Goの「GCC不要なコンパイル」という目標と、`cgo`によるC/C++リンキングの必要性との間のバランスを取るための設計思想が明確に示されています。

## 関連リンク

*   Go Programming Language: [https://go.dev/](https://go.dev/)
*   cgo documentation: [https://go.dev/cmd/cgo/](https://go.dev/cmd/cgo/) (このコミットで追加された内容が最終的に統合される場所)
*   SWIG: [http://www.swig.org/](http://www.swig.org/)

## 参考にした情報源リンク

*   GitHub Commit: `b89000bcabe16644d877e8d1251a3e6a784153d9` (このコミット自体)
*   Go issue tracker (関連する議論や設計ドキュメントがある可能性): [https://go.dev/issue/](https://go.dev/issue/)
*   Go mailing lists (golang-devなど、設計に関する議論が行われる場所): [https://groups.google.com/g/golang-dev](https://groups.google.com/g/golang-dev)
*   Go source code: [https://github.com/golang/go](https://github.com/golang/go)
*   GCC documentation: [https://gcc.gnu.org/onlinedocs/](https://gcc.gnu.org/onlinedocs/)
*   GLIBC documentation: [https://www.gnu.org/software/libc/manual/](https://www.gnu.org/software/libc/manual/)
*   ELF (Executable and Linkable Format) specification: (OSのドキュメントや標準化団体から入手可能)
*   Mach-O (macOS/iOS executable format) documentation: (Apple Developer Documentationから入手可能)
*   PE (Portable Executable format) documentation: (Microsoft Learnから入手可能)