[インデックス 15550] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go
において、SWIG (Simplified Wrapper and Interface Generator) のバージョン 2.0.9 以降で必要となる -intgosize
フラグを渡すように変更を加えるものです。これにより、Goの int
型のサイズをSWIGに正確に伝え、C/C++コードとの連携における潜在的な問題を解決します。
コミット
commit 7c793826d44a6abb76f7846c51503f574eafe9e4
Author: Carlos Castillo <cookieo9@gmail.com>
Date: Fri Mar 1 16:48:21 2013 -0800
cmd/go: pass -intgosize to SWIG
swig >= 2.0.9 requires the size of int values to be passed via a command line flag. Should swig complain about the -intgosize not being supported, then alert the user to their outdated version of swig.
Fixes #4756.
R=golang-dev, minux.ma, iant
CC=golang-dev
https://golang.org/cl/7331048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7c793826d44a6abb76f7846c51503f574eafe9e4
元コミット内容
cmd/go: pass -intgosize to SWIG
SWIG バージョン 2.0.9 以降では、int
型のサイズをコマンドラインフラグで渡す必要があります。もしSWIGが -intgosize
をサポートしていないと文句を言ってきた場合、ユーザーにSWIGのバージョンが古いことを警告するべきです。
Go Issue #4756 を修正します。
変更の背景
この変更の背景には、Go言語とC/C++言語の相互運用性を提供するツールであるSWIGの進化があります。SWIGは、異なるプログラミング言語間でC/C++ライブラリを簡単に利用できるようにするためのラッパーコードを生成します。
Go言語の int
型は、実行環境のアーキテクチャ(32ビットまたは64ビット)によってサイズが異なります。例えば、32ビットシステムでは int
は32ビット(4バイト)ですが、64ビットシステムでは64ビット(8バイト)になることがあります。
SWIGのバージョン2.0.9以降では、このGoの int
型の可変サイズに対応するため、明示的に int
のサイズをコマンドライン引数 -intgosize
で指定するようになりました。これにより、SWIGが生成するラッパーコードが、Goの int
型とC/C++の int
型の間のサイズ不一致による問題を回避できるようになります。
このコミットは、GoのビルドツールがSWIGを呼び出す際に、Goの int
型の実際のサイズを検出し、その情報を -intgosize
フラグとしてSWIGに渡すようにすることで、この新しい要件に対応しています。もし古いバージョンのSWIGが使用されており、このフラグを認識しない場合は、適切なエラーメッセージをユーザーに表示し、SWIGのアップデートを促すように設計されています。
具体的には、Go Issue #4756 で報告された問題(SWIG 2.0.9以降でビルドが失敗する問題)を修正するためにこの変更が導入されました。
前提知識の解説
SWIG (Simplified Wrapper and Interface Generator)
SWIGは、C/C++/Objective-Cのコードを、Python, Perl, Ruby, Java, C#, Go, PHP, JavaScript, R, Lua, Octave, Scilab, Scheme, Tcl, Common Lisp, OCaml, Modula-3, Allegro CL, CLISP, Eiffel, Erlang, Guile, MzScheme, Pike, S-Lang, Smalltalk, V8 JavaScript, WxPython, XMLなど、様々なスクリプト言語や他のプログラミング言語から利用できるようにするためのオープンソースツールです。
SWIGは、C/C++のヘッダーファイルやインターフェース定義ファイル(.i
ファイル)を読み込み、ターゲット言語(この場合はGo)からC/C++関数を呼び出したり、C/C++クラスのオブジェクトを操作したりするための「ラッパーコード」を自動生成します。これにより、開発者は手動で複雑なFII (Foreign Function Interface) コードを書く手間を省き、異なる言語間の連携を容易にすることができます。
Go言語の int
型
Go言語の int
型は、プラットフォームに依存する整数型です。これは、実行されているCPUアーキテクチャのワードサイズ(通常は32ビットまたは64ビット)に合わせてサイズが決定されます。
- 32ビットシステム:
int
は32ビット(4バイト) - 64ビットシステム:
int
は64ビット(8バイト)
この特性は、Goプログラムが異なるアーキテクチャでコンパイル・実行される際に、int
のサイズが自動的に最適化されるという利点がありますが、C/C++のような固定サイズの整数型(例: int
は通常32ビット)と連携する際には、サイズ不一致による問題を引き起こす可能性があります。
Cgo
Cgoは、GoプログラムからCコードを呼び出すためのGoの機能です。Cgoを使用すると、Goのソースファイル内にCのコードを直接記述したり、既存のCライブラリをGoからリンクして利用したりできます。SWIGは、GoとC/C++の連携において、Cgoのメカニズムを利用してラッパーコードを生成します。
Goのビルドプロセス (cmd/go
)
cmd/go
は、Go言語の公式ビルドツールであり、Goプログラムのコンパイル、リンク、テスト、依存関係の管理など、様々なタスクを実行します。Goのソースコードをビルドする際、もしCgoやSWIGが関与するパッケージがある場合、cmd/go
はこれらのツールを適切に呼び出し、生成されたC/C++コードやラッパーコードをGoのビルドプロセスに統合します。
技術的詳細
このコミットは、src/cmd/go/build.go
ファイルに以下の主要な変更を加えています。
-
processOutput
関数の導入: 以前はrun
関数内で直接行われていた、コマンド実行結果の出力処理(末尾の改行追加、Cgo関連のエラーメッセージの整形)がprocessOutput
という新しいヘルパー関数に切り出されました。これにより、コードの再利用性と可読性が向上しています。 -
toolchain.gc
メソッドの変更:toolchain
インターフェースのgc
(Goコンパイラ) メソッドのシグネチャが変更されました。以前は(ofile string, err error)
を返していましたが、変更後は(ofile string, out []byte, err error)
を返すようになりました。これにより、Goコンパイラの標準出力(out []byte
)も呼び出し元に返されるようになり、コンパイラからの警告やエラーメッセージをより詳細に処理できるようになります。 -
swigIntSize
関数の導入: Goのint
型のサイズ(32ビットまたは64ビット)を動的に判定するためのswigIntSize
関数が追加されました。 この関数は、swig_intsize.go
という一時的なGoソースファイルを生成します。このファイルには、const i int = 1 << 32
という定数宣言が含まれています。 この一時ファイルをGoコンパイラ (buildToolchain.gc
) でコンパイルを試みます。- もしコンパイルが成功した場合、それは
int
が64ビットであることを意味します(1 << 32
がint
に収まるため)。この場合、"64"
を返します。 - もしコンパイルが失敗した場合(例:
constant 4294967296 overflows int
のようなエラー)、それはint
が32ビットであることを意味します(1 << 32
がint
に収まらないため)。この場合、"32"
を返します。 この巧妙な方法で、実行環境のint
サイズをビルド時に判定しています。
- もしコンパイルが成功した場合、それは
-
swigOne
関数への-intgosize
フラグの追加: SWIGの単一の入力ファイルを処理するswigOne
関数が変更され、intgosize
引数が追加されました。 SWIGコマンドを実行する際に、"-intgosize", intgosize
という引数が追加されるようになりました。これにより、Goのint
型のサイズがSWIGに正確に伝えられます。 -
SWIGのエラーハンドリングの改善:
swigOne
関数内でSWIGの実行結果をチェックする際に、SWIGの出力に"Unrecognized option -intgosize"
という文字列が含まれているかどうかをチェックするようになりました。 もしこの文字列が含まれていれば、それはユーザーがSWIGバージョン2.0.9よりも古いものを使用していることを意味するため、"must have SWIG version >= 2.0.9\n"
というエラーメッセージを生成し、ユーザーにSWIGのアップデートを促します。
これらの変更により、GoのビルドツールはSWIGの新しい要件に準拠し、異なるアーキテクチャ上でのGoとC/C++の相互運用性をより堅牢にしています。
コアとなるコードの変更箇所
変更の中心は src/cmd/go/build.go
ファイルです。
src/cmd/go/build.go
の変更点
-
build
メソッド内のbuildToolchain.gc
呼び出しの変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -814,11 +814,17 @@ func (b *builder) build(a *action) (err error) { // Compile Go. if len(gofiles) > 0 { - out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles) + ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles) + if len(out) > 0 { + b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) + if err != nil { + return errPrintedOutput + } + } if err != nil { return err } - objects = append(objects, out) + objects = append(objects, ofile) }
buildToolchain.gc
の戻り値がofile
とout
に増え、out
(標準出力) が存在する場合にprocessOutput
を通して表示されるようになりました。 -
run
メソッド内の出力処理の変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1185,22 +1191,10 @@ var cgoLine = regexp.MustCompile(`\\[[^\\[\\]]+\\.cgo1\\.go:[0-9]+\\]`)\n func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {\n out, err := b.runOut(dir, desc, cmdargs...)\n if len(out) > 0 {\n- if out[len(out)-1] != '\\n' {\n- out = append(out, '\\n')\n- }\n if desc == "" {\n desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))\n }\n- out := string(out)\n- // Fix up output referring to cgo-generated code to be more readable.\n- // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.\n- // Replace _Ctype_foo with C.foo.\n- // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.\n- if !buildX && cgoLine.MatchString(out) {\n- out = cgoLine.ReplaceAllString(out, "")\n- out = strings.Replace(out, "type _Ctype_", "type C.", -1)\n- }\n- b.showOutput(dir, desc, out)\n+ b.showOutput(dir, desc, b.processOutput(out))\n if err != nil {\n err = errPrintedOutput\n }\n ``` `run` メソッドから出力整形ロジックが削除され、`processOutput` 関数に委譲されました。
-
processOutput
関数の追加:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1208,6 +1202,23 @@ func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {\n return err\n }\n \n+// processOutput prepares the output of runOut to be output to the console.\n+func (b *builder) processOutput(out []byte) string {\n+ if out[len(out)-1] != '\\n' {\n+ out = append(out, '\\n')\n+ }\n+ messages := string(out)\n+ // Fix up output referring to cgo-generated code to be more readable.\n+ // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.\n+ // Replace _Ctype_foo with C.foo.\n+ // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.\n+ if !buildX && cgoLine.MatchString(messages) {\n+ messages = cgoLine.ReplaceAllString(messages, "")\n+ messages = strings.Replace(messages, "type _Ctype_", "type C.", -1)\n+ }\n+ return messages\n+}\n+\n // runOut runs the command given by cmdline in the directory dir.\n // It returns the command output and any errors that occurred.\n func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byte, error) {\
コマンドの出力を整形するための新しい関数が追加されました。
-
toolchain
インターフェースのgc
メソッドのシグネチャ変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1325,7 +1336,7 @@ type toolchain interface {\n // gc runs the compiler in a specific directory on a set of files\n // and returns the name of the generated output file.\n // The compiler runs in the directory dir.\n- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)\n+ gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)\
gc
メソッドがout []byte
も返すようになりました。 -
noToolchain
およびgcToolchain
のgc
メソッドの実装変更:noToolchain
とgcToolchain
のgc
メソッドが、新しいシグネチャに合わせてout []byte
を返すように変更されました。 -
swig
メソッド内のswigIntSize
呼び出し:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1897,8 +1912,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n \n // Run SWIG on all SWIG input files.\n func (b *builder) swig(p *Package, obj string, gccfiles []string) (outGo, outObj []string, err error) {\n +\n +\tintgosize, err := b.swigIntSize(obj)\n +\tif err != nil {\n +\t\treturn nil, nil, err\n +\t}\n +\n for _, f := range p.SwigFiles {\n - goFile, objFile, err := b.swigOne(p, f, obj, false)\n + goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize)\
swig
関数内でswigIntSize
を呼び出し、その結果をswigOne
に渡すようになりました。 -
swigIntSize
関数の追加:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1924,8 +1945,31 @@ func (b *builder) swig(p *Package, obj string, gccfiles []string) (outGo, outObj\n return outGo, outObj, nil\n }\n \n +// This code fails to build if sizeof(int) <= 32\n +const swigIntSizeCode = `\n +package main\n +const i int = 1 << 32\n +`\n +\n +// Determine the size of int on the target system for the -intgosize option\n +// of swig >= 2.0.9\n +func (b *builder) swigIntSize(obj string) (intsize string, err error) {\n +\tsrc := filepath.Join(b.work, "swig_intsize.go")\n +\tif err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0644); err != nil {\n +\t\treturn\n +\t}\n +\tsrcs := []string{src}\n +\n +\tp := goFilesPackage(srcs)\n +\n +\tif _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil {\n +\t\treturn "32", nil\n +\t}\n +\treturn "64", nil\n +}\n +\n // Run SWIG on one SWIG input file.\n -func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj string, err error) {\
Goの
int
サイズを判定するための新しい関数が追加されました。 -
swigOne
メソッドへの-intgosize
フラグの追加とエラーハンドリングの改善:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1945,6 +1989,7 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj\n // swig\n args := []string{\n "-go",\n + "-intgosize", intgosize,\n "-module", base,\n "-soname", soname,\n "-o", obj + gccBase + gccExt,\
SWIGコマンドに
-intgosize
フラグが追加されました。--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1957,7 +2002,14 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj\n args = append(args, "-c++")\n }\n \n - if err := b.run(p.Dir, p.ImportPath, "swig", args, file); err != nil {\n + if out, err := b.runOut(p.Dir, p.ImportPath, "swig", args, file); err != nil {\n + if len(out) > 0 {\n + if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {\n + return "", "", errors.New("must have SWIG version >= 2.0.9\\n")\n + }\n + b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))\n + return "", "", errPrintedOutput\n + }\n return "", "", err\n }\
SWIGの出力に "Unrecognized option -intgosize" が含まれる場合のエラーハンドリングが追加されました。
コアとなるコードの解説
このコミットの核心は、GoのビルドプロセスがSWIGと連携する際に、Goの int
型のサイズを正確にSWIGに伝えるメカニズムを導入した点にあります。
-
swigIntSize
関数によるint
サイズの動的判定: この関数は、Goのint
が32ビットか64ビットかをビルド時に自動的に判定します。これは、const i int = 1 << 32
というコードを含む一時的なGoファイルをコンパイルすることで実現されます。もしint
が32ビットであれば1 << 32
はオーバーフローするためコンパイルエラーとなり、64ビットであれば成功します。この結果に基づいて、SWIGに渡すべき-intgosize
の値("32" または "64")が決定されます。この動的な判定は、異なるアーキテクチャでGoコードをビルドする際の移植性を高めます。 -
swigOne
関数での-intgosize
フラグの追加:swigOne
関数は、個々のSWIG入力ファイルを処理し、SWIGコマンドを実行します。この関数にintgosize
引数が追加され、SWIGコマンドの引数リストに"-intgosize", intgosize
が追加されるようになりました。これにより、SWIGはGoのint
型の正確なサイズを知ることができ、GoとC/C++間の型変換を正しく行えるようになります。 -
SWIGのバージョンチェックとユーザーへの警告:
swigOne
関数内でSWIGの実行結果をチェックし、もしSWIGが-intgosize
オプションを認識しないというエラーメッセージ("Unrecognized option -intgosize"
)を出力した場合、Goのビルドツールはユーザーに対して「SWIGバージョン2.0.9以上が必要です」という明確なエラーメッセージを表示します。これは、ユーザーが古いSWIGバージョンを使用している場合に、問題の原因を特定し、解決策を提示するための重要なユーザーフレンドリーな改善です。 -
出力処理の共通化 (
processOutput
):processOutput
関数の導入は、コードの重複を減らし、GoコンパイラやSWIGなどの外部ツールの出力メッセージを整形するロジックを一元化することで、保守性を向上させています。特にCgoが生成する一時ファイルに関するパスを整形する機能は、ユーザーにとってより読みやすいエラーメッセージを提供するために重要です。
これらの変更は、Goのビルドシステムが外部ツール(SWIG)の進化に追従し、GoとC/C++の相互運用性をより堅牢かつユーザーフレンドリーにするための重要なステップです。
関連リンク
- Go Issue #4756: https://code.google.com/p/go/issues/detail?id=4756 (元のGoogle CodeのIssueトラッカー。現在はGitHubに移行済み)
- Go CL 7331048: https://golang.org/cl/7331048 (Gerrit Code Reviewへのリンク)
参考にした情報源リンク
- SWIG 公式サイト: http://www.swig.org/
- Go言語の
int
型に関するドキュメント (Go言語の公式ドキュメントや仕様を参照) - Cgoに関するGo言語のドキュメント (Go言語の公式ドキュメントを参照)
- SWIGの変更履歴やリリースノート (特に2.0.9に関する情報)
[インデックス 15550] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go
において、SWIG (Simplified Wrapper and Interface Generator) のバージョン 2.0.9 以降で必要となる -intgosize
フラグを渡すように変更を加えるものです。これにより、Goの int
型のサイズをSWIGに正確に伝え、C/C++コードとの連携における潜在的な問題を解決します。
コミット
commit 7c793826d44a6abb76f7846c51503f574eafe9e4
Author: Carlos Castillo <cookieo9@gmail.com>
Date: Fri Mar 1 16:48:21 2013 -0800
cmd/go: pass -intgosize to SWIG
swig >= 2.0.9 requires the size of int values to be passed via a command line flag. Should swig complain about the -intgosize not being supported, then alert the user to their outdated version of swig.
Fixes #4756.
R=golang-dev, minux.ma, iant
CC=golang-dev
https://golang.org/cl/7331048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7c793826d44a6abb76f7846c51503f574eafe9e4
元コミット内容
cmd/go: pass -intgosize to SWIG
SWIG バージョン 2.0.9 以降では、int
型のサイズをコマンドラインフラグで渡す必要があります。もしSWIGが -intgosize
をサポートしていないと文句を言ってきた場合、ユーザーにSWIGのバージョンが古いことを警告するべきです。
Go Issue #4756 を修正します。
変更の背景
この変更の背景には、Go言語とC/C++言語の相互運用性を提供するツールであるSWIGの進化があります。SWIGは、異なるプログラミング言語間でC/C++ライブラリを簡単に利用できるようにするためのラッパーコードを生成します。
Go言語の int
型は、実行環境のアーキテクチャ(32ビットまたは64ビット)によってサイズが異なります。例えば、32ビットシステムでは int
は32ビット(4バイト)ですが、64ビットシステムでは64ビット(8バイト)になることがあります。
SWIGのバージョン2.0.9以降では、このGoの int
型の可変サイズに対応するため、明示的に int
のサイズをコマンドライン引数 -intgosize
で指定するようになりました。これにより、SWIGが生成するラッパーコードが、Goの int
型とC/C++の int
型の間のサイズ不一致による問題を回避できるようになります。
このコミットは、GoのビルドツールがSWIGを呼び出す際に、Goの int
型の実際のサイズを検出し、その情報を -intgosize
フラグとしてSWIGに渡すようにすることで、この新しい要件に対応しています。もし古いバージョンのSWIGが使用されており、このフラグを認識しない場合は、適切なエラーメッセージをユーザーに表示し、SWIGのアップデートを促すように設計されています。
具体的には、Go Issue #4756 で報告された問題(SWIG 2.0.9以降でビルドが失敗する問題)を修正するためにこの変更が導入されました。
前提知識の解説
SWIG (Simplified Wrapper and Interface Generator)
SWIGは、C/C++/Objective-Cのコードを、Python, Perl, Ruby, Java, C#, Go, PHP, JavaScript, R, Lua, Octave, Scilab, Scheme, Tcl, Common Lisp, OCaml, Modula-3, Allegro CL, CLISP, Eiffel, Erlang, Guile, MzScheme, Pike, S-Lang, Smalltalk, V8 JavaScript, WxPython, XMLなど、様々なスクリプト言語や他のプログラミング言語から利用できるようにするためのオープンソースツールです。
SWIGは、C/C++のヘッダーファイルやインターフェース定義ファイル(.i
ファイル)を読み込み、ターゲット言語(この場合はGo)からC/C++関数を呼び出したり、C/C++クラスのオブジェクトを操作したりするための「ラッパーコード」を自動生成します。これにより、開発者は手動で複雑なFII (Foreign Function Interface) コードを書く手間を省き、異なる言語間の連携を容易にすることができます。
Go言語の int
型
Go言語の int
型は、プラットフォームに依存する整数型です。これは、実行されているCPUアーキテクチャのワードサイズ(通常は32ビットまたは64ビット)に合わせてサイズが決定されます。
- 32ビットシステム:
int
は32ビット(4バイト) - 64ビットシステム:
int
は64ビット(8バイト)
この特性は、Goプログラムが異なるアーキテクチャでコンパイル・実行される際に、int
のサイズが自動的に最適化されるという利点がありますが、C/C++のような固定サイズの整数型(例: int
は通常32ビット)と連携する際には、サイズ不一致による問題を引き起こす可能性があります。
Cgo
Cgoは、GoプログラムからCコードを呼び出すためのGoの機能です。Cgoを使用すると、Goのソースファイル内にCのコードを直接記述したり、既存のCライブラリをGoからリンクして利用したりできます。SWIGは、GoとC/C++の連携において、Cgoのメカニズムを利用してラッパーコードを生成します。
Goのビルドプロセス (cmd/go
)
cmd/go
は、Go言語の公式ビルドツールであり、Goプログラムのコンパイル、リンク、テスト、依存関係の管理など、様々なタスクを実行します。Goのソースコードをビルドする際、もしCgoやSWIGが関与するパッケージがある場合、cmd/go
はこれらのツールを適切に呼び出し、生成されたC/C++コードやラッパーコードをGoのビルドプロセスに統合します。
技術的詳細
このコミットは、src/cmd/go/build.go
ファイルに以下の主要な変更を加えています。
-
processOutput
関数の導入: 以前はrun
関数内で直接行われていた、コマンド実行結果の出力処理(末尾の改行追加、Cgo関連のエラーメッセージの整形)がprocessOutput
という新しいヘルパー関数に切り出されました。これにより、コードの再利用性と可読性が向上しています。 -
toolchain.gc
メソッドの変更:toolchain
インターフェースのgc
(Goコンパイラ) メソッドのシグネチャが変更されました。以前は(ofile string, err error)
を返していましたが、変更後は(ofile string, out []byte, err error)
を返すようになりました。これにより、Goコンパイラの標準出力(out []byte
)も呼び出し元に返されるようになり、コンパイラからの警告やエラーメッセージをより詳細に処理できるようになります。 -
swigIntSize
関数の導入: Goのint
型のサイズ(32ビットまたは64ビット)を動的に判定するためのswigIntSize
関数が追加されました。 この関数は、swig_intsize.go
という一時的なGoソースファイルを生成します。このファイルには、const i int = 1 << 32
という定数宣言が含まれています。 この一時ファイルをGoコンパイラ (buildToolchain.gc
) でコンパイルを試みます。- もしコンパイルが成功した場合、それは
int
が64ビットであることを意味します(1 << 32
がint
に収まるため)。この場合、"64"
を返します。 - もしコンパイルが失敗した場合(例:
constant 4294967296 overflows int
のようなエラー)、それはint
が32ビットであることを意味します(1 << 32
がint
に収まらないため)。この巧妙な方法で、実行環境のint
サイズをビルド時に判定しています。
- もしコンパイルが成功した場合、それは
-
swigOne
関数への-intgosize
フラグの追加: SWIGの単一の入力ファイルを処理するswigOne
関数が変更され、intgosize
引数が追加されました。 SWIGコマンドを実行する際に、"-intgosize", intgosize
という引数が追加されるようになりました。これにより、Goのint
型のサイズがSWIGに正確に伝えられます。 -
SWIGのエラーハンドリングの改善:
swigOne
関数内でSWIGの実行結果をチェックする際に、SWIGの出力に"Unrecognized option -intgosize"
という文字列が含まれているかどうかをチェックするようになりました。 もしこの文字列が含まれていれば、それはユーザーがSWIGバージョン2.0.9よりも古いものを使用していることを意味するため、"must have SWIG version >= 2.0.9\n"
というエラーメッセージを生成し、ユーザーにSWIGのアップデートを促します。
これらの変更により、GoのビルドツールはSWIGの新しい要件に準拠し、異なるアーキテクチャ上でのGoとC/C++の相互運用性をより堅牢にしています。
コアとなるコードの変更箇所
変更の中心は src/cmd/go/build.go
ファイルです。
src/cmd/go/build.go
の変更点
-
build
メソッド内のbuildToolchain.gc
呼び出しの変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -814,11 +814,17 @@ func (b *builder) build(a *action) (err error) { // Compile Go. if len(gofiles) > 0 { - out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles) + ofile, out, err := buildToolchain.gc(b, a.p, obj, inc, gofiles) + if len(out) > 0 { + b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) + if err != nil { + return errPrintedOutput + } + } if err != nil { return err } - objects = append(objects, out) + objects = append(objects, ofile) }
buildToolchain.gc
の戻り値がofile
とout
に増え、out
(標準出力) が存在する場合にprocessOutput
を通して表示されるようになりました。 -
run
メソッド内の出力処理の変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1185,22 +1191,10 @@ var cgoLine = regexp.MustCompile(`\\[[^\\[\\]]+\\.cgo1\\.go:[0-9]+\\]`)\n func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {\n out, err := b.runOut(dir, desc, cmdargs...)\n if len(out) > 0 {\n- if out[len(out)-1] != '\\n' {\n- out = append(out, '\\n')\n- }\n if desc == "" {\n desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))\n }\n- out := string(out)\n- // Fix up output referring to cgo-generated code to be more readable.\n- // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.\n- // Replace _Ctype_foo with C.foo.\n- // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.\n- if !buildX && cgoLine.MatchString(out) {\n- out = cgoLine.ReplaceAllString(out, "")\n- out = strings.Replace(out, "type _Ctype_", "type C.", -1)\n- }\n- b.showOutput(dir, desc, out)\n+ b.showOutput(dir, desc, b.processOutput(out))\n if err != nil {\n err = errPrintedOutput\n }\n ``` `run` メソッドから出力整形ロジックが削除され、`processOutput` 関数に委譲されました。
-
processOutput
関数の追加:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1208,6 +1202,23 @@ func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {\n return err\n }\n \n+// processOutput prepares the output of runOut to be output to the console.\n+func (b *builder) processOutput(out []byte) string {\n+ if out[len(out)-1] != '\\n' {\n+ out = append(out, '\\n')\n+ }\n+ messages := string(out)\n+ // Fix up output referring to cgo-generated code to be more readable.\n+ // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19.\n+ // Replace _Ctype_foo with C.foo.\n+ // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.\n+ if !buildX && cgoLine.MatchString(messages) {\n+ messages = cgoLine.ReplaceAllString(messages, "")\n+ messages = strings.Replace(messages, "type _Ctype_", "type C.", -1)\n+ }\n+ return messages\n+}\n+\n // runOut runs the command given by cmdline in the directory dir.\n // It returns the command output and any errors that occurred.\n func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byte, error) {\
コマンドの出力を整形するための新しい関数が追加されました。
-
toolchain
インターフェースのgc
メソッドのシグネチャ変更:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1325,7 +1336,7 @@ type toolchain interface {\n // gc runs the compiler in a specific directory on a set of files\n // and returns the name of the generated output file.\n // The compiler runs in the directory dir.\n- gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)\n+ gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)\
gc
メソッドがout []byte
も返すようになりました。 -
noToolchain
およびgcToolchain
のgc
メソッドの実装変更:noToolchain
とgcToolchain
のgc
メソッドが、新しいシグネチャに合わせてout []byte
を返すように変更されました。 -
swig
メソッド内のswigIntSize
呼び出し:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1897,8 +1912,14 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n \n // Run SWIG on all SWIG input files.\n func (b *builder) swig(p *Package, obj string, gccfiles []string) (outGo, outObj []string, err error) {\n +\n +\tintgosize, err := b.swigIntSize(obj)\n +\tif err != nil {\n +\t\treturn nil, nil, err\n +\t}\n +\n for _, f := range p.SwigFiles {\n - goFile, objFile, err := b.swigOne(p, f, obj, false)\n + goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize)\
swig
関数内でswigIntSize
を呼び出し、その結果をswigOne
に渡すようになりました。 -
swigIntSize
関数の追加:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1924,8 +1945,31 @@ func (b *builder) swig(p *Package, obj string, gccfiles []string) (outGo, outObj\n return outGo, outObj, nil\n }\n \n +// This code fails to build if sizeof(int) <= 32\n +const swigIntSizeCode = `\n +package main\n +const i int = 1 << 32\n +`\n +\n +// Determine the size of int on the target system for the -intgosize option\n +// of swig >= 2.0.9\n +func (b *builder) swigIntSize(obj string) (intsize string, err error) {\n +\tsrc := filepath.Join(b.work, "swig_intsize.go")\n +\tif err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0644); err != nil {\n +\t\treturn\n +\t}\n +\tsrcs := []string{src}\n +\n +\tp := goFilesPackage(srcs)\n +\n +\tif _, _, e := buildToolchain.gc(b, p, obj, nil, srcs); e != nil {\n +\t\treturn "32", nil\n +\t}\n +\treturn "64", nil\n +}\n +\n // Run SWIG on one SWIG input file.\n -func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj string, err error) {\
Goの
int
サイズを判定するための新しい関数が追加されました。 -
swigOne
メソッドへの-intgosize
フラグの追加とエラーハンドリングの改善:--- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -1945,6 +1989,7 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj\n // swig\n args := []string{\n "-go",\n + "-intgosize", intgosize,\n "-module", base,\n "-soname", soname,\n "-o", obj + gccBase + gccExt,\
SWIGコマンドに
-intgosize
フラグが追加されました。--- a/src/cmd/go/build.go +++ b/cmd/go/build.go @@ -1957,7 +2002,14 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool) (outGo, outObj\n args = append(args, "-c++")\n }\n \n - if err := b.run(p.Dir, p.ImportPath, "swig", args, file); err != nil {\n + if out, err := b.runOut(p.Dir, p.ImportPath, "swig", args, file); err != nil {\n + if len(out) > 0 {\n + if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {\n + return "", "", errors.New("must have SWIG version >= 2.0.9\\n")\n + }\n + b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))\n + return "", "", errPrintedOutput\n + }\n return "", "", err\n }\
SWIGの出力に "Unrecognized option -intgosize" が含まれる場合のエラーハンドリングが追加されました。
コアとなるコードの解説
このコミットの核心は、GoのビルドプロセスがSWIGと連携する際に、Goの int
型のサイズを正確にSWIGに伝えるメカニズムを導入した点にあります。
-
swigIntSize
関数によるint
サイズの動的判定: この関数は、Goのint
が32ビットか64ビットかをビルド時に自動的に判定します。これは、const i int = 1 << 32
というコードを含む一時的なGoファイルをコンパイルすることで実現されます。もしint
が32ビットであれば1 << 32
はオーバーフローするためコンパイルエラーとなり、64ビットであれば成功します。この結果に基づいて、SWIGに渡すべき-intgosize
の値("32" または "64")が決定されます。この動的な判定は、異なるアーキテクチャでGoコードをビルドする際の移植性を高めます。 -
swigOne
関数での-intgosize
フラグの追加:swigOne
関数は、個々のSWIG入力ファイルを処理し、SWIGコマンドを実行します。この関数にintgosize
引数が追加され、SWIGコマンドの引数リストに"-intgosize", intgosize
が追加されるようになりました。これにより、SWIGはGoのint
型の正確なサイズを知ることができ、GoとC/C++間の型変換を正しく行えるようになります。 -
SWIGのバージョンチェックとユーザーへの警告:
swigOne
関数内でSWIGの実行結果をチェックし、もしSWIGが-intgosize
オプションを認識しないというエラーメッセージ("Unrecognized option -intgosize"
)を出力した場合、Goのビルドツールはユーザーに対して「SWIGバージョン2.0.9以上が必要です」という明確なエラーメッセージを表示します。これは、ユーザーが古いSWIGバージョンを使用している場合に、問題の原因を特定し、解決策を提示するための重要なユーザーフレンドリーな改善です。 -
出力処理の共通化 (
processOutput
):processOutput
関数の導入は、コードの重複を減らし、GoコンパイラやSWIGなどの外部ツールの出力メッセージを整形するロジックを一元化することで、保守性を向上させています。特にCgoが生成する一時ファイルに関するパスを整形する機能は、ユーザーにとってより読みやすいエラーメッセージを提供するために重要です。
これらの変更は、Goのビルドシステムが外部ツール(SWIG)の進化に追従し、GoとC/C++の相互運用性をより堅牢かつユーザーフレンドリーにするための重要なステップです。
関連リンク
- Go Issue #4756: https://code.google.com/p/go/issues/detail?id=4756 (元のGoogle CodeのIssueトラッカー。現在はGitHubに移行済み)
- Go CL 7331048: https://golang.org/cl/7331048 (Gerrit Code Reviewへのリンク)
参考にした情報源リンク
- SWIG 公式サイト: http://www.swig.org/
- SWIG Go Language Module Documentation: http://www.swig.org/Doc2.0/Go.html (特に
-intgosize
オプションに関する記述) - Go言語の
int
型に関するドキュメント (Go言語の公式ドキュメントや仕様を参照) - Cgoに関するGo言語のドキュメント (Go言語の公式ドキュメントを参照)
- SWIGの変更履歴やリリースノート (特に2.0.9に関する情報)