[インデックス 11524] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go
に対する複数の改善を含んでいます。主な変更点は以下の通りです。
$GOROOT/src/pkg
、$GOROOT/src/cmd
、$GOPATH/src
といったトップレベルのディレクトリをパッケージディレクトリとして扱わないように修正し、これらのサブディレクトリのみをパッケージとして認識するようにしました。これにより、Goのパッケージ解決のセマンティクスがより正確になります。cgo
のビルドプロセスにおいて、環境変数$CGO_CFLAGS
および$CGO_LDFLAGS
から追加のコンパイラおよびリンカ引数を受け入れるようにしました。これにより、Cgoを使用する際のビルドの柔軟性が向上します。pkg-config
コマンドの実行が失敗した場合に、その出力を表示するように改善しました。これにより、pkg-config
関連のエラーのデバッグが容易になります。- バージョン管理システム (VCS) の操作、特に
git
コマンドの内部的な使用方法を改善しました。
コミット
commit 0f1056667fb8952046e5360ebf9f3285b6f7de33
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 31 17:40:36 2012 -0500
cmd/go: improvements
Do not treat $GOROOT/src/pkg, $GOROOT/src/cmd,
$GOPATH/src as package directories (only subdirectories
of those can be package directories). Fixes issue 2602.
Accept additional compiler and linker arguments during
cgo from $CGO_CFLAGS and $CGO_LDFLAGS, as the
Makefiles used to do.
Show failed pkg-config output. Fixes issue 2785.
Use different (perhaps better) git commands. Fixes issue 2109.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5605045
---
src/cmd/go/build.go | 17 +++++++++++++----\n src/cmd/go/get.go | 6 +-----\n src/cmd/go/main.go | 6 +++---\n src/cmd/go/vcs.go | 25 ++++++++++++++-----------\n 4 files changed, 31 insertions(+), 23 deletions(-)\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0f1056667fb8952046e5360ebf9f3285b6f7de33
元コミット内容
cmd/go: improvements
Do not treat $GOROOT/src/pkg, $GOROOT/src/cmd,
$GOPATH/src as package directories (only subdirectories
of those can be package directories). Fixes issue 2602.
Accept additional compiler and linker arguments during
cgo from $CGO_CFLAGS and $CGO_LDFLAGS, as the
Makefiles used to do.
Show failed pkg-config output. Fixes issue 2785.
Use different (perhaps better) git commands. Fixes issue 2109.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5605045
変更の背景
このコミットは、Goのビルドシステムとツールチェーンにおけるいくつかの既存の問題と改善点を解決するために行われました。
-
Issue 2602: トップレベルディレクトリのパッケージ認識問題
- Goのビルドツール
go build
やgo install
は、パッケージを識別する際に、$GOROOT/src/pkg
、$GOROOT/src/cmd
、$GOPATH/src
といったディレクトリ自体をパッケージとして誤って認識してしまうことがありました。これらのディレクトリは通常、パッケージのルートではなく、パッケージを含むコンテナディレクトリであるべきです。この誤認識により、ビルドエラーや予期せぬ動作が発生する可能性がありました。例えば、go install pkg
のようなコマンドが意図しない結果を招くことがありました。
- Goのビルドツール
-
Cgoビルドにおけるコンパイラ/リンカ引数の不足
cgo
はGoコードからC/C++コードを呼び出すためのメカニズムですが、従来のGoのビルドシステムでは、C/C++コンパイラやリンカに追加のフラグ(例えば、特定のインクルードパスやライブラリパス)を渡すための標準的な方法が不足していました。Makefilesを使用していた時代にはこれらの引数を渡すことができましたが、cmd/go
ツールが主流になるにつれて、この機能が失われていました。開発者は、外部のC/C++ライブラリに依存するCgoプロジェクトをビルドする際に、これらの引数を指定できず、不便を強いられていました。
-
Issue 2785:
pkg-config
失敗時のデバッグ情報の不足pkg-config
は、C/C++ライブラリのコンパイル・リンクに必要なフラグ(インクルードパス、ライブラリパス、ライブラリ名など)を取得するためのツールです。Cgoプロジェクトでは、外部Cライブラリの依存関係を解決するためにpkg-config
が利用されます。しかし、pkg-config
の実行が何らかの理由で失敗した場合(例えば、必要なライブラリが見つからない、設定ファイルが不正など)、cmd/go
ツールはその失敗の具体的な原因を示す出力を表示しませんでした。これにより、開発者はpkg-config
関連のビルドエラーのデバッグに苦労していました。
-
Issue 2109:
git
コマンドの非効率性または非推奨な使用cmd/go
ツールは、go get
コマンドなどでリモートリポジトリからソースコードを取得する際に、内部的にgit
などのバージョン管理システムコマンドを呼び出します。このコミット以前は、使用されているgit
コマンドの一部が非効率的であったり、特定のシナリオで問題を引き起こす可能性がありました。例えば、タグの同期やリポジトリの更新方法に関して、より堅牢で推奨されるgit
の操作方法が存在していました。
これらの問題に対処し、Goのビルドシステム全体の堅牢性、使いやすさ、およびデバッグ能力を向上させることが、このコミットの主な目的でした。
前提知識の解説
このコミットの変更内容を理解するためには、以下の概念について基本的な知識が必要です。
-
Go言語のワークスペースと環境変数:
GOROOT
: Goのインストールディレクトリを指す環境変数です。Goの標準ライブラリのソースコード($GOROOT/src
以下)などが含まれます。GOPATH
: Goのワークスペースディレクトリを指す環境変数です。ユーザーが開発するGoプロジェクトのソースコード、コンパイル済みパッケージ、実行可能ファイルなどが配置されます。通常、$GOPATH/src
にソースコード、$GOPATH/pkg
にコンパイル済みパッケージ、$GOPATH/bin
に実行可能ファイルが置かれます。- パッケージディレクトリ: Goでは、ディレクトリがパッケージの単位となります。
import "path/to/package"
のように指定された場合、Goツールは$GOROOT/src/path/to/package
や$GOPATH/src/path/to/package
を探します。
-
cgo
:- Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出すことを可能にします。また、GoコードをC言語から呼び出すこともできます。
cgo
を使用すると、Goのビルドプロセス中にC/C++コンパイラやリンカが呼び出され、GoとC/C++の間のバインディングが生成されます。 CGO_CFLAGS
/CGO_LDFLAGS
:cgo
のビルドプロセス中にC/C++コンパイラ(CGO_CFLAGS
)やリンカ(CGO_LDFLAGS
)に渡される追加のフラグを指定するための環境変数です。これらは、インクルードパス(-I
)、ライブラリパス(-L
)、ライブラリ名(-l
)などを指定するのに使われます。
- Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出すことを可能にします。また、GoコードをC言語から呼び出すこともできます。
-
pkg-config
:- Unix系システムで広く使われているツールで、インストールされているライブラリのコンパイル・リンクに必要な情報を取得するために使用されます。例えば、
pkg-config --cflags --libs gtk+-3.0
のように実行すると、GTK+ 3.0ライブラリを使用するために必要なコンパイラフラグとリンカフラグが出力されます。Cgoプロジェクトでは、Goプログラムが外部のCライブラリに依存する場合に、pkg-config
を利用してこれらのライブラリのビルド情報を動的に取得します。
- Unix系システムで広く使われているツールで、インストールされているライブラリのコンパイル・リンクに必要な情報を取得するために使用されます。例えば、
-
バージョン管理システム (VCS):
- Git: 分散型バージョン管理システム。ソースコードの変更履歴を管理し、複数の開発者間での共同作業を容易にします。
git clone
: リモートリポジトリの完全なコピーをローカルに作成するコマンド。git fetch
: リモートリポジトリから最新の変更(コミット、ブランチ、タグなど)をローカルにダウンロードするが、現在のブランチにはマージしないコマンド。git checkout
: ブランチやコミット、タグなど、特定の状態に作業ディレクトリを切り替えるコマンド。git tag
: 特定のコミットに意味のある名前(タグ)を付けるコマンド。通常、リリースバージョンを示すために使われます。git branch
: ブランチを管理するコマンド。master
は伝統的にメインの開発ラインを指すブランチ名です。go get
: Goのパッケージをリモートリポジトリから取得し、ビルドしてインストールするコマンド。内部的にVCSコマンド(git, hg, svn, bzrなど)を呼び出します。
技術的詳細
このコミットは、Goのビルドツール cmd/go
の内部実装に複数の重要な変更を加えています。
-
トップレベルディレクトリのパッケージ認識の修正 (
src/cmd/go/main.go
):- 以前の
cmd/go
は、$GOROOT/src/pkg
、$GOROOT/src/cmd
、$GOPATH/src
といったディレクトリ自体を有効なGoパッケージとして扱ってしまうバグがありました。しかし、これらのディレクトリは通常、Goパッケージのルートではなく、複数のパッケージを含むコンテナディレクトリです。 - このコミットでは、
filepath.Walk
を使用してファイルシステムを走査し、パッケージディレクトリを検出するロジックに修正が加えられました。具体的には、path == cmd
やpath == src
、path == dir
といった条件が追加され、これらのトップレベルディレクトリ自体がパッケージとして認識されないように変更されました。これにより、go install pkg
のようなコマンドが意図しない動作をするのを防ぎ、Goのパッケージ解決のセマンティクスがより正確になりました。
- 以前の
-
CGO_CFLAGS
およびCGO_LDFLAGS
のサポート (src/cmd/go/build.go
):cgo
のビルドプロセスにおいて、環境変数CGO_CFLAGS
とCGO_LDFLAGS
の値を読み込み、それぞれCコンパイラとリンカに渡す引数リストに追加する機能が実装されました。envList
という新しいヘルパー関数が導入され、環境変数の値をスペースで区切られた文字列のリストとして解析します。cgoCFLAGS
とcgoLDFLAGS
の初期化時に、envList("CGO_CFLAGS")
とenvList("CGO_LDFLAGS")
の結果がp.info.CgoCFLAGS
やp.info.CgoLDFLAGS
と結合されるようになりました。これにより、開発者は環境変数を通じて追加のコンパイラ/リンカ引数を簡単に指定できるようになり、特に外部Cライブラリへの依存がある場合にビルドの柔軟性が大幅に向上しました。
-
pkg-config
失敗時の出力表示 (src/cmd/go/build.go
):pkg-config
コマンド(--cflags
または--libs
)の実行が失敗した場合、以前は単にエラーが返されるだけで、pkg-config
自体の標準出力や標準エラー出力が表示されませんでした。これにより、何が問題だったのかを特定するのが困難でした。- このコミットでは、
b.showOutput
メソッドが呼び出され、pkg-config
コマンドの出力(たとえそれがエラーメッセージであっても)がユーザーに表示されるようになりました。さらに、b.print(err.Error() + "\n")
を通じて、Go側で捕捉されたエラーメッセージも出力されます。これにより、pkg-config
関連のビルドエラーが発生した際に、より詳細なデバッグ情報が提供され、問題解決が容易になります。
-
git
コマンドの改善 (src/cmd/go/vcs.go
,src/cmd/go/get.go
):vcs.go
ファイルでは、vcsCmd
構造体にtagSyncDefault
という新しいフィールドが追加されました。これは、特定のタグが指定されていない場合にデフォルトで使用されるタグ同期コマンドを定義します。git
の定義において、tagSyncDefault
がcheckout origin/master
に変更されました。これは、git
リポジトリでタグが指定されない場合に、リモートのmaster
ブランチにチェックアウトするという、より一般的で堅牢な動作を反映しています。以前はtagDefault
フィールドがありましたが、これは削除され、より柔軟なtagSyncDefault
に置き換えられました。get.go
ファイルでは、selectTag
関数の結果を直接vcs.tagSync
に渡すように変更されました。これにより、tagDefault
のような中間的な変数やロジックが不要になり、コードが簡素化されました。- これらの変更は、
go get
が内部的にgit
を使用してリポジトリを操作する際の信頼性と効率性を向上させることを目的としています。特に、タグの同期やリポジトリの初期クローン/更新の際に、より適切なgit
コマンドが使用されるようになります。
コアとなるコードの変更箇所
src/cmd/go/build.go
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1131,6 +1131,10 @@ func (b *builder) gccCmd(objdir string) []string {
return a
}
+func envList(key string) []string {
+ return strings.Fields(os.Getenv(key))
+}
+
var cgoRe = regexp.MustCompile(`[/\\\\:]`)
func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo, outObj []string, err error) {
@@ -1140,19 +1144,24 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
outObj = append(outObj, "") // for importObj, at end of function
- cgoCFLAGS := stringList(p.info.CgoCFLAGS)
- cgoLDFLAGS := stringList(p.info.CgoLDFLAGS)
+ cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.info.CgoCFLAGS)
+ cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.info.CgoLDFLAGS)
+
if pkgs := p.info.CgoPkgConfig; len(pkgs) > 0 {
out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs)
if err != nil {
- return nil, nil, err
+ b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoCFLAGS = append(cgoCFLAGS, strings.Fields(string(out))...)
}
out, err = b.runOut(p.Dir, p.ImportPath, "pkg-config", "--libs", pkgs)
if err != nil {
- return nil, nil, err
+ b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.print(err.Error() + "\n")
+ return nil, nil, errPrintedOutput
}
if len(out) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, strings.Fields(string(out))...)
src/cmd/go/main.go
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -347,7 +347,7 @@ func allPackages(pattern string) []string {
goroot := build.Path[0].Path
cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
+ if err != nil || !fi.IsDir() || path == cmd {
return nil
}
name := path[len(cmd):]
@@ -378,7 +378,7 @@ func allPackages(pattern string) []string {
}
src := t.SrcDir() + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
+ if err != nil || !fi.IsDir() || path == src {
return nil
}
@@ -445,7 +445,7 @@ func allPackagesInFS(pattern string) []string {
var pkgs []string
filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
+ if err != nil || !fi.IsDir() || path == dir {
return nil
}
src/cmd/go/vcs.go
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -23,9 +23,9 @@ type vcsCmd struct {
createCmd string // command to download a fresh copy of a repository
downloadCmd string // command to download updates into an existing repository
- tagCmd []tagCmd // commands to list tags
- tagDefault string // default tag to use
- tagSyncCmd string // command to sync to specific tag
+ tagCmd []tagCmd // commands to list tags
+ tagSyncCmd string // command to sync to specific tag
+ tagSyncDefault string // command to sync to default tag
}
// A tagCmd describes a command to list available tags
@@ -71,8 +71,8 @@ var vcsHg = &vcsCmd{
{"tags", `^(\S+)`},
{"branches", `^(\S+)`},
},
- tagDefault: "default",
- tagSyncCmd: "update -r {tag}",
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update default",
}
// vcsGit describes how to use Git.
@@ -83,9 +83,9 @@ var vcsGit = &vcsCmd{
createCmd: "clone {repo} {dir}",
downloadCmd: "fetch",
- tagCmd: []tagCmd{{"tag", `^(\S+)$`}},
- tagDefault: "master",
- tagSyncCmd: "checkout {tag}",
+ tagCmd: []tagCmd{{"tag", `^(\S+)$`}},
+ tagSyncCmd: "checkout {tag}",
+ tagSyncDefault: "checkout origin/master",
}
// vcsBzr describes how to use Bazaar.
@@ -99,9 +99,9 @@ var vcsBzr = &vcsCmd{
// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
downloadCmd: "pull --overwrite",
- tagCmd: []tagCmd{{"tags", `^(\S+)`}},
- tagDefault: "revno:-1",
- tagSyncCmd: "update -r {tag}",
+ tagCmd: []tagCmd{{"tags", `^(\S+)`}},
+ tagSyncCmd: "update -r {tag}",
+ tagSyncDefault: "update -r revno:-1",
}
// vcsSvn describes how to use Subversion.
@@ -198,6 +198,9 @@ func (v *vcsCmd) tagSync(dir, tag string) error {\n if v.tagSyncCmd == "" {\n return nil\n }\n+\tif tag == "" && v.tagSyncDefault != "" {\n+\t\treturn v.run(dir, v.tagSyncDefault)\n+\t}\n return v.run(dir, v.tagSyncCmd, "tag", tag)\n }\n
src/cmd/go/get.go
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -215,11 +215,7 @@ func downloadPackage(p *Package) error {
if i := strings.Index(vers, " "); i >= 0 {
vers = vers[:i]
}
-\ttag := selectTag(vers, tags)
-\tif tag == "" {\n-\t\ttag = vcs.tagDefault\n-\t}\n-\tif err := vcs.tagSync(root, tag); err != nil {\n+\tif err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {\n \t\treturn err\n \t}\n
コアとなるコードの解説
src/cmd/go/build.go
の変更
envList
関数の追加:func envList(key string) []string
は、指定された環境変数key
の値を取得し、その値をスペースで分割して文字列スライスとして返します。これは、CGO_CFLAGS
やCGO_LDFLAGS
のような環境変数から複数の引数を取得する際に便利です。
CGO_CFLAGS
とCGO_LDFLAGS
の統合:- 変更前:
cgoCFLAGS := stringList(p.info.CgoCFLAGS)
- 変更後:
cgoCFLAGS := stringList(envList("CGO_CFLAGS"), p.info.CgoCFLAGS)
- これにより、
cgo
のビルド時に、パッケージ情報 (p.info.CgoCFLAGS
) に加えて、環境変数CGO_CFLAGS
で指定されたフラグもcgoCFLAGS
リストに追加されるようになりました。cgoLDFLAGS
も同様です。stringList
関数は、複数の文字列スライスを結合するヘルパー関数です。
- 変更前:
pkg-config
失敗時の出力表示:pkg-config
コマンドの実行がエラーになった場合 (if err != nil
) の処理が変更されました。- 変更前は単に
return nil, nil, err
でエラーを返していましたが、変更後は以下の2行が追加されました。b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
:pkg-config
コマンドとその出力(エラーメッセージを含む)をユーザーに表示します。これにより、何が問題だったのかが視覚的に確認できるようになります。b.print(err.Error() + "\n")
:Go側で捕捉されたエラーメッセージも出力します。return nil, nil, errPrintedOutput
:エラーが既に表示されたことを示す特別なエラーerrPrintedOutput
を返します。これにより、上位の呼び出し元で重複してエラーメッセージが表示されるのを防ぎます。
src/cmd/go/main.go
の変更
- トップレベルディレクトリのパッケージ認識の修正:
filepath.Walk
を使用してパッケージを探索する際に、if err != nil || !fi.IsDir()
という条件に加えて、|| path == cmd
、|| path == src
、|| path == dir
という条件が追加されました。- これは、
$GOROOT/src/cmd
、$GOPATH/src
、およびallPackagesInFS
で指定されたルートディレクトリ自体が、有効なGoパッケージとして誤って認識されるのを防ぐためのものです。これらのディレクトリはパッケージのコンテナであり、それ自体がパッケージであるべきではありません。この修正により、Goのパッケージ解決のロジックがより正確になりました。
src/cmd/go/vcs.go
の変更
vcsCmd
構造体の変更:tagDefault string
フィールドが削除され、代わりにtagSyncDefault string
フィールドが追加されました。tagSyncDefault
は、特定のタグが指定されていない場合に、リポジトリを同期するためのデフォルトコマンドを保持します。これにより、VCSの種類ごとに異なるデフォルトの同期動作を柔軟に設定できるようになります。
git
の定義の変更:vcsGit
の定義において、tagDefault: "master"
が削除され、tagSyncDefault: "checkout origin/master"
が追加されました。- これは、
git
においてタグが指定されない場合のデフォルトの同期動作を、リモートのmaster
ブランチにチェックアウトするという、より一般的で堅牢な方法に変更したことを意味します。
tagSync
メソッドの変更:func (v *vcsCmd) tagSync(dir, tag string) error
メソッドに以下のロジックが追加されました。if tag == "" && v.tagSyncDefault != "" { return v.run(dir, v.tagSyncDefault) }
- これは、
tag
引数が空文字列(つまり、特定のタグが指定されていない)であり、かつv.tagSyncDefault
が設定されている場合に、tagSyncDefault
で定義されたコマンドを実行するようにします。これにより、デフォルトの同期動作がより柔軟に制御できるようになりました。
src/cmd/go/get.go
の変更
vcs.tagSync
の呼び出しの簡素化:- 変更前は、
selectTag
の結果をtag
変数に格納し、tag
が空の場合はvcs.tagDefault
を使用するというロジックがありました。 - 変更後:
if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
selectTag(vers, tags)
の結果を直接vcs.tagSync
に渡すように変更されました。これは、vcs.tagSync
メソッド自体がtagSyncDefault
ロジックを内部で処理するようになったため、get.go
側でデフォルトタグの処理を行う必要がなくなったためです。これにより、コードがより簡潔になりました。
- 変更前は、
関連リンク
- Go CL 5605045: https://golang.org/cl/5605045
参考にした情報源リンク
- Go Issue 2602: cmd/go: go install pkg should not install pkg itself (closed by this commit) - https://github.com/golang/go/issues/2602
- Go Issue 2785: cmd/go: show pkg-config output on failure (closed by this commit) - https://github.com/golang/go/issues/2785
- Go Issue 2109: cmd/go: use different (perhaps better) git commands (closed by this commit) - https://github.com/golang/go/issues/2109
- Go Modules (Go公式ドキュメント): https://go.dev/blog/using-go-modules (Go Modulesはコミット当時のGoのバージョンでは存在しませんでしたが、
GOPATH
の概念を理解する上で参考になります) - cgo (Go公式ドキュメント): https://go.dev/blog/cgo
- pkg-config (Wikipedia): https://ja.wikipedia.org/wiki/Pkg-config
- Git Documentation: https://git-scm.com/doc
- Go Command Documentation: https://go.dev/cmd/go/ (当時のバージョンとは異なる可能性がありますが、
cmd/go
の基本的な機能理解に役立ちます)