Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

このコミットは、Go言語のビルドシステムにおいて、内部ツール(go-tool)の配置ディレクトリの参照方法を修正するものです。具体的には、go-toolGOBIN環境変数で指定されるディレクトリではなく、Goのインストールルートディレクトリ(GOROOT)内のbin/go-toolに配置されるべきであるという認識に基づき、関連するMakefileとGoのソースコードが更新されています。これにより、Goの内部ツールが常に正しい場所から参照され、ビルドや実行時の問題が解消されます。

コミット

commit 2d13e1f16e4b6709dc98f2cc45d717af8807005a
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Mon Jan 30 16:43:28 2012 +1100

    build: use correct go-tool directory location
    
    R=golang-dev, rsc, cw, rsc
    CC=golang-dev
    https://golang.org/cl/5576070

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

https://github.com/golang/go/commit/2d13e1f16e4b6709dc98f2cc45d717af8807005a

元コミット内容

このコミットの元の内容は、「build: use correct go-tool directory location」であり、Goのビルドプロセスにおいて、go-toolという内部ツールのディレクトリ位置を正しく使用するように修正することを目的としています。

変更の背景

Go言語のビルドシステムでは、コンパイラやリンカ、プロファイラなどの様々な内部ツールが使用されます。これらのツールは通常、Goのインストールディレクトリ(GOROOT)内の特定の場所に配置され、Goコマンド(go build, go runなど)から内部的に呼び出されます。

以前の実装では、これらの内部ツールがGOBIN環境変数によって指定されるディレクトリ、またはbuild.Path[0].BinDir()というGoのビルドパスから導出されるディレクトリに配置されると誤って想定されていました。しかし、GOBINはユーザーがGoの実行可能ファイルをインストールする場所を指定するためのものであり、Goの内部ツールが配置されるべき場所ではありません。また、build.Path[0].BinDir()の挙動が、内部ツールの実際の配置場所と一致しないケースがあった可能性があります。

この不整合により、Goのビルドプロセスが内部ツールを見つけられず、ビルドエラーや予期せぬ動作が発生する可能性がありました。このコミットは、go-toolが常にGOROOT/bin/go-toolという固定された、かつ正しい場所に配置されるように参照パスを修正することで、この問題を解決することを目的としています。

前提知識の解説

  • GOROOT: Go言語のインストールディレクトリを指す環境変数です。Goの標準ライブラリ、ツール、ソースコードなどがこのディレクトリ以下に配置されます。Goのビルドシステムは、GOROOTを基準として内部ツールやライブラリを探します。
  • GOBIN: Goの実行可能ファイル(go installなどでビルドされたバイナリ)がインストールされるディレクトリを指す環境変数です。ユーザーがGoのプログラムをビルドしてパスに追加したい場合などに設定します。GOBINはユーザーがビルドしたプログラムのためのものであり、Go言語自体が提供する内部ツールのためではありません。
  • go-tool: Go言語のビルドシステムが内部的に使用する補助ツールの総称です。これには、go tool compile(コンパイラ)、go tool link(リンカ)、go tool vet(静的解析ツール)、go tool pprof(プロファイラ)などが含まれます。これらのツールはGoのインストール時にGOROOT/pkg/tool/<GOOS_GOARCH>(古いバージョンではGOROOT/bin/go-tool)のようなディレクトリに配置されます。
  • Makefile: ソフトウェアのビルドプロセスを自動化するためのツールであるmakeが使用する設定ファイルです。このファイルには、ソースコードのコンパイル、リンク、インストールなどの手順が記述されます。Goのソースコード内でも、一部のツールのビルドやインストールにMakefileが使用されています。
  • go/buildパッケージ: Go言語の標準ライブラリの一部で、Goのビルド環境に関する情報(GOROOTGOPATHGOOSGOARCHなど)を提供するパッケージです。build.DefaultContextは現在のビルドコンテキストを表し、build.PathはGoのソースコードパスに関する情報を提供します。
  • path/filepathパッケージ: Go言語の標準ライブラリの一部で、ファイルパスの操作(結合、分割、正規化など)を行うための機能を提供するパッケージです。filepath.Joinは、複数のパス要素を結合して、オペレーティングシステムに適した形式のパスを生成します。

