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

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

このコミットは、Go言語のビルドシステム (go/buildパッケージ) において、Windows環境で(*Tree).BinDir()メソッドが返すパスにスラッシュ (/) が含まれないように修正するものです。具体的には、GOBIN環境変数の値が設定されている場合に、filepath.Clean()関数を使用してパスを正規化することで、Windowsにおけるパスの互換性問題を解決しています。

コミット

commit 102c1a7c961c503379cdfe09476fa26662792c77
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Fri Dec 23 09:46:30 2011 +1100

    go/build: (*Tree).BinDir should not return path with / in it on windows

    R=rsc
    CC=golang-dev
    https://golang.org/cl/5502064

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

https://github.com/golang/go/commit/102c1a7c961c503379cdfe09476fa26662792c77

元コミット内容

go/build: (*Tree).BinDir should not return path with / in it on windows

R=rsc
CC=golang-dev
https://golang.org/cl/5502064

変更の背景

Go言語のビルドシステムは、コンパイルされたバイナリが配置されるディレクトリを決定するために、go/buildパッケージ内の(*Tree).BinDir()メソッドを使用します。Windowsオペレーティングシステムでは、ファイルパスの区切り文字としてバックスラッシュ (\) が一般的に使用されますが、Unix系システムではスラッシュ (/) が使用されます。

このコミットが行われる前は、GOBIN環境変数が設定されている場合、(*Tree).BinDir()メソッドはGOBINの値をそのまま返していました。もしGOBINの値がスラッシュ (/) を含むパス形式で設定されていた場合、Windows環境でそのパスが正しく解釈されず、ビルドされた実行ファイルの配置や、それらの実行ファイルへのパス解決に問題が生じる可能性がありました。例えば、シェルスクリプトや他のプログラムがWindowsのパス形式を期待している場合、スラッシュを含むパスは予期せぬエラーを引き起こすことがあります。

この問題に対処するため、GOBINから取得したパスをWindowsに適した形式に正規化する必要がありました。

前提知識の解説

  • Go言語のgo/buildパッケージ: Go言語の標準ライブラリの一部であり、Goのソースコードのビルドプロセスを管理するための機能を提供します。これには、パッケージの解決、ソースファイルの検索、ビルドディレクトリの決定などが含まれます。go buildコマンドの内部で利用される基盤的なパッケージです。
  • (*Tree).BinDir()メソッド: go/buildパッケージ内のTree構造体(ビルドツリーを表す)のメソッドで、Goのバイナリがインストールされるディレクトリのパスを返します。このパスは、go installコマンドなどで生成された実行ファイルが配置される場所を指します。
  • Windowsにおけるパスの表現: Windowsでは、ディレクトリの区切り文字としてバックスラッシュ (\) が慣例的に使用されます(例: C:\Program Files\Go\bin)。しかし、多くのプログラミング言語やツールでは、クロスプラットフォーム互換性のためにスラッシュ (/) もサポートされています。Go言語のpath/filepathパッケージは、OS固有のパス区切り文字を抽象化し、クロスプラットフォームで動作するように設計されています。
  • GOBIN環境変数: Go言語の環境変数の一つで、go installコマンドでビルドされた実行可能ファイルがインストールされるディレクトリを指定します。この変数が設定されていない場合、デフォルトで$GOPATH/binまたは$GOROOT/binにインストールされます。
  • filepath.Clean()関数: Go言語のpath/filepathパッケージに含まれる関数です。この関数は、与えられたパス文字列を「クリーン」な形式に正規化します。具体的には、以下の処理を行います。
    • 冗長な区切り文字(例: //)を単一の区切り文字に変換します。
    • .(現在のディレクトリ)を削除します。
    • ..(親ディレクトリ)を解決します。
    • OS固有のパス区切り文字(Windowsでは\、Unix系では/)を考慮して、パスを正規化します。 filepath.Cleanはパス文字列を字句的に変換するだけであり、ファイルシステム上にそのパスが存在するかどうかは確認しません。

技術的詳細

このコミットの技術的な核心は、Windows環境におけるパスの正規化です。Goのpath/filepathパッケージは、OSに依存しないパス操作を提供しますが、特にfilepath.Clean関数は、パスの冗長性を排除し、OSの慣習に合わせた形式に変換する上で非常に重要です。

変更前は、(*Tree).BinDir()メソッド内でGOBIN環境変数の値が直接返されていました。もしユーザーがGOBINを例えばC:/Go/binのようにスラッシュ区切りで設定していた場合、Windowsシステムではこのパスが問題を引き起こす可能性がありました。Windowsの多くのAPIやシェルコマンドは、バックスラッシュ区切りのパスを期待するため、スラッシュ区切りのパスが渡されると、ファイルが見つからない、または不正なパスとして扱われるなどのエラーが発生することがあります。

filepath.Clean()関数を適用することで、この問題が解決されます。filepath.Clean()は、入力されたパス文字列を解析し、現在のオペレーティングシステムに適した形式に変換します。Windows上で実行された場合、C:/Go/binのようなパスはC:\Go\binのようにバックスラッシュ区切りに変換され、冗長なスラッシュや...などの要素も適切に処理されます。これにより、GOBINの値がどのような形式で設定されていても、BinDir()が常にWindowsで正しく機能するパスを返すことが保証されます。

この修正は、GoのビルドシステムがWindows環境でより堅牢に動作するために不可欠であり、クロスプラットフォーム互換性を高める上で重要な役割を果たしています。

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

--- a/src/pkg/go/build/path.go
+++ b/src/pkg/go/build/path.go
@@ -57,7 +57,7 @@ func (t *Tree) PkgDir() string {
 func (t *Tree) BinDir() string {
 	if t.Goroot {
 		if gobin := os.Getenv("GOBIN"); gobin != "" {
-			return gobin
+			return filepath.Clean(gobin)
 		}
 	}
 	return filepath.Join(t.Path, "bin")

コアとなるコードの解説

変更はsrc/pkg/go/build/path.goファイルのBinDir()メソッド内で行われています。

  • 変更前:

    if gobin := os.Getenv("GOBIN"); gobin != "" {
        return gobin
    }
    

    このコードは、GOBIN環境変数が設定されている場合、その値をそのまま返していました。

  • 変更後:

    if gobin := os.Getenv("GOBIN"); gobin != "" {
        return filepath.Clean(gobin)
    }
    

    変更後では、GOBIN環境変数の値を取得した後、filepath.Clean(gobin)を呼び出しています。これにより、GOBINの値がどのような形式であっても、filepath.Cleanがそのパスを正規化し、現在のオペレーティングシステム(特にWindows)に適したクリーンな形式に変換してから返すようになります。

この一箇所の変更により、Windows環境でGOBINがスラッシュを含むパスで設定されていた場合に発生しうる、パス解決の不具合が解消されました。

関連リンク

参考にした情報源リンク