[インデックス 12533] ファイルの概要
このコミットは、Go言語のコマンドラインツール go
に env
サブコマンドを追加し、それを利用して misc/cgo/testso
のテストスクリプトを修正するものです。これにより、特に64ビットマシン上での32ビット(386)ビルドに関する問題が解決されます。
コミット
commit 2c46569f57fd575e2acceabdbd40a187e66cd71e
Author: Russ Cox <rsc@golang.org>
Date: Thu Mar 8 14:28:44 2012 -0500
cmd/go: add env command, use to fix misc/cgo/testso
Fixes 386 build on 64-bit machines.
R=golang-dev, bradfitz, minux.ma
CC=golang-dev
https://golang.org/cl/5785053
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2c46569f57fd575e2acceabdbd40a187e66cd71e
元コミット内容
このコミットの目的は以下の通りです。
go env
コマンドの追加: Go環境に関する情報を表示するための新しいコマンドを導入します。misc/cgo/testso
の修正:go env
コマンドを利用して、misc/cgo/testso/test.bash
スクリプトにおけるビルドプロセスを改善します。- 64ビットマシン上での32ビット(386)ビルドの問題解決: 上記の変更により、特定の環境(64ビットマシンでの32ビットターゲットビルド)で発生していたビルド問題を修正します。
変更の背景
このコミットの背景には、Go言語のビルドシステムが進化する中で、異なるアーキテクチャ間でのクロスコンパイルの複雑さが増していたことがあります。特に、64ビットシステム上で32ビット(x86、通称386)バイナリをビルドする際に、Cgo(GoとC言語の相互運用機能)が絡むと、GCCのフラグ設定が環境に依存し、問題が発生しやすかったと考えられます。
go env
コマンドの導入は、Goのビルド環境に関する標準的な情報をプログラム的に取得できるようにすることで、このような環境依存の問題を解決し、ビルドスクリプトのポータビリティを高めることを目的としています。GOGCCFLAGS
のようなビルドフラグは、Goツールチェーンが内部的に使用するGCCのコンパイルオプションを決定するために重要であり、これらを go env
経由で公開することで、ユーザーやスクリプトがGoのビルド設定にアクセスし、適切に利用できるようになります。
misc/cgo/testso/test.bash
は、Cgoと共有ライブラリ(.so
ファイル)の連携をテストするためのスクリプトであり、このテストが特定の環境で失敗していたことが、このコミットの直接的なトリガーとなったようです。go env GOGCCFLAGS
を使用することで、Goツールチェーンが推奨するGCCフラグを動的に取得し、ビルドコマンドに適用できるようになり、環境間の差異を吸収してビルドの信頼性を向上させます。
前提知識の解説
Go言語のビルドシステム
Go言語は、go build
コマンドを通じてソースコードをコンパイルし、実行可能なバイナリを生成します。このビルドシステムは、依存関係の解決、パッケージのコンパイル、リンクといった一連のプロセスを自動的に行います。Goはクロスコンパイルを強力にサポートしており、GOOS
(オペレーティングシステム)や GOARCH
(アーキテクチャ)といった環境変数を設定することで、異なるプラットフォーム向けのバイナリを簡単に生成できます。
Cgo
Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。Cgoを使用するGoソースファイルは、import "C"
という特殊なインポート宣言を含みます。Cgoは、GoコンパイラとCコンパイラ(通常はGCCやClang)の両方を連携させて動作するため、ビルドプロセスが複雑になることがあります。特に、CgoがC/C++のライブラリにリンクする場合、リンカフラグやインクルードパスの設定が重要になります。
GCCFLAGS (GOGCCFLAGS)
GCCFLAGS
は、GCC(GNU Compiler Collection)に渡されるコンパイルオプションやリンカオプションを指定するための一般的な用語です。Goのビルドシステムでは、Cgoを使用する際にGoツールチェーンが内部的にGCCを呼び出します。このとき、GoツールチェーンがGCCに渡す特定のフラグのセットが GOGCCFLAGS
に相当します。これらのフラグは、ターゲットアーキテクチャ、OS、Goのバージョンなどに応じて動的に決定されることがあり、Goのビルド環境の整合性を保つ上で重要です。
386ビルドと64ビットマシン
- 386: Intel 80386プロセッサに由来する名称で、一般的に32ビットのx86アーキテクチャを指します。
- 64ビットマシン: 64ビットのCPUアーキテクチャ(例: x86-64、AMD64、Intel 64)を持つコンピュータを指します。
64ビットマシン上で32ビットバイナリをビルドする(クロスコンパイルする)場合、Cコンパイラ(GCC)は32ビットのライブラリやヘッダファイルを使用するように適切に設定される必要があります。これには、特定のコンパイラフラグ(例: -m32
)や、32ビット版のシステムライブラリへのパス指定が必要になることがあります。このコミットが「Fixes 386 build on 64-bit machines」と述べているのは、まさにこのクロスコンパイル環境でのCgo関連のビルド問題を指しています。
技術的詳細
go env
コマンドの設計と実装
go env
コマンドは、Goのビルド環境に関する様々な情報を表示するために導入されました。これは、シェルスクリプトや他のツールがGoの環境設定をプログラム的に取得できるようにすることを目的としています。
- デフォルトの出力形式: 引数なしで
go env
を実行すると、環境変数の設定をシェルスクリプト形式(Windowsではバッチファイル形式)で出力します。これにより、ユーザーはeval $(go env)
のようにして、現在のシェルセッションにGoの環境変数を簡単に設定できます。 - 特定の変数の取得:
go env [var ...]
のように引数として変数名を指定すると、その変数の値のみを1行で出力します。これは、特定の環境変数(例:GOROOT
,GOPATH
,GOARCH
,GOOS
,GOGCCFLAGS
など)をスクリプト内で利用する際に非常に便利です。 GOGCCFLAGS
の動的生成:env.go
内のmkEnv
関数では、GOGCCFLAGS
の値がb.gccCmd(".")[3:]
という形で動的に生成されています。これは、Goツールチェーンが内部的にGCCを呼び出す際に使用するデフォルトのフラグを、現在のビルド環境に基づいて取得していることを示しています。これにより、Goのバージョンやターゲットアーキテクチャに応じて適切なGCCフラグが提供されます。
misc/cgo/testso/test.bash
の修正
元の test.bash
スクリプトでは、Cgoで共有ライブラリをビルドする際に gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
のようにGCCを直接呼び出していました。この方法では、Goツールチェーンが内部的に使用するGCCフラグ(特にクロスコンパイル時に重要なもの)が考慮されていませんでした。
修正後、この行は gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c
となっています。
$(go env GOGCCFLAGS)
: これはシェルコマンド置換であり、go env GOGCCFLAGS
コマンドの出力結果(Goツールチェーンが推奨するGCCフラグの文字列)が、gcc
コマンドの引数として展開されます。- これにより、Cgoの共有ライブラリビルド時に、Goツールチェーンが想定する適切なGCCフラグが自動的に適用されるようになり、特に64ビットマシン上での32ビットビルドのような複雑な環境での互換性が向上します。
src/cmd/go/doc.go
の変更
doc.go
は go
コマンドのヘルプドキュメントを生成するためのソースファイルです。
go env
コマンドの追加に伴い、The commands are:
セクションにenv print Go environment information
が追加されました。Print Go environment information
という新しいセクションが追加され、go env
コマンドの基本的な使い方と引数に関する説明が記述されました。go help packages
などで表示されるPackage
構造体(Goパッケージに関するメタデータ)に、以下の新しいフィールドが追加されました。これらのフィールドは、Goパッケージに関するより詳細なビルド関連情報を提供し、go list
コマンドなどで利用されることを想定しています。Target string // install path
Goroot bool // is this package in the Go root?
Standard bool // is this package part of the standard Go library?
Root string // Go root or Go path dir containing this package
SysoFiles []string // .syso object files to add to archive
CgoCFLAGS []string // cgo: flags for C compiler
CgoLDFLAGS []string // cgo: flags for linker
CgoPkgConfig []string // cgo: pkg-config names
TestGoFiles []string // _test.go files in package
TestImports []string // imports from TestGoFiles
XTestGoFiles []string // _test.go files outside package
XTestImports []string // imports from XTestGoFiles
これらの追加は、Goのビルドシステムがより多くの情報を公開し、ツールやスクリプトがGoパッケージのビルドに関する詳細な情報を取得できるようにするためのものです。特にCgoCFLAGS
,CgoLDFLAGS
,CgoPkgConfig
は、Cgoのビルドプロセスをより細かく制御・理解するために重要です。
コアとなるコードの変更箇所
misc/cgo/testso/test.bash
--- a/misc/cgo/testso/test.bash
+++ b/misc/cgo/testso/test.bash
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
set -e
-gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
+gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c
go build main.go
LD_LIBRARY_PATH=. ./main
rm -f libcgosotest.so main
src/cmd/go/doc.go
doc.go
の変更は多岐にわたりますが、主要な変更は go env
コマンドのドキュメント追加と、Package
構造体へのフィールド追加です。
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -14,6 +14,7 @@ The commands are:\n build compile packages and dependencies\n clean remove object files\n doc run godoc on package sources\n+ env print Go environment information\n fix run go tool fix on packages\n fmt run gofmt on package sources\n get download and install packages and dependencies\n@@ -76,6 +77,8 @@ The build flags are shared by the build, install, run, and test commands:\n \t-x\n \t\tprint the commands.\n \n+\t-compiler name\n+\t\tname of compiler to use, as in runtime.Compiler (gccgo or gc)\n \t-gccgoflags \'arg list\'\n \t\targuments to pass on each gccgo compiler/linker invocation\n \t-gcflags \'arg list\'\n@@ -153,6 +156,20 @@ To run godoc with specific options, run godoc itself.\n See also: go fix, go fmt, go vet.\n \n \n+Print Go environment information\n+\n+Usage:\n+\n+\tgo env [var ...]\n+\n+Env prints Go environment information.\n+\n+By default env prints information as a shell script\n+(on Windows, a batch file). If one or more variable\n+names is given as arguments, env prints the value of\n+each named variable on its own line.\n+\n+\n Run go tool fix on packages\n \n Usage:\n@@ -253,21 +270,28 @@ is equivalent to -f \'{{.ImportPath}}\'. The struct\n being passed to the template is:\n \n type Package struct {\n+ Dir string // directory containing package sources\n+ ImportPath string // import path of package in dir\n Name string // package name\n Doc string // package documentation string\n- ImportPath string // import path of package in dir\n- Dir string // directory containing package sources\n- Version string // version of installed package (TODO)\n+ Target string // install path\n+ Goroot bool // is this package in the Go root?\n+ Standard bool // is this package part of the standard Go library?\n Stale bool // would \'go install\' do anything for this package?\n+ Root string // Go root or Go path dir containing this package\n \n // Source files\n- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, and XTestGoFiles)\n- TestGoFiles []string // _test.go source files internal to the package they are testing\n- XTestGoFiles []string // _test.go source files external to the package they are testing\n- CFiles []string // .c source files\n- HFiles []string // .h source files\n- SFiles []string // .s source files\n- CgoFiles []string // .go sources files that import \"C\"\n+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)\n+ CgoFiles []string // .go sources files that import \"C\"\n+ CFiles []string // .c source files\n+ HFiles []string // .h source files\n+ SFiles []string // .s source files\n+ SysoFiles []string // .syso object files to add to archive\n+\n+ // Cgo directives\n+ CgoCFLAGS []string // cgo: flags for C compiler\n+ CgoLDFLAGS []string // cgo: flags for linker\n+ CgoPkgConfig []string // cgo: pkg-config names\n \n // Dependency information\n Imports []string // import paths used by this package\n@@ -275,8 +299,13 @@ being passed to the template is:\n \n // Error information\n Incomplete bool // this package or a dependency has an error\n- Error *PackageError // error loading package\n+ Error *PackageError // error loading package\n DepsErrors []*PackageError // errors loading dependencies\n+\n+ TestGoFiles []string // _test.go files in package\n+ TestImports []string // imports from TestGoFiles\n+ XTestGoFiles []string // _test.go files outside package\n+ XTestImports []string // imports from XTestGoFiles\n }\n \n The -json flag causes the package data to be printed in JSON format
src/cmd/go/env.go
(新規ファイル)
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"runtime"
"strings"
)
var cmdEnv = &Command{
Run: runEnv,
UsageLine: "env [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
`,
}
type envVar struct {
name, value string
}
func mkEnv() []envVar {
var b builder
b.init()
env := []envVar{
{"GOROOT", goroot},
{"GOBIN", gobin},
{"GOARCH", goarch},
{"GOCHAR", archChar},
{"GOOS", goos},
{"GOEXE", exeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOTOOLDIR", toolDir},
{"GOGCCFLAGS", strings.Join(b.gccCmd(".")[3:], " ")},
}
return env
}
func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.name == name {
return e.value
}
}
return ""
}
func runEnv(cmd *Command, args []string) {
env := mkEnv()
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
return
}
switch runtime.GOOS {
default:
for _, e := range env {
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
}
case "plan9":
for _, e := range env {
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
}
case "windows":
for _, e := range env {
fmt.Printf("set %s=%s\n", e.name, e.value)
}
}
}
src/cmd/go/main.go
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -76,6 +76,7 @@ var commands = []*Command{\n cmdBuild,\n cmdClean,\n cmdDoc,\n+\tcmdEnv,\n cmdFix,\n cmdFmt,\n cmdGet,\n```
## コアとなるコードの解説
### `src/cmd/go/env.go`
このファイルは、`go env` コマンドのロジックを実装しています。
- **`cmdEnv`**: `go` コマンドのサブコマンドとして `env` を登録するための `Command` 構造体のインスタンスです。`UsageLine`、`Short`、`Long` フィールドでコマンドの利用方法と説明が定義されています。
- **`envVar` 構造体**: 環境変数の名前と値を保持するためのシンプルな構造体です。
- **`mkEnv()` 関数**:
- この関数は、Goのビルド環境に関する主要な環境変数とその値のリストを `[]envVar` のスライスとして生成します。
- `GOROOT`, `GOBIN`, `GOARCH`, `GOOS` など、Goのビルドに不可欠な変数が含まれています。
- 特筆すべきは `GOGCCFLAGS` の生成です。`b.gccCmd(".")[3:]` は、Goツールチェーンが内部的にGCCを呼び出す際に使用するデフォルトのフラグを取得するためのロジックです。`builder` 型の `gccCmd` メソッドは、GoのビルドシステムがGCCを呼び出す際のコマンドライン引数を生成し、その中からGCCフラグの部分を抽出しています。これにより、Goツールチェーンが推奨するGCCフラグが動的に取得され、`GOGCCFLAGS` として提供されます。
- **`findEnv()` 関数**: `mkEnv()` で生成された `envVar` のスライスから、指定された名前の環境変数の値を探して返します。
- **`runEnv()` 関数**:
- `go env` コマンドが実行された際のエントリポイントとなる関数です。
- `mkEnv()` を呼び出して環境変数のリストを取得します。
- `len(args) > 0` の場合(つまり、`go env GOROOT` のように引数が指定された場合)、引数として渡された各環境変数の値を1行ずつ出力します。
- 引数がない場合(デフォルトの動作)、現在のOSに応じて異なる形式で環境変数をシェルスクリプト形式で出力します。
- Unix-likeシステム(デフォルト): `VAR="value"` 形式。
- Plan 9: `VAR='value'` 形式(シングルクォートのエスケープ処理を含む)。
- Windows: `set VAR=value` 形式。
- このOSごとの出力形式の切り替えにより、`go env` の出力が各プラットフォームのシェルで直接実行可能な形式となるように配慮されています。
### `misc/cgo/testso/test.bash`
- このシェルスクリプトの変更は非常にシンプルですが、その影響は大きいです。
- `gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c` から `gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c` への変更は、Cgoで共有ライブラリをビルドする際に、Goツールチェーンが提供する `GOGCCFLAGS` を利用するようにしたものです。
- これにより、Goのビルドシステムが内部的に使用するGCCのコンパイルオプション(例えば、特定のアーキテクチャ向けのクロスコンパイルフラグなど)が、Cgoのビルドプロセスにも適用されるようになり、ビルドの互換性と信頼性が向上します。特に、64ビットシステム上で32ビットバイナリをビルドする際に必要となるGCCフラグが自動的に含まれることで、以前の問題が解決されます。
### `src/cmd/go/doc.go` と `src/cmd/go/main.go`
- `src/cmd/go/doc.go` への変更は、主に新しい `go env` コマンドのドキュメントを追加し、`go list` コマンドなどで利用される `Package` 構造体に、より詳細なビルド関連情報(特にCgo関連のフラグやテストファイルの情報)を追加するものです。これにより、Goのツールエコシステムがよりリッチな情報を利用できるようになります。
- `src/cmd/go/main.go` への変更は、`cmdEnv` 変数を `commands` スライスに追加することで、`go` コマンドが `env` サブコマンドを認識し、実行できるようにするためのものです。これは新しいコマンドを追加する際の標準的な手順です。
これらの変更は、Goのビルドシステムがより堅牢で、クロスプラットフォーム対応が強化され、かつユーザーやツールがビルド環境に関する詳細な情報にアクセスできるようになるための重要なステップを示しています。
## 関連リンク
- Go言語公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
- Go Modules (Go 1.11以降の依存関係管理): [https://go.dev/blog/using-go-modules](https://go.dev/blog/using-go-modules) (このコミット時点ではGo Modulesは存在しませんが、Goのビルドシステム全体の理解に役立ちます)
- Cgoのドキュメント: [https://go.dev/blog/c-go-is-not-go](https://go.dev/blog/c-go-is-not-go) (Cgoの基本的な概念と注意点)
## 参考にした情報源リンク
- Goのソースコード (GitHub): [https://github.com/golang/go](https://github.com/golang/go)
- Go Code Review (Gerrit): [https://go.dev/cl/5785053](https://go.dev/cl/5785053) (このコミットの元のコードレビューページ)
- GCC (GNU Compiler Collection) ドキュメント: [https://gcc.gnu.org/onlinedocs/](https://gcc.gnu.org/onlinedocs/)
- x86アーキテクチャに関する情報 (Wikipediaなど)
- クロスコンパイルに関する一般的な情報 (各種技術ブログ、ドキュメント)
- Goの環境変数に関する情報 (Go公式ドキュメントの `go env` コマンドの説明など)
# [インデックス 12533] ファイルの概要
このコミットは、Go言語のコマンドラインツール `go` に `env` サブコマンドを追加し、それを利用して `misc/cgo/testso` のテストスクリプトを修正するものです。これにより、特に64ビットマシン上での32ビット(386)ビルドに関する問題が解決されます。
## コミット
commit 2c46569f57fd575e2acceabdbd40a187e66cd71e Author: Russ Cox rsc@golang.org Date: Thu Mar 8 14:28:44 2012 -0500
cmd/go: add env command, use to fix misc/cgo/testso
Fixes 386 build on 64-bit machines.
R=golang-dev, bradfitz, minux.ma
CC=golang-dev
https://golang.org/cl/5785053
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/2c46569f57fd575e2acceabdbd40a187e66cd71e](https://github.com/golang/go/commit/2c46569f57fd575e2acceabdbd40a187e66cd71e)
## 元コミット内容
このコミットの目的は以下の通りです。
1. `go env` コマンドの追加: Go環境に関する情報を表示するための新しいコマンドを導入します。
2. `misc/cgo/testso` の修正: `go env` コマンドを利用して、`misc/cgo/testso/test.bash` スクリプトにおけるビルドプロセスを改善します。
3. 64ビットマシン上での32ビット(386)ビルドの問題解決: 上記の変更により、特定の環境(64ビットマシンでの32ビットターゲットビルド)で発生していたビルド問題を修正します。
## 変更の背景
このコミットの背景には、Go言語のビルドシステムが進化する中で、異なるアーキテクチャ間でのクロスコンパイルの複雑さが増していたことがあります。特に、64ビットシステム上で32ビット(x86、通称386)バイナリをビルドする際に、Cgo(GoとC言語の相互運用機能)が絡むと、GCCのフラグ設定が環境に依存し、問題が発生しやすかったと考えられます。
`go env` コマンドの導入は、Goのビルド環境に関する標準的な情報をプログラム的に取得できるようにすることで、このような環境依存の問題を解決し、ビルドスクリプトのポータビリティを高めることを目的としています。`GOGCCFLAGS` のようなビルドフラグは、Goツールチェーンが内部的に使用するGCCのコンパイルオプションを決定するために重要であり、これらを `go env` 経由で公開することで、ユーザーやスクリプトがGoのビルド設定にアクセスし、適切に利用できるようになります。
`misc/cgo/testso/test.bash` は、Cgoと共有ライブラリ(`.so` ファイル)の連携をテストするためのスクリプトであり、このテストが特定の環境で失敗していたことが、このコミットの直接的なトリガーとなったようです。`go env GOGCCFLAGS` を使用することで、Goツールチェーンが推奨するGCCフラグを動的に取得し、ビルドコマンドに適用できるようになり、環境間の差異を吸収してビルドの信頼性を向上させます。
## 前提知識の解説
### Go言語のビルドシステム
Go言語は、`go build` コマンドを通じてソースコードをコンパイルし、実行可能なバイナリを生成します。このビルドシステムは、依存関係の解決、パッケージのコンパイル、リンクといった一連のプロセスを自動的に行います。Goはクロスコンパイルを強力にサポートしており、`GOOS`(オペレーティングシステム)や `GOARCH`(アーキテクチャ)といった環境変数を設定することで、異なるプラットフォーム向けのバイナリを簡単に生成できます。
### Cgo
Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。Cgoを使用するGoソースファイルは、`import "C"` という特殊なインポート宣言を含みます。Cgoは、GoコンパイラとCコンパイラ(通常はGCCやClang)の両方を連携させて動作するため、ビルドプロセスが複雑になることがあります。特に、CgoがC/C++のライブラリにリンクする場合、リンカフラグやインクルードパスの設定が重要になります。
### GCCFLAGS (GOGCCFLAGS)
`GCCFLAGS` は、GCC(GNU Compiler Collection)に渡されるコンパイルオプションやリンカオプションを指定するための一般的な用語です。Goのビルドシステムでは、Cgoを使用する際にGoツールチェーンが内部的にGCCを呼び出します。このとき、GoツールチェーンがGCCに渡す特定のフラグのセットが `GOGCCFLAGS` に相当します。これらのフラグは、ターゲットアーキテクチャ、OS、Goのバージョンなどに応じて動的に決定されることがあり、Goのビルド環境の整合性を保つ上で重要です。`GOGCCFLAGS` は、Goがcgoを使用するプログラムをビルドする際に、Cコンパイラ (`CC`) に渡される引数のスペース区切りリストを保持する環境変数です。これは主に情報提供を目的としており、ユーザーが直接変更してGoのビルドプロセスに影響を与えることは通常できません。Goツールチェーン自体がCコンパイラを呼び出す際に使用するフラグを反映しています。`go env` コマンドでその値を確認できます。例えば、`-fPIC` (Position-Independent Code) や `-pthread` (pthreadsサポート) のようなフラグが含まれることがあります。
### 386ビルドと64ビットマシン
- **386**: Intel 80386プロセッサに由来する名称で、一般的に32ビットのx86アーキテクチャを指します。
- **64ビットマシン**: 64ビットのCPUアーキテクチャ(例: x86-64、AMD64、Intel 64)を持つコンピュータを指します。
64ビットマシン上で32ビットバイナリをビルドする(クロスコンパイルする)場合、Cコンパイラ(GCC)は32ビットのライブラリやヘッダファイルを使用するように適切に設定される必要があります。これには、特定のコンパイラフラグ(例: `-m32`)や、32ビット版のシステムライブラリへのパス指定が必要になることがあります。このコミットが「Fixes 386 build on 64-bit machines」と述べているのは、まさにこのクロスコンパイル環境でのCgo関連のビルド問題を指しています。
## 技術的詳細
### `go env` コマンドの設計と実装
`go env` コマンドは、Goのビルド環境に関する様々な情報を表示するために導入されました。これは、シェルスクリプトや他のツールがGoの環境設定をプログラム的に取得できるようにすることを目的としています。
- **デフォルトの出力形式**: 引数なしで `go env` を実行すると、環境変数の設定をシェルスクリプト形式(Windowsではバッチファイル形式)で出力します。これにより、ユーザーは `eval $(go env)` のようにして、現在のシェルセッションにGoの環境変数を簡単に設定できます。
- **特定の変数の取得**: `go env [var ...]` のように引数として変数名を指定すると、その変数の値のみを1行で出力します。これは、特定の環境変数(例: `GOROOT`, `GOPATH`, `GOARCH`, `GOOS`, `GOGCCFLAGS` など)をスクリプト内で利用する際に非常に便利です。
- **`GOGCCFLAGS` の動的生成**: `env.go` 内の `mkEnv` 関数では、`GOGCCFLAGS` の値が `b.gccCmd(".")[3:]` という形で動的に生成されています。これは、Goツールチェーンが内部的に使用するGCCのコンパイルオプションを、現在のビルド環境に基づいて取得していることを示しています。これにより、Goのバージョンやターゲットアーキテクチャに応じて適切なGCCフラグが提供されます。
### `misc/cgo/testso/test.bash` の修正
元の `test.bash` スクリプトでは、Cgoで共有ライブラリをビルドする際に `gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c` のようにGCCを直接呼び出していました。この方法では、Goツールチェーンが内部的に使用するGCCフラグ(特にクロスコンパイル時に重要なもの)が考慮されていませんでした。
修正後、この行は `gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c` となっています。
- `$(go env GOGCCFLAGS)`: これはシェルコマンド置換であり、`go env GOGCCFLAGS` コマンドの出力結果(Goツールチェーンが推奨するGCCフラグの文字列)が、`gcc` コマンドの引数として展開されます。
- これにより、Cgoの共有ライブラリビルド時に、Goツールチェーンが想定する適切なGCCフラグが自動的に適用されるようになり、特に64ビットマシン上での32ビットビルドのような複雑な環境での互換性が向上します。
### `src/cmd/go/doc.go` の変更
`doc.go` は `go` コマンドのヘルプドキュメントを生成するためのソースファイルです。
- `go env` コマンドの追加に伴い、`The commands are:` セクションに `env print Go environment information` が追加されました。
- `Print Go environment information` という新しいセクションが追加され、`go env` コマンドの基本的な使い方と引数に関する説明が記述されました。
- `go help packages` などで表示される `Package` 構造体(Goパッケージに関するメタデータ)に、以下の新しいフィールドが追加されました。これらのフィールドは、Goパッケージに関するより詳細なビルド関連情報を提供し、`go list` コマンドなどで利用されることを想定しています。
- `Target string // install path`
- `Goroot bool // is this package in the Go root?`
- `Standard bool // is this package part of the standard Go library?`
- `Root string // Go root or Go path dir containing this package`
- `SysoFiles []string // .syso object files to add to archive`
- `CgoCFLAGS []string // cgo: flags for C compiler`
- `CgoLDFLAGS []string // cgo: flags for linker`
- `CgoPkgConfig []string // cgo: pkg-config names`
- `TestGoFiles []string // _test.go files in package`
- `TestImports []string // imports from TestGoFiles`
- `XTestGoFiles []string // _test.go files outside package`
- `XTestImports []string // imports from XTestGoFiles`
これらの追加は、Goのビルドシステムがより多くの情報を公開し、ツールやスクリプトがGoパッケージのビルドに関する詳細な情報を取得できるようにするためのものです。特に `CgoCFLAGS`, `CgoLDFLAGS`, `CgoPkgConfig` は、Cgoのビルドプロセスをより細かく制御・理解するために重要です。
## コアとなるコードの変更箇所
### `misc/cgo/testso/test.bash`
```diff
--- a/misc/cgo/testso/test.bash
+++ b/misc/cgo/testso/test.bash
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
set -e
-gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
+gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c
go build main.go
LD_LIBRARY_PATH=. ./main
rm -f libcgosotest.so main
src/cmd/go/doc.go
doc.go
の変更は多岐にわたりますが、主要な変更は go env
コマンドのドキュメント追加と、Package
構造体へのフィールド追加です。
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -14,6 +14,7 @@ The commands are:\n build compile packages and dependencies\n clean remove object files\n doc run godoc on package sources\n+ env print Go environment information\n fix run go tool fix on packages\n fmt run gofmt on package sources\n get download and install packages and dependencies\n@@ -76,6 +77,8 @@ The build flags are shared by the build, install, run, and test commands:\n \t-x\n \t\tprint the commands.\n \n+\t-compiler name\n+\t\tname of compiler to use, as in runtime.Compiler (gccgo or gc)\n \t-gccgoflags \'arg list\'\n \t\targuments to pass on each gccgo compiler/linker invocation\n \t-gcflags \'arg list\'\n@@ -153,6 +156,20 @@ To run godoc with specific options, run godoc itself.\n See also: go fix, go fmt, go vet.\n \n \n+Print Go environment information\n+\n+Usage:\n+\n+\tgo env [var ...]\n+\n+Env prints Go environment information.\n+\n+By default env prints information as a shell script\n+(on Windows, a batch file). If one or more variable\n+names is given as arguments, env prints the value of\n+each named variable on its own line.\n+\n+\n Run go tool fix on packages\n \n Usage:\n@@ -253,21 +270,28 @@ is equivalent to -f \'{{.ImportPath}}\'. The struct\n being passed to the template is:\n \n type Package struct {\n+ Dir string // directory containing package sources\n+ ImportPath string // import path of package in dir\n Name string // package name\n Doc string // package documentation string\n- ImportPath string // import path of package in dir\n- Dir string // directory containing package sources\n- Version string // version of installed package (TODO)\n+ Target string // install path\n+ Goroot bool // is this package in the Go root?\n+ Standard bool // is this package part of the standard Go library?\n Stale bool // would \'go install\' do anything for this package?\n+ Root string // Go root or Go path dir containing this package\n \n // Source files\n- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, and XTestGoFiles)\n- TestGoFiles []string // _test.go source files internal to the package they are testing\n- XTestGoFiles []string // _test.go source files external to the package they are testing\n- CFiles []string // .c source files\n- HFiles []string // .h source files\n- SFiles []string // .s source files\n- CgoFiles []string // .go sources files that import \"C\"\n+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)\n+ CgoFiles []string // .go sources files that import \"C\"\n+ CFiles []string // .c source files\n+ HFiles []string // .h source files\n+ SFiles []string // .s source files\n+ SysoFiles []string // .syso object files to add to archive\n+\n+ // Cgo directives\n+ CgoCFLAGS []string // cgo: flags for C compiler\n+ CgoLDFLAGS []string // cgo: flags for linker\n+ CgoPkgConfig []string // cgo: pkg-config names\n \n // Dependency information\n Imports []string // import paths used by this package\n@@ -275,8 +299,13 @@ being passed to the template is:\n \n // Error information\n Incomplete bool // this package or a dependency has an error\n- Error *PackageError // error loading package\n+ Error *PackageError // error loading package\n DepsErrors []*PackageError // errors loading dependencies\n+\n+ TestGoFiles []string // _test.go files in package\n+ TestImports []string // imports from TestGoFiles\n+ XTestGoFiles []string // _test.go files outside package\n+ XTestImports []string // imports from XTestGoFiles\n }\n \n The -json flag causes the package data to be printed in JSON format
src/cmd/go/env.go
(新規ファイル)
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"runtime"
"strings"
)
var cmdEnv = &Command{
Run: runEnv,
UsageLine: "env [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
`,
}
type envVar struct {
name, value string
}
func mkEnv() []envVar {
var b builder
b.init()
env := []envVar{
{"GOROOT", goroot},
{"GOBIN", gobin},
{"GOARCH", goarch},
{"GOCHAR", archChar},
{"GOOS", goos},
{"GOEXE", exeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOTOOLDIR", toolDir},
{"GOGCCFLAGS", strings.Join(b.gccCmd(".")[3:], " ")},
}
return env
}
func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.name == name {
return e.value
}
}
return ""
}
func runEnv(cmd *Command, args []string) {
env := mkEnv()
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
return
}
switch runtime.GOOS {
default:
for _, e := range env {
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
}
case "plan9":
for _, e := range env {
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
}
case "windows":
for _, e := range env {
fmt.Printf("set %s=%s\n", e.name, e.value)
}
}
}
src/cmd/go/main.go
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -76,6 +76,7 @@ var commands = []*Command{\n cmdBuild,\n cmdClean,\n cmdDoc,\n+\tcmdEnv,\n cmdFix,\n cmdFmt,\n cmdGet,\n```
## コアとなるコードの解説
### `src/cmd/go/env.go`
このファイルは、`go env` コマンドのロジックを実装しています。
- **`cmdEnv`**: `go` コマンドのサブコマンドとして `env` を登録するための `Command` 構造体のインスタンスです。`UsageLine`、`Short`、`Long` フィールドでコマンドの利用方法と説明が定義されています。
- **`envVar` 構造体**: 環境変数の名前と値を保持するためのシンプルな構造体です。
- **`mkEnv()` 関数**:
- この関数は、Goのビルド環境に関する主要な環境変数とその値のリストを `[]envVar` のスライスとして生成します。
- `GOROOT`, `GOBIN`, `GOARCH`, `GOOS` など、Goのビルドに不可欠な変数が含まれています。
- 特筆すべきは `GOGCCFLAGS` の生成です。`b.gccCmd(".")[3:]` は、Goツールチェーンが内部的にGCCを呼び出す際に使用するデフォルトのフラグを取得するためのロジックです。`builder` 型の `gccCmd` メソッドは、GoのビルドシステムがGCCを呼び出す際のコマンドライン引数を生成し、その中からGCCフラグの部分を抽出しています。これにより、Goツールチェーンが推奨するGCCフラグが動的に取得され、`GOGCCFLAGS` として提供されます。
- **`findEnv()` 関数**: `mkEnv()` で生成された `envVar` のスライスから、指定された名前の環境変数の値を探して返します。
- **`runEnv()` 関数**:
- `go env` コマンドが実行された際のエントリポイントとなる関数です。
- `mkEnv()` を呼び出して環境変数のリストを取得します。
- `len(args) > 0` の場合(つまり、`go env GOROOT` のように引数が指定された場合)、引数として渡された各環境変数の値を1行ずつ出力します。
- 引数がない場合(デフォルトの動作)、現在のOSに応じて異なる形式で環境変数をシェルスクリプト形式で出力します。
- Unix-likeシステム(デフォルト): `VAR="value"` 形式。
- Plan 9: `VAR='value'` 形式(シングルクォートのエスケープ処理を含む)。
- Windows: `set VAR=value` 形式。
- このOSごとの出力形式の切り替えにより、`go env` の出力が各プラットフォームのシェルで直接実行可能な形式となるように配慮されています。
### `misc/cgo/testso/test.bash`
- このシェルスクリプトの変更は非常にシンプルですが、その影響は大きいです。
- `gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c` から `gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c` への変更は、Cgoで共有ライブラリをビルドする際に、Goツールチェーンが提供する `GOGCCFLAGS` を利用するようにしたものです。
- これにより、Goのビルドシステムが内部的に使用するGCCのコンパイルオプション(例えば、特定のアーキテクチャ向けのクロスコンパイルフラグなど)が、Cgoのビルドプロセスにも適用されるようになり、ビルドの互換性と信頼性が向上します。特に、64ビットシステム上で32ビットバイナリをビルドする際に必要となるGCCフラグが自動的に含まれることで、以前の問題が解決されます。
### `src/cmd/go/doc.go` と `src/cmd/go/main.go`
- `src/cmd/go/doc.go` への変更は、主に新しい `go env` コマンドのドキュメントを追加し、`go list` コマンドなどで利用される `Package` 構造体に、より詳細なビルド関連情報(特にCgo関連のフラグやテストファイルの情報)を追加するものです。これにより、Goのツールエコシステムがよりリッチな情報を利用できるようになります。
- `src/cmd/go/main.go` への変更は、`cmdEnv` 変数を `commands` スライスに追加することで、`go` コマンドが `env` サブコマンドを認識し、実行できるようにするためのものです。これは新しいコマンドを追加する際の標準的な手順です。
これらの変更は、Goのビルドシステムがより堅牢で、クロスプラットフォーム対応が強化され、かつユーザーやツールがビルド環境に関する詳細な情報にアクセスできるようになるための重要なステップを示しています。
## 関連リンク
- Go言語公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
- Go Modules (Go 1.11以降の依存関係管理): [https://go.dev/blog/using-go-modules](https://go.dev/blog/using-go-modules) (このコミット時点ではGo Modulesは存在しませんが、Goのビルドシステム全体の理解に役立ちます)
- Cgoのドキュメント: [https://go.dev/blog/c-go-is-not-go](https://go.dev/blog/c-go-is-not-go) (Cgoの基本的な概念と注意点)
## 参考にした情報源リンク
- Goのソースコード (GitHub): [https://github.com/golang/go](https://github.com/golang/go)
- Go Code Review (Gerrit): [https://go.dev/cl/5785053](https://go.dev/cl/5785053) (このコミットの元のコードレビューページ)
- GCC (GNU Compiler Collection) ドキュメント: [https://gcc.gnu.org/onlinedocs/](https://gcc.gnu.org/onlinedocs/)
- x86アーキテクチャに関する情報 (Wikipediaなど)
- クロスコンパイルに関する一般的な情報 (各種技術ブログ、ドキュメント)
- Goの環境変数に関する情報 (Go公式ドキュメントの `go env` コマンドの説明など)
- GOGCCFLAGSに関する情報: [https://go.dev/src/cmd/go/internal/work/exec.go](https://go.dev/src/cmd/go/internal/work/exec.go) (Goのソースコード内のGOGCCFLAGSの定義と使用箇所)
- GOGCCFLAGSに関するStack Overflowの議論: [https://stackoverflow.com/questions/tagged/gogccflags](https://stackoverflow.com/questions/tagged/gogccflags)
# [インデックス 12533] ファイルの概要
このコミットは、Go言語のコマンドラインツール `go` に `env` サブコマンドを追加し、それを利用して `misc/cgo/testso` のテストスクリプトを修正するものです。これにより、特に64ビットマシン上での32ビット(386)ビルドに関する問題が解決されます。
## コミット
commit 2c46569f57fd575e2acceabdbd40a187e66cd71e Author: Russ Cox rsc@golang.org Date: Thu Mar 8 14:28:44 2012 -0500
cmd/go: add env command, use to fix misc/cgo/testso
Fixes 386 build on 64-bit machines.
R=golang-dev, bradfitz, minux.ma
CC=golang-dev
https://golang.org/cl/5785053
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/2c46569f57fd575e2acceabdbd40a187e66cd71e](https://github.com/golang/go/commit/2c46569f57fd575e2acceabdbd40a187e66cd71e)
## 元コミット内容
このコミットの目的は以下の通りです。
1. `go env` コマンドの追加: Go環境に関する情報を表示するための新しいコマンドを導入します。
2. `misc/cgo/testso` の修正: `go env` コマンドを利用して、`misc/cgo/testso/test.bash` スクリプトにおけるビルドプロセスを改善します。
3. 64ビットマシン上での32ビット(386)ビルドの問題解決: 上記の変更により、特定の環境(64ビットマシンでの32ビットターゲットビルド)で発生していたビルド問題を修正します。
## 変更の背景
このコミットの背景には、Go言語のビルドシステムが進化する中で、異なるアーキテクチャ間でのクロスコンパイルの複雑さが増していたことがあります。特に、64ビットシステム上で32ビット(x86、通称386)バイナリをビルドする際に、Cgo(GoとC言語の相互運用機能)が絡むと、GCCのフラグ設定が環境に依存し、問題が発生しやすかったと考えられます。
`go env` コマンドの導入は、Goのビルド環境に関する標準的な情報をプログラム的に取得できるようにすることで、このような環境依存の問題を解決し、ビルドスクリプトのポータビリティを高めることを目的としています。`GOGCCFLAGS` のようなビルドフラグは、Goツールチェーンが内部的に使用するGCCのコンパイルオプションを決定するために重要であり、これらを `go env` 経由で公開することで、ユーザーやスクリプトがGoのビルド設定にアクセスし、適切に利用できるようになります。
`misc/cgo/testso/test.bash` は、Cgoと共有ライブラリ(`.so` ファイル)の連携をテストするためのスクリプトであり、このテストが特定の環境で失敗していたことが、このコミットの直接的なトリガーとなったようです。`go env GOGCCFLAGS` を使用することで、Goツールチェーンが推奨するGCCフラグを動的に取得し、ビルドコマンドに適用できるようになり、環境間の差異を吸収してビルドの信頼性を向上させます。
## 前提知識の解説
### Go言語のビルドシステム
Go言語は、`go build` コマンドを通じてソースコードをコンパイルし、実行可能なバイナリを生成します。このビルドシステムは、依存関係の解決、パッケージのコンパイル、リンクといった一連のプロセスを自動的に行います。Goはクロスコンパイルを強力にサポートしており、`GOOS`(オペレーティングシステム)や `GOARCH`(アーキテクチャ)といった環境変数を設定することで、異なるプラットフォーム向けのバイナリを簡単に生成できます。
### Cgo
Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。Cgoを使用するGoソースファイルは、`import "C"` という特殊なインポート宣言を含みます。Cgoは、GoコンパイラとCコンパイラ(通常はGCCやClang)の両方を連携させて動作するため、ビルドプロセスが複雑になることがあります。特に、CgoがC/C++のライブラリにリンクする場合、リンカフラグやインクルードパスの設定が重要になります。
### GCCFLAGS (GOGCCFLAGS)
`GCCFLAGS` は、GCC(GNU Compiler Collection)に渡されるコンパイルオプションやリンカオプションを指定するための一般的な用語です。Goのビルドシステムでは、Cgoを使用する際にGoツールチェーンが内部的にGCCを呼び出します。このとき、GoツールチェーンがGCCに渡す特定のフラグのセットが `GOGCCFLAGS` に相当します。これらのフラグは、ターゲットアーキテクチャ、OS、Goのバージョンなどに応じて動的に決定されることがあり、Goのビルド環境の整合性を保つ上で重要です。`GOGCCFLAGS` は、Goがcgoを使用するプログラムをビルドする際に、Cコンパイラ (`CC`) に渡される引数のスペース区切りリストを保持する環境変数です。これは主に情報提供を目的としており、ユーザーが直接変更してGoのビルドプロセスに影響を与えることは通常できません。Goツールチェーン自体がCコンパイラを呼び出す際に使用するフラグを反映しています。`go env` コマンドでその値を確認できます。例えば、`-fPIC` (Position-Independent Code) や `-pthread` (pthreadsサポート) のようなフラグが含まれることがあります。
### 386ビルドと64ビットマシン
- **386**: Intel 80386プロセッサに由来する名称で、一般的に32ビットのx86アーキテクチャを指します。
- **64ビットマシン**: 64ビットのCPUアーキテクチャ(例: x86-64、AMD64、Intel 64)を持つコンピュータを指します。
64ビットマシン上で32ビットバイナリをビルドする(クロスコンパイルする)場合、Cコンパイラ(GCC)は32ビットのライブラリやヘッダファイルを使用するように適切に設定される必要があります。これには、特定のコンパイラフラグ(例: `-m32`)や、32ビット版のシステムライブラリへのパス指定が必要になることがあります。このコミットが「Fixes 386 build on 64-bit machines」と述べているのは、まさにこのクロスコンパイル環境でのCgo関連のビルド問題を指しています。
## 技術的詳細
### `go env` コマンドの設計と実装
`go env` コマンドは、Goのビルド環境に関する様々な情報を表示するために導入されました。これは、シェルスクリプトや他のツールがGoの環境設定をプログラム的に取得できるようにすることを目的としています。
- **デフォルトの出力形式**: 引数なしで `go env` を実行すると、環境変数の設定をシェルスクリプト形式(Windowsではバッチファイル形式)で出力します。これにより、ユーザーは `eval $(go env)` のようにして、現在のシェルセッションにGoの環境変数を簡単に設定できます。
- **特定の変数の取得**: `go env [var ...]` のように引数として変数名を指定すると、その変数の値のみを1行で出力します。これは、特定の環境変数(例: `GOROOT`, `GOPATH`, `GOARCH`, `GOOS`, `GOGCCFLAGS` など)をスクリプト内で利用する際に非常に便利です。
- **`GOGCCFLAGS` の動的生成**: `env.go` 内の `mkEnv` 関数では、`GOGCCFLAGS` の値が `b.gccCmd(".")[3:]` という形で動的に生成されています。これは、Goツールチェーンが内部的に使用するGCCのコンパイルオプションを、現在のビルド環境に基づいて取得していることを示しています。これにより、Goのバージョンやターゲットアーキテクチャに応じて適切なGCCフラグが提供されます。
### `misc/cgo/testso/test.bash` の修正
元の `test.bash` スクリプトでは、Cgoで共有ライブラリをビルドする際に `gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c` のようにGCCを直接呼び出していました。この方法では、Goツールチェーンが内部的に使用するGCCフラグ(特にクロスコンパイル時に重要なもの)が考慮されていませんでした。
修正後、この行は `gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c` となっています。
- `$(go env GOGCCFLAGS)`: これはシェルコマンド置換であり、`go env GOGCCFLAGS` コマンドの出力結果(Goツールチェーンが推奨するGCCフラグの文字列)が、`gcc` コマンドの引数として展開されます。
- これにより、Cgoの共有ライブラリビルド時に、Goツールチェーンが想定する適切なGCCフラグが自動的に適用されるようになり、特に64ビットマシン上での32ビットビルドのような複雑な環境での互換性が向上します。
### `src/cmd/go/doc.go` の変更
`doc.go` は `go` コマンドのヘルプドキュメントを生成するためのソースファイルです。
- `go env` コマンドの追加に伴い、`The commands are:` セクションに `env print Go environment information` が追加されました。
- `Print Go environment information` という新しいセクションが追加され、`go env` コマンドの基本的な使い方と引数に関する説明が記述されました。
- `go help packages` などで表示される `Package` 構造体(Goパッケージに関するメタデータ)に、以下の新しいフィールドが追加されました。これらのフィールドは、Goパッケージに関するより詳細なビルド関連情報を提供し、`go list` コマンドなどで利用されることを想定しています。
- `Target string // install path`
- `Goroot bool // is this package in the Go root?`
- `Standard bool // is this package part of the standard Go library?`
- `Root string // Go root or Go path dir containing this package`
- `SysoFiles []string // .syso object files to add to archive`
- `CgoCFLAGS []string // cgo: flags for C compiler`
- `CgoLDFLAGS []string // cgo: flags for linker`
- `CgoPkgConfig []string // cgo: pkg-config names`
- `TestGoFiles []string // _test.go files in package`
- `TestImports []string // imports from TestGoFiles`
- `XTestGoFiles []string // _test.go files outside package`
- `XTestImports []string // imports from XTestGoFiles`
これらの追加は、Goのビルドシステムがより多くの情報を公開し、ツールやスクリプトがGoパッケージのビルドに関する詳細な情報を取得できるようにするためのものです。特に `CgoCFLAGS`, `CgoLDFLAGS`, `CgoPkgConfig` は、Cgoのビルドプロセスをより細かく制御・理解するために重要です。
## コアとなるコードの変更箇所
### `misc/cgo/testso/test.bash`
```diff
--- a/misc/cgo/testso/test.bash
+++ b/misc/cgo/testso/test.bash
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
set -e
-gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
+gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c
go build main.go
LD_LIBRARY_PATH=. ./main
rm -f libcgosotest.so main
src/cmd/go/doc.go
doc.go
の変更は多岐にわたりますが、主要な変更は go env
コマンドのドキュメント追加と、Package
構造体へのフィールド追加です。
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -14,6 +14,7 @@ The commands are:\n build compile packages and dependencies\n clean remove object files\n doc run godoc on package sources\n+ env print Go environment information\n fix run go tool fix on packages\n fmt run gofmt on package sources\n get download and install packages and dependencies\n@@ -76,6 +77,8 @@ The build flags are shared by the build, install, run, and test commands:\n \t-x\n \t\tprint the commands.\n \n+\t-compiler name\n+\t\tname of compiler to use, as in runtime.Compiler (gccgo or gc)\n \t-gccgoflags \'arg list\'\n \t\targuments to pass on each gccgo compiler/linker invocation\n \t-gcflags \'arg list\'\n@@ -153,6 +156,20 @@ To run godoc with specific options, run godoc itself.\n See also: go fix, go fmt, go vet.\n \n \n+Print Go environment information\n+\n+Usage:\n+\n+\tgo env [var ...]\n+\n+Env prints Go environment information.\n+\n+By default env prints information as a shell script\n+(on Windows, a batch file). If one or more variable\n+names is given as arguments, env prints the value of\n+each named variable on its own line.\n+\n+\n Run go tool fix on packages\n \n Usage:\n@@ -253,21 +270,28 @@ is equivalent to -f \'{{.ImportPath}}\'. The struct\n being passed to the template is:\n \n type Package struct {\n+ Dir string // directory containing package sources\n+ ImportPath string // import path of package in dir\n Name string // package name\n Doc string // package documentation string\n- ImportPath string // import path of package in dir\n- Dir string // directory containing package sources\n- Version string // version of installed package (TODO)\n+ Target string // install path\n+ Goroot bool // is this package in the Go root?\n+ Standard bool // is this package part of the standard Go library?\n Stale bool // would \'go install\' do anything for this package?\n+ Root string // Go root or Go path dir containing this package\n \n // Source files\n- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, and XTestGoFiles)\n- TestGoFiles []string // _test.go source files internal to the package they are testing\n- XTestGoFiles []string // _test.go source files external to the package they are testing\n- CFiles []string // .c source files\n- HFiles []string // .h source files\n- SFiles []string // .s source files\n- CgoFiles []string // .go sources files that import \"C\"\n+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)\n+ CgoFiles []string // .go sources files that import \"C\"\n+ CFiles []string // .c source files\n+ HFiles []string // .h source files\n+ SFiles []string // .s source files\n+ SysoFiles []string // .syso object files to add to archive\n+\n+ // Cgo directives\n+ CgoCFLAGS []string // cgo: flags for C compiler\n+ CgoLDFLAGS []string // cgo: flags for linker\n+ CgoPkgConfig []string // cgo: pkg-config names\n \n // Dependency information\n Imports []string // import paths used by this package\n@@ -275,8 +299,13 @@ being passed to the template is:\n \n // Error information\n Incomplete bool // this package or a dependency has an error\n- Error *PackageError // error loading package\n+ Error *PackageError // error loading package\n DepsErrors []*PackageError // errors loading dependencies\n+\n+ TestGoFiles []string // _test.go files in package\n+ TestImports []string // imports from TestGoFiles\n+ XTestGoFiles []string // _test.go files outside package\n+ XTestImports []string // imports from XTestGoFiles\n }\n \n The -json flag causes the package data to be printed in JSON format
src/cmd/go/env.go
(新規ファイル)
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"runtime"
"strings"
)
var cmdEnv = &Command{
Run: runEnv,
UsageLine: "env [var ...]",
Short: "print Go environment information",
Long: `
Env prints Go environment information.
By default env prints information as a shell script
(on Windows, a batch file). If one or more variable
names is given as arguments, env prints the value of
each named variable on its own line.
`,
}
type envVar struct {
name, value string
}
func mkEnv() []envVar {
var b builder
b.init()
env := []envVar{
{"GOROOT", goroot},
{"GOBIN", gobin},
{"GOARCH", goarch},
{"GOCHAR", archChar},
{"GOOS", goos},
{"GOEXE", exeSuffix},
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOTOOLDIR", toolDir},
{"GOGCCFLAGS", strings.Join(b.gccCmd(".")[3:], " ")},
}
return env
}
func findEnv(env []envVar, name string) string {
for _, e := range env {
if e.name == name {
return e.value
}
}
return ""
}
func runEnv(cmd *Command, args []string) {
env := mkEnv()
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
}
return
}
switch runtime.GOOS {
default:
for _, e := range env {
fmt.Printf("%s=\"%s\"\n", e.name, e.value)
}
case "plan9":
for _, e := range env {
fmt.Printf("%s='%s'\n", e.name, strings.Replace(e.value, "'", "''", -1))
}
case "windows":
for _, e := range env {
fmt.Printf("set %s=%s\n", e.name, e.value)
}
}
}
src/cmd/go/main.go
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -76,6 +76,7 @@ var commands = []*Command{\n cmdBuild,\n cmdClean,\n cmdDoc,\n+\tcmdEnv,\n cmdFix,\n cmdFmt,\n cmdGet,\n```
## コアとなるコードの解説
### `src/cmd/go/env.go`
このファイルは、`go env` コマンドのロジックを実装しています。
- **`cmdEnv`**: `go` コマンドのサブコマンドとして `env` を登録するための `Command` 構造体のインスタンスです。`UsageLine`、`Short`、`Long` フィールドでコマンドの利用方法と説明が定義されています。
- **`envVar` 構造体**: 環境変数の名前と値を保持するためのシンプルな構造体です。
- **`mkEnv()` 関数**:
- この関数は、Goのビルド環境に関する主要な環境変数とその値のリストを `[]envVar` のスライスとして生成します。
- `GOROOT`, `GOBIN`, `GOARCH`, `GOOS` など、Goのビルドに不可欠な変数が含まれています。
- 特筆すべきは `GOGCCFLAGS` の生成です。`b.gccCmd(".")[3:]` は、Goツールチェーンが内部的にGCCを呼び出す際に使用するデフォルトのフラグを取得するためのロジックです。`builder` 型の `gccCmd` メソッドは、GoのビルドシステムがGCCを呼び出す際のコマンドライン引数を生成し、その中からGCCフラグの部分を抽出しています。これにより、Goツールチェーンが推奨するGCCフラグが動的に取得され、`GOGCCFLAGS` として提供されます。
- **`findEnv()` 関数**: `mkEnv()` で生成された `envVar` のスライスから、指定された名前の環境変数の値を探して返します。
- **`runEnv()` 関数**:
- `go env` コマンドが実行された際のエントリポイントとなる関数です。
- `mkEnv()` を呼び出して環境変数のリストを取得します。
- `len(args) > 0` の場合(つまり、`go env GOROOT` のように引数が指定された場合)、引数として渡された各環境変数の値を1行ずつ出力します。
- 引数がない場合(デフォルトの動作)、現在のOSに応じて異なる形式で環境変数をシェルスクリプト形式で出力します。
- Unix-likeシステム(デフォルト): `VAR="value"` 形式。
- Plan 9: `VAR='value'` 形式(シングルクォートのエスケープ処理を含む)。
- Windows: `set VAR=value` 形式。
- このOSごとの出力形式の切り替えにより、`go env` の出力が各プラットフォームのシェルで直接実行可能な形式となるように配慮されています。
### `misc/cgo/testso/test.bash`
- このシェルスクリプトの変更は非常にシンプルですが、その影響は大きいです。
- `gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c` から `gcc $(go env GOGCCFLAGS) -shared -o libcgosotest.so cgoso_c.c` への変更は、Cgoで共有ライブラリをビルドする際に、Goツールチェーンが提供する `GOGCCFLAGS` を利用するようにしたものです。
- これにより、Goのビルドシステムが内部的に使用するGCCのコンパイルオプション(例えば、特定のアーキテクチャ向けのクロスコンパイルフラグなど)が、Cgoのビルドプロセスにも適用されるようになり、ビルドの互換性と信頼性が向上します。特に、64ビットシステム上で32ビットバイナリをビルドする際に必要となるGCCフラグが自動的に含まれることで、以前の問題が解決されます。
### `src/cmd/go/doc.go` と `src/cmd/go/main.go`
- `src/cmd/go/doc.go` への変更は、主に新しい `go env` コマンドのドキュメントを追加し、`go list` コマンドなどで利用される `Package` 構造体に、より詳細なビルド関連情報(特にCgo関連のフラグやテストファイルの情報)を追加するものです。これにより、Goのツールエコシステムがよりリッチな情報を利用できるようになります。
- `src/cmd/go/main.go` への変更は、`cmdEnv` 変数を `commands` スライスに追加することで、`go` コマンドが `env` サブコマンドを認識し、実行できるようにするためのものです。これは新しいコマンドを追加する際の標準的な手順です。
これらの変更は、Goのビルドシステムがより堅牢で、クロスプラットフォーム対応が強化され、かつユーザーやツールがビルド環境に関する詳細な情報にアクセスできるようになるための重要なステップを示しています。
## 関連リンク
- Go言語公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
- Go Modules (Go 1.11以降の依存関係管理): [https://go.dev/blog/using-go-modules](https://go.dev/blog/using-go-modules) (このコミット時点ではGo Modulesは存在しませんが、Goのビルドシステム全体の理解に役立ちます)
- Cgoのドキュメント: [https://go.dev/blog/c-go-is-not-go](https://go.dev/blog/c-go-is-not-go) (Cgoの基本的な概念と注意点)
## 参考にした情報源リンク
- Goのソースコード (GitHub): [https://github.com/golang/go](https://github.com/golang/go)
- Go Code Review (Gerrit): [https://go.dev/cl/5785053](https://go.dev/cl/5785053) (このコミットの元のコードレビューページ)
- GCC (GNU Compiler Collection) ドキュメント: [https://gcc.gnu.org/onlinedocs/](https://gcc.gnu.org/onlinedocs/)
- x86アーキテクチャに関する情報 (Wikipediaなど)
- クロスコンパイルに関する一般的な情報 (各種技術ブログ、ドキュメント)
- Goの環境変数に関する情報 (Go公式ドキュメントの `go env` コマンドの説明など)
- GOGCCFLAGSに関する情報: [https://go.dev/src/cmd/go/internal/work/exec.go](https://go.dev/src/cmd/go/internal/work/exec.go) (Goのソースコード内のGOGCCFLAGSの定義と使用箇所)
- GOGCCFLAGSに関するStack Overflowの議論: [https://stackoverflow.com/questions/tagged/gogccflags](https://stackoverflow.com/questions/tagged/gogccflags)