[インデックス 15616] ファイルの概要
このコミットは、Go言語のcgo
ツールにおけるシンボルエクスポートのメカニズムを改善し、より柔軟なリンカフラグの指定を可能にするものです。具体的には、既存のcgo_export
プラグマを静的リンクと動的リンクのシナリオに合わせてcgo_export_static
とcgo_export_dynamic
に分割し、さらにcgo_ldflag
プラグマを導入して、Goのソースコードから直接リンカフラグを指定できるようにしています。これにより、Cgoを利用したGoとCの連携が、より細かく制御できるようになります。
コミット
commit fb59aed60b64319ad6fb1d6e6f18e7b1d96aaf77
Author: Russ Cox <rsc@golang.org>
Date: Wed Mar 6 16:57:14 2013 -0500
cmd/cgo: split cgo_export into cgo_export_static and cgo_export_dynamic
Also emit cgo_ldflag pragmas.
R=golang-dev, remyoudompheng, iant
CC=golang-dev
https://golang.org/cl/7530043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fb59aed60b64319ad6fb1d6e6f18e7b1d96aaf77
元コミット内容
このコミットは、cgo
ツールがGoとCのコードを連携させる際に使用するディレクティブの挙動を変更・拡張しています。
主な変更点は以下の通りです。
cgo_export
プラグマの分割:- これまでの
#pragma cgo_export
は、静的リンクと動的リンクの両方でGoのシンボルをCコードにエクスポートするために使用されていました。 - このコミットにより、
#pragma cgo_export_static
と#pragma cgo_export_dynamic
に明確に分割されました。 #pragma dynexport
は#pragma cgo_export_dynamic
のエイリアスとして残されています。
- これまでの
cgo_ldflag
プラグマの導入:#pragma cgo_ldflag "arg"
という新しいプラグマが導入されました。これにより、Goのソースコード内で直接リンカフラグを指定できるようになります。これは特に外部リンカ(通常はgcc)を使用する際に役立ちます。
CgoFlags
のデータ構造変更:src/cmd/cgo/main.go
において、Package
構造体のCgoFlags
フィールドの型がmap[string]string
からmap[string][]string
に変更されました。これにより、同じフラグ名に対して複数の引数をリストとして保持できるようになり、特にLDFLAGS
のような複数の引数を取るフラグの扱いが改善されます。
- リンカでの処理の更新:
src/cmd/ld/go.c
において、リンカがcgo_export_dynamic
とcgo_ldflag
ディレクティブを適切に解釈し、処理するように更新されました。
これらの変更により、Cgoを利用したGoプログラムのビルドプロセスにおいて、シンボルエクスポートとリンカオプションの指定がより細かく、かつ意図的に制御できるようになります。
変更の背景
このコミットが行われた背景には、GoプログラムとCライブラリを連携させるcgo
の機能性、特にシンボルエクスポートとリンカオプションの指定における柔軟性の向上が求められていたことがあります。
-
静的リンクと動的リンクの区別:
- Goプログラムは、デフォルトで静的リンクを志向しますが、Cgoを使用する場合、Cライブラリとの連携においては動的リンクが必要となるケースも少なくありません。
- 従来の
cgo_export
プラグマは、静的・動的リンクの区別なくシンボルをエクスポートする機能を提供していましたが、これにより、特定のリンクモードでのみシンボルをエクスポートしたいという、より高度な要件に対応できませんでした。例えば、共有ライブラリとしてビルドされるGoコードからCコードにシンボルをエクスポートする場合と、完全に静的にリンクされる実行ファイルからエクスポートする場合では、その挙動や意図が異なることがあります。この曖昧さを解消し、開発者が明示的にどちらのリンクモードでシンボルをエクスポートするかを制御できるようにするために、cgo_export_static
とcgo_export_dynamic
への分割が必要とされました。
-
リンカフラグの直接指定:
cgo
は、Cコードをコンパイル・リンクするために、内部的にCコンパイラ(通常はgcc)を呼び出します。この際、特定のライブラリをリンクしたり、リンカの挙動を調整したりするために、リンカフラグ(LDFLAGS
)を渡す必要があります。- これまでは、
#cgo LDFLAGS: -L/path/to/lib -lmylib
のように、#cgo
ディレクティブを通じてリンカフラグを指定していました。しかし、これはGoのビルドシステムが_cgo_flags
ファイルに書き出し、それを外部のビルドシステム(Makeなど)が読み取ってgccに渡すという間接的な方法でした。 #pragma cgo_ldflag
の導入は、Goのソースコードから直接リンカにフラグを渡す、より直接的なメカニズムを提供します。これにより、ビルドスクリプトの複雑さを軽減し、GoコードとCコードのリンカ設定をより密接に管理できるようになります。これは、特に複雑なCライブラリに依存するプロジェクトや、特定のリンカ機能(例: バージョンシンボル、セクション配置)を利用したい場合に有用です。
これらの変更は、cgo
の柔軟性と表現力を高め、GoとCのハイブリッドアプリケーション開発におけるより複雑なシナリオに対応するための基盤を強化することを目的としています。
前提知識の解説
このコミットの理解を深めるためには、以下の概念について基本的な知識が必要です。
-
Go言語の
cgo
:cgo
はGo言語に組み込まれているツールで、GoプログラムからC言語のコードを呼び出したり、逆にC言語のコードからGo言語の関数を呼び出したりするためのメカニズムを提供します。これはForeign Function Interface (FFI) の一種です。- Goのソースファイル内に
import "C"
と記述することでcgo
が有効になり、Cの関数をGoから呼び出したり、Goの関数をCから呼び出せるようにエクスポートしたりするための特別なコメント(#cgo
ディレクティブや#pragma
ディレクティブ)を使用します。 cgo
は、Goのビルドプロセス中にCコードをコンパイルし、Goのオブジェクトファイルとリンクするための橋渡し役を担います。
-
静的リンクと動的リンク:
- 静的リンク (Static Linking): プログラムが依存するすべてのライブラリのコードが、最終的な実行ファイルに直接組み込まれる方式です。
- 利点: 実行ファイルが自己完結型になり、他のシステムに配布する際に依存ライブラリの有無を気にする必要がありません。実行時のパフォーマンスがわずかに向上する可能性があります。
- 欠点: 実行ファイルのサイズが大きくなる傾向があります。複数のプログラムが同じライブラリを使用する場合でも、それぞれの実行ファイルにライブラリのコピーが含まれるため、ディスクスペースの無駄が生じます。ライブラリの更新があった場合、そのライブラリに依存するすべてのプログラムを再コンパイル・再リンクする必要があります。
- 動的リンク (Dynamic Linking): プログラムが依存するライブラリのコードが、最終的な実行ファイルには組み込まれず、実行時に共有ライブラリ(WindowsではDLL、Linuxでは.so、macOSでは.dylib)としてロードされる方式です。
- 利点: 実行ファイルのサイズが小さくなります。複数のプログラムが同じ共有ライブラリを使用する場合、メモリ上でライブラリのコードを共有できるため、メモリ効率が良くなります。ライブラリの更新があった場合、プログラムを再コンパイル・再リンクすることなく、共有ライブラリを置き換えるだけで対応できます。
- 欠点: 実行時に依存ライブラリが存在しないとプログラムが起動できません("DLL Hell"や"dependency hell"と呼ばれる問題)。実行時のパフォーマンスがわずかに低下する可能性があります。
- 静的リンク (Static Linking): プログラムが依存するすべてのライブラリのコードが、最終的な実行ファイルに直接組み込まれる方式です。
-
シンボルエクスポート:
- プログラムやライブラリが、外部のコードからアクセスできるように、その内部の関数や変数の名前(シンボル)を公開することです。
- Cgoにおいては、Goで定義された関数や変数をCコードから呼び出せるようにするために、これらのGoシンボルをCのリンカが認識できる形式でエクスポートする必要があります。
-
プラグマ (Pragma):
- コンパイラやリンカに対する特別な指示を与えるためのディレクティブです。C/C++では
#pragma
キーワードを使用します。 cgo
では、Goのソースコード内に#pragma
ディレクティブを記述することで、cgo
ツールに対して特定の処理(例: シンボルのエクスポート、リンカフラグの追加)を指示します。
- コンパイラやリンカに対する特別な指示を与えるためのディレクティブです。C/C++では
-
リンカフラグ (Linker Flags / LDFLAGS):
- リンカに渡されるコマンドライン引数で、リンク処理の挙動を制御します。
- 例:
-L/path/to/lib
: ライブラリを検索するディレクトリを追加します。-lfoo
:libfoo.a
またはlibfoo.so
(または対応する動的ライブラリ)という名前のライブラリをリンクします。-Wl,--version-script=version.map
: 特定のリンカスクリプトを使用します。
cgo
を使用するGoプログラムでは、Cコードが依存する外部ライブラリをリンクするためにこれらのフラグが必要となることがあります。
これらの概念を理解することで、このコミットがGoのビルドシステム、特にCgoとの連携においてどのような課題を解決し、どのような機能強化をもたらしたのかを深く把握することができます。
技術的詳細
このコミットは、Goのcgo
ツールチェーンにおけるシンボルエクスポートとリンカフラグ処理の内部実装に深く関わる変更を含んでいます。
-
#pragma cgo_export
の分割とsrc/cmd/cc/dpchk.c
の変更:src/cmd/cc/dpchk.c
は、Goのコンパイラ(cmd/cc
)の一部であり、Cgo関連の#pragma
ディレクティブを解析する役割を担っています。- 変更前は、
strcmp(verb, "cgo_export") == 0 || strcmp(verb, "dynexport") == 0
という条件でcgo_export
とdynexport
を同じように処理していました。 - 変更後、
dynexport
はcgo_export_dynamic
に内部的に変換され、cgo_export_static
とcgo_export_dynamic
が明示的に区別されるようになりました。 fmtprint(&pragcgobuf, "%s %q\\n", verb, local->name);
のように、verb
(cgo_export_static
またはcgo_export_dynamic
)が直接pragcgobuf
(_cgo_export.c
などのCgoが生成する中間ファイルに書き込まれるバッファ)に書き込まれるようになりました。これにより、リンカがどの種類のエクスポートであるかを正確に識別できるようになります。- エラーメッセージも
yyerror("usage: #pragma %s local [remote]", verb);
のように、使用されたプラグマ名を含むように改善されています。
-
#pragma cgo_ldflag
の導入とsrc/cmd/cc/dpchk.c
、src/cmd/ld/go.c
の変更:src/cmd/cc/dpchk.c
に、新しい#pragma cgo_ldflag
の解析ロジックが追加されました。これは引用符で囲まれた文字列引数(リンカフラグ)を受け取り、fmtprint(&pragcgobuf, "cgo_ldflag %q\\n", p);
として中間ファイルに書き出します。src/cmd/ld/go.c
はGoのリンカ(cmd/ld
)のCgo関連の処理を担当しています。このファイルに、cgo_ldflag
ディレクティブを読み取り、その引数をリンカの内部的なldflag
リストに追加するロジックが追加されました。ldflag = realloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
のように、動的にリンカフラグの配列を拡張して格納しています。これにより、Goのソースコード内で指定されたリンカフラグが、最終的なリンクコマンドに確実に含まれるようになります。
-
CgoFlags
の型変更とsrc/cmd/cgo/main.go
、src/cmd/cgo/out.go
の変更:src/cmd/cgo/main.go
のPackage
構造体において、CgoFlags
フィールドの型がmap[string]string
からmap[string][]string
に変更されました。これは、#cgo
ディレクティブで指定されるCFLAGS
やLDFLAGS
が、実際には複数の引数を持つ可能性があるためです。例えば、-L/path/to/lib -lmylib
は2つの異なる引数として扱われるべきです。src/cmd/cgo/gcc.go
のaddToFlag
関数も、この新しい型に合わせてp.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
のように、引数をリストに直接追加するように変更されました。src/cmd/cgo/out.go
では、_cgo_flags
ファイルへの書き出しロジックが更新されました。fmt.Fprintf(fflg, "_CGO_%s=%s\\n", k, strings.Join(v, " "))
のように、CgoFlags
マップの値が文字列のリストになったため、strings.Join
を使ってスペース区切りの単一文字列として書き出されます。- さらに重要な変更として、
src/cmd/cgo/out.go
のLDFLAGS
処理が追加されました。if k == "LDFLAGS"
のブロック内で、LDFLAGS
の各引数に対して#pragma cgo_ldflag %q\\n
をfc
(Cgoが生成するCソースファイル)に書き出すようになりました。これは、#cgo LDFLAGS
で指定されたフラグが、最終的に#pragma cgo_ldflag
としてCgoの中間Cファイルに埋め込まれ、リンカによって処理されるという新しいフローを確立します。
-
リンカにおける
cgo_export_dynamic
の処理:src/cmd/ld/go.c
のloadcgo
関数内で、cgo_export_dynamic
ディレクティブの処理が更新されました。s->dynimpname = remote;
とs->dynexport = 1;
は、シンボルが動的にエクスポートされることを示します。dynexp
配列は、動的にエクスポートされるシンボルのリストを保持します。この配列への追加ロジックも、競合するエクスポートディレクティブがないかを確認するように強化されています。
これらの変更は、GoのビルドシステムがCgoを介してCコードと連携する際の、シンボル管理とリンカオプション指定の柔軟性と堅牢性を大幅に向上させるものです。特に、静的・動的リンクの区別を明確にし、リンカフラグをGoソースから直接制御できるようになった点は、複雑なC/Goハイブリッドプロジェクトの開発において大きなメリットとなります。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は、以下のファイルに集中しています。
-
src/cmd/cc/dpchk.c
:pragcgo
関数内で、cgo_export
とdynexport
の処理がcgo_export_static
とcgo_export_dynamic
に分割されました。- 新しい
cgo_ldflag
プラグマの解析ロジックが追加されました。
--- a/src/cmd/cc/dpchk.c +++ b/src/cmd/cc/dpchk.c @@ -692,22 +692,24 @@ pragcgo(char *verb) goto out; } - if(strcmp(verb, "cgo_export") == 0 || strcmp(verb, "dynexport") == 0) { + if(strcmp(verb, "dynexport") == 0) + verb = "cgo_export_dynamic"; + if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) { local = getimpsym(); if(local == nil) goto err2; if(!more()) { - fmtprint(&pragcgobuf, "cgo_export %q\n", local->name); + fmtprint(&pragcgobuf, "%s %q\n", verb, local->name); goto out; } remote = getimpsym(); if(remote == nil) goto err2; - fmtprint(&pragcgobuf, "cgo_export %q %q\n", local->name, remote->name); + fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name); goto out; err2: - yyerror("usage: #pragma cgo_export local [remote]"); + yyerror("usage: #pragma %s local [remote]", verb); goto out; } @@ -749,6 +751,18 @@ pragcgo(char *verb) goto out; } + if(strcmp(verb, "cgo_ldflag") == 0) { + p = getquoted(); + if(p == nil) + goto err5; + fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p); + goto out; + + err5: + yyerror("usage: #pragma cgo_ldflag \"arg\""); + goto out; + } + out: while(getnsc() != '\n') ;
-
src/cmd/cgo/doc.go
:cgo_export
のドキュメントがcgo_export_dynamic
に更新され、cgo_export_static
の新しい説明が追加されました。cgo_ldflag
のドキュメントが追加されました。
-
src/cmd/cgo/main.go
:Package
構造体のCgoFlags
フィールドの型がmap[string]string
からmap[string][]string
に変更されました。
--- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -33,7 +33,7 @@ type Package struct { PtrSize int64 IntSize int64 GccOptions []string - CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS) + CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS) Written map[string]bool Name map[string]*Name // accumulated Name from Files ExpFunc []*ExpFunc // accumulated ExpFunc from Files @@ -312,7 +312,7 @@ func newPackage(args []string) *Package { PtrSize: ptrSize, IntSize: intSize, GccOptions: gccOptions, - CgoFlags: make(map[string]string), + CgoFlags: make(map[string][]string), Written: make(map[string]bool), } return p
-
src/cmd/cgo/out.go
:_cgo_flags
ファイルへの書き出しで、CgoFlags
の値がstrings.Join
で結合されるようになりました。LDFLAGS
に対して、各引数を#pragma cgo_ldflag
としてCgoが生成するCソースファイルに書き出すロジックが追加されました。cgo_export
の代わりにcgo_export_dynamic
が使用されるようになりました。cgo_export_static
の新しいプラグマが追加されました。
--- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -31,7 +31,12 @@ func (p *Package) writeDefs() { fflg := creat(*objDir + "_cgo_flags") for k, v := range p.CgoFlags { - fmt.Fprintf(fflg, "_CGO_%s=%s\\n", k, v) + fmt.Fprintf(fflg, "_CGO_%s=%s\\n", k, strings.Join(v, " ")) + if k == "LDFLAGS" { + for _, arg := range v { + fmt.Fprintf(fc, "#pragma cgo_ldflag %q\\n", arg) + } + } } fflg.Close() @@ -100,6 +105,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "extern char %s[];\\n", n.C) fmt.Fprintf(fm, "void *_cgohack_%s = %s;\\n\\n", n.C, n.C) + fmt.Fprintf(fc, "#pragma cgo_import_static %s\\n", n.C) fmt.Fprintf(fc, "extern byte *%s;\\n", n.C) cVars[n.C] = true @@ -651,8 +657,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { if fn.Recv != nil { goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname } - fmt.Fprintf(fc, "#pragma cgo_export %s\\n", goname) + fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\\n", goname) fmt.Fprintf(fc, "extern void ·%s();\\n\\n", goname) + fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\\n", cPrefix, exp.ExpName) fmt.Fprintf(fc, "#pragma textflag 7\\n") // no split stack, so no use of m or g fmt.Fprintf(fc, "void\\n") fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\\n", cPrefix, exp.ExpName)
-
src/cmd/ld/go.c
:loadcgo
関数内で、cgo_export
の代わりにcgo_export_dynamic
を処理するように変更されました。cgo_ldflag
ディレクティブを解析し、リンカの内部的なldflag
リストに追加するロジックが追加されました。
--- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -487,7 +487,9 @@ loadcgo(char *file, char *pkg, char *p, int n) continue; } - if(strcmp(f[0], "cgo_export") == 0) { + // TODO: cgo_export_static + + if(strcmp(f[0], "cgo_export_dynamic") == 0) { if(nf < 2 || nf > 3) goto err; local = f[1]; @@ -501,13 +503,17 @@ loadcgo(char *file, char *pkg, char *p, int n) if(fprint(2, "%s: symbol is both imported and exported: %s\\n", argv0, local), nerrors++, 0) ; } - s->dynimpname = remote; s->dynexport = 1; - - if(ndynexp%32 == 0) - dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); - dynexp[ndynexp++] = s; - + if(s->dynimpname == nil) { + s->dynimpname = remote; + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + dynexp[ndynexp++] = s; + } else if(strcmp(s->dynimpname, remote) != 0) { + fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\\n", argv0, s->name, s->dynimpname, remote); + nerrors++; + return; + } if(local != f[1]) free(local); continue; @@ -528,6 +534,15 @@ loadcgo(char *file, char *pkg, char *p, int n) } continue; } + + if(strcmp(f[0], "cgo_ldflag") == 0) { + if(nf != 2) + goto err; + if(nldflag%32 == 0) + ldflag = realloc(ldflag, (nldflag+32)*sizeof ldflag[0]); + ldflag[nldflag++] = strdup(f[1]); + continue; + } } free(p0); return;
-
src/cmd/ld/lib.h
:- リンカの内部変数として
nldflag
とldflag
が追加されました。
--- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -138,6 +138,8 @@ EXTERN char* outfile; EXTERN int32 nsymbol; EXTERN char* thestring; EXTERN int ndynexp; +EXTERN int nldflag; +EXTERN char** ldflag; EXTERN int havedynamic; EXTERN int iscgo; EXTERN int isobj;
- リンカの内部変数として
これらの変更は、cgo
のフロントエンド(cmd/cc
)、中間処理(cmd/cgo
)、そしてバックエンド(cmd/ld
)にわたる一貫した機能強化を示しています。
コアとなるコードの解説
このコミットのコアとなる変更は、cgo
がGoとCの間のインターフェースをどのように生成し、リンカにどのように指示を伝えるかというメカニズムにあります。
-
#pragma cgo_export
の分割 (src/cmd/cc/dpchk.c
):src/cmd/cc/dpchk.c
のpragcgo
関数は、Goのソースコード内に埋め込まれた#pragma
ディレクティブを解析する部分です。- 以前は
cgo_export
とdynexport
が同じロジックで処理されていましたが、この変更により、dynexport
は内部的にcgo_export_dynamic
として扱われるようになります。 - そして、
cgo_export_static
とcgo_export_dynamic
が明示的に区別され、それぞれのプラグマ名がそのままpragcgobuf
(Cgoが生成するCファイルに書き込まれるバッファ)に書き込まれます。 - これにより、後続のツール(特にリンカ)が、このシンボルが静的リンク時にエクスポートされるべきか、動的リンク時にエクスポートされるべきかを正確に判断できるようになります。これは、Goの関数をCの共有ライブラリから呼び出す場合と、Goの実行ファイルに静的にリンクされたCコードから呼び出す場合で、リンカの挙動を最適化するために重要です。
-
#pragma cgo_ldflag
の処理フロー (src/cmd/cc/dpchk.c
,src/cmd/cgo/out.go
,src/cmd/ld/go.c
):src/cmd/cc/dpchk.c
: Goソース内の#pragma cgo_ldflag "arg"
を解析し、cgo_ldflag "arg"
という形式で中間ファイルに書き出します。src/cmd/cgo/out.go
: ここが重要な変更点です。#cgo LDFLAGS: ...
というGoのビルドディレクティブで指定されたリンカフラグは、Package.CgoFlags["LDFLAGS"]
に文字列のリストとして格納されます。このコミットでは、out.go
がこのLDFLAGS
リストの各要素を読み取り、それぞれを#pragma cgo_ldflag "..."
という形式でCgoが生成するCソースファイル(_cgo_main.c
など)に書き出すようになりました。- つまり、
#cgo LDFLAGS: -L/usr/local/lib -lmylib
と書くと、Cgoは内部的に#pragma cgo_ldflag "-L/usr/local/lib"
と#pragma cgo_ldflag "-lmylib"
という2つのプラグマを生成するわけです。
- つまり、
src/cmd/ld/go.c
: Goのリンカは、Cgoが生成したCソースファイルをコンパイルした結果のオブジェクトファイルを読み込みます。このオブジェクトファイルには、#pragma cgo_ldflag
ディレクティブが埋め込まれています。リンカはこれらのディレクティブを解析し、指定されたリンカフラグを自身の内部的なリンカフラグリスト(ldflag
配列)に追加します。最終的に、リンカが外部のCリンカ(gccなど)を呼び出す際に、このldflag
リストの内容がコマンドライン引数として渡されます。- このフローにより、Goのソースコード内で指定されたリンカフラグが、Goのビルドシステムを介して最終的なリンクコマンドに直接、かつ確実に反映されるようになります。これは、特にクロスコンパイル環境や、特定のリンカ機能に依存する複雑なビルド設定において、非常に有用な機能です。
-
CgoFlags
の型変更 (src/cmd/cgo/main.go
):CgoFlags
がmap[string]string
からmap[string][]string
に変更されたことで、#cgo
ディレクティブで指定されるフラグ(例:CFLAGS
,LDFLAGS
)が、単一の文字列ではなく、複数の文字列(引数)のリストとして扱えるようになりました。- これにより、
-L/path -lfoo
のような複数の引数を持つフラグが、["-L/path", "-lfoo"]
のように正確に表現・処理できるようになり、ビルドシステムの堅牢性が向上します。
これらの変更は、GoのビルドシステムがCgoを介してCコードと連携する際の、シンボル管理とリンカオプション指定の柔軟性と堅牢性を大幅に向上させるものです。特に、静的・動的リンクの区別を明確にし、リンカフラグをGoソースから直接制御できるようになった点は、複雑なC/Goハイブリッドプロジェクトの開発において大きなメリットとなります。
関連リンク
- Go言語の
cgo
に関する公式ドキュメント: https://pkg.go.dev/cmd/cgo - Go言語のリンカに関する情報(Goのソースコード内):
src/cmd/ld/
ディレクトリ - Go言語のコンパイラに関する情報(Goのソースコード内):
src/cmd/cc/
ディレクトリ
参考にした情報源リンク
- Go言語のソースコード: https://github.com/golang/go
- このコミットの変更リスト (Gerrit Change-ID):
https://golang.org/cl/7530043
(現在はGitHubのコミットページにリダイレクトされます) - 静的リンクと動的リンクに関する一般的な情報源(例: Wikipedia, プログラミング関連のブログや書籍)
- C言語の
#pragma
ディレクティブに関する一般的な情報源(例: C言語の標準仕様、コンパイラのドキュメント) - リンカの動作とリンカフラグに関する一般的な情報源(例: GNU Binutilsのドキュメント、OSのリンカマニュアル)