技術的詳細

このコミットの技術的な核心は、Goの内部ツール(go-tool)の配置場所を特定し、そのパスを正しく参照するようにビルドスクリプトとGoのソースコードを修正することにあります。

  1. Makefileの修正:

    • src/cmd/cov/Makefilesrc/cmd/prof/Makefileにおいて、install-defaultターゲットのcpコマンドのパスが変更されています。
    • 変更前: cp $(TARG) "$(GOBIN)"/go-tool/$(TARG)
    • 変更後: cp $(TARG) "$(GOROOT)"/bin/go-tool/$(TARG)
    • この変更は、cov(カバレッジツール)とprof(プロファイリングツール)のバイナリをインストールする際に、GOBINではなくGOROOT/bin/go-toolディレクトリにコピーするように指示しています。これは、これらのツールがユーザーがインストールする一般的なGoプログラムではなく、Goシステムの一部として扱われるべきであることを明確にしています。
  2. src/cmd/go/tool.goの修正:

    • このファイルは、go toolコマンドの内部的なロジックを定義しています。
    • 変更前: toolBinToolDir = build.Path[0].BinDir() + "/go-tool"
    • 変更後: toolBinToolDir = filepath.Join(build.Path[0].Path, "bin", "go-tool")
    • この変更は、go toolコマンドが内部ツールを探すためのベースディレクトリtoolBinToolDirの計算方法を修正しています。
      • build.Path[0].BinDir()は、Goのビルドパスの最初の要素(通常はGOROOT)のbinディレクトリを返しますが、その挙動が常にgo-toolの実際の配置場所と一致するとは限りませんでした。
      • filepath.Join(build.Path[0].Path, "bin", "go-tool")は、build.Path[0].Path(通常はGOROOT)とbingo-toolという文字列を結合して、オペレーティングシステムに依存しない形で正しいパスを構築します。これにより、go toolコマンドが内部ツールを確実に発見できるようになります。filepath.Joinを使用することで、パス区切り文字(Windowsの\やUnix系の/)の違いを吸収し、クロスプラットフォームでの互換性を高めています。

これらの変更により、Goのビルドシステム全体でgo-toolの場所に関する一貫性が保たれ、ビルドの信頼性が向上します。

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

src/cmd/cov/Makefile

--- a/src/cmd/cov/Makefile
+++ b/src/cmd/cov/Makefile
@@ -38,4 +38,4 @@ install-darwin: $(TARG)
 	@true
 
 install-default: $(TARG)
-	cp $(TARG) "$(GOBIN)"/go-tool/$(TARG)
+	cp $(TARG) "$(GOROOT)"/bin/go-tool/$(TARG)

src/cmd/go/tool.go

--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -9,6 +9,7 @@ import (
 	"go/build"
 	"os"
 	"os/exec"
+	"path/filepath"
 	"sort"
 	"strings"
 )
@@ -28,7 +29,7 @@ For more about each tool command, see 'go tool command -h'.
 var (
 	toolGoos       = build.DefaultContext.GOOS
 	toolIsWindows  = toolGoos == "windows"
-	toolBinToolDir = build.Path[0].BinDir() + "/go-tool"
+	toolBinToolDir = filepath.Join(build.Path[0].Path, "bin", "go-tool")
 )
 
 const toolWindowsExtension = ".exe"

src/cmd/prof/Makefile

--- a/src/cmd/prof/Makefile
+++ b/src/cmd/prof/Makefile
@@ -32,7 +32,7 @@ install-darwin: $(TARG)
 	@true
 
 install-default: $(TARG)
-	cp $(TARG) "$(GOBIN)"/go-tool/$(TARG)
+	cp $(TARG) "$(GOROOT)"/bin/go-tool/$(TARG)
 
 install-pprof: pprof
-	cp pprof "$(GOBIN)"/go-tool/pprof
+	cp pprof "$(GOROOT)"/bin/go-tool/pprof

コアとなるコードの解説

Makefileの変更 (src/cmd/cov/Makefile, src/cmd/prof/Makefile)

これらのMakefileは、cov(カバレッジツール)とprof(プロファイリングツール)のビルドとインストールを担当しています。install-defaultターゲットは、ビルドされたバイナリをGoのシステムにインストールする際のパスを定義しています。

  • 変更前: cp $(TARG) "$(GOBIN)"/go-tool/$(TARG)
    • これは、ビルドされたターゲット($(TARG))を、GOBIN環境変数で指定されたディレクトリの下のgo-toolサブディレクトリにコピーしようとしていました。しかし、前述の通り、GOBINはユーザーがインストールするGoプログラムのためのものであり、Goの内部ツールが配置されるべき場所ではありません。この誤ったパス指定が、ツールの発見失敗やビルドエラーの原因となる可能性がありました。
  • 変更後: cp $(TARG) "$(GOROOT)"/bin/go-tool/$(TARG)
    • この修正により、ターゲットはGOROOT環境変数で指定されたGoのインストールルートディレクトリの下のbin/go-toolサブディレクトリにコピーされるようになります。これは、Goの内部ツールが標準的に配置されるべき正しい場所であり、Goのビルドシステムがこれらのツールを期待する場所です。これにより、ツールのインストールパスがGoの内部的な期待と一致し、ビルドの信頼性が向上します。

src/cmd/go/tool.goの変更

このファイルは、go toolコマンドがGoの内部ツールを実行する際のロジックを管理しています。特に、toolBinToolDir変数は、go toolコマンドが内部ツールバイナリを探すためのベースディレクトリを定義しています。

  • 変更前: toolBinToolDir = build.Path[0].BinDir() + "/go-tool"
    • build.Path[0]は、Goのビルドパスの最初の要素(通常はGOROOT)を表します。BinDir()メソッドは、そのパスのbinサブディレクトリを返します。したがって、この行はGOROOT/bin"/go-tool"を文字列として連結していました。
    • このアプローチの問題点は、BinDir()の挙動がプラットフォームやGoのバージョンによって微妙に異なる可能性があったこと、また、単なる文字列連結ではパス区切り文字の自動調整が行われないため、クロスプラットフォームでの互換性に問題が生じる可能性があったことです。
  • 変更後: toolBinToolDir = filepath.Join(build.Path[0].Path, "bin", "go-tool")
    • この修正では、path/filepathパッケージのJoin関数が導入されています。
    • build.Path[0].Pathは、GOROOTの絶対パスを文字列として返します。
    • filepath.Joinは、引数として与えられた複数のパス要素を、現在のオペレーティングシステムに適したパス区切り文字を使用して結合し、正規化されたパスを生成します。例えば、Unix系システムでは/、Windowsでは\が使用されます。
    • この変更により、toolBinToolDirは常にGOROOT/bin/go-toolという形式の正しい絶対パスを指すようになり、go toolコマンドが内部ツールを確実に発見できるようになります。これは、パスの構築における堅牢性とクロスプラットフォーム互換性を大幅に向上させます。

関連リンク

参考にした情報源リンク

  • 上記の関連リンクに加えて、Go言語のソースコード自体と、Goのビルドシステムに関する一般的な知識を参考にしました。
  • GOBINGOROOTの役割に関する一般的なGoのチュートリアルやドキュメント。
  • Makefileの基本的な構文とcpコマンドの動作。
  • Goのpath/filepath.Join関数の動作に関するGoのドキュメント。