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

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

このコミットは、Go言語のビルドシステムにおいて、テスト実行前にGOPATH環境変数を解除する変更を導入しています。これは、GOROOT(Goのインストールディレクトリ)がGOPATHの配下にある場合に、非ローカルパッケージに対するローカルインポートが許可されないというGoのビルドルールにより、一部のテストがビルドに失敗する問題を解決するためのものです。

コミット

commit 23322ab841c2d6192557a9a0cae3ace40bff8c9d
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Mar 21 00:47:27 2012 +0800

    build: unset GOPATH before tests
    This is because we disallow local import for non-local packages, if
    GOROOT happens to be under one of GOPATH, then some tests will fail
    to build.
    Fixes #3337.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5852043
---
 src/run.bash | 2 +++
 src/run.bat  | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/src/run.bash b/src/run.bash
index 748f6e93f5..41ab37e3c2 100755
--- a/src/run.bash
+++ b/run.bash
@@ -8,6 +8,8 @@ set -e
 eval $(go env)
 
 unset CDPATH	# in case user has it set
+unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
+                # to be under $GOPATH, then some tests below will fail
 
 # no core files, please
 ulimit -c 0
diff --git a/src/run.bat b/src/run.bat
index 1d5bf60f25..c7a1579728 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -12,6 +12,10 @@ setlocal
 
 set GOBUILDFAIL=0
 
+:: we disallow local import for non-local packages, if %GOROOT% happens
+:: to be under %GOPATH%, then some tests below will fail
+set GOPATH=
+
 rem TODO avoid rebuild if possible
 
 if x%1==x--no-rebuild goto norebuild

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

https://github.com/golang/go/commit/23322ab841c2d6192557a9a0cae3ace40bff8c9d

元コミット内容

build: unset GOPATH before tests
This is because we disallow local import for non-local packages, if
GOROOT happens to be under one of GOPATH, then some tests will fail
to build.
Fixes #3337.

変更の背景

この変更の背景には、Go言語のビルドシステムにおける特定の環境設定とパッケージインポートのルールが関係しています。

Go言語では、GOROOTGOPATHという2つの重要な環境変数があります。

  • GOROOT: GoのSDK(コンパイラ、ツール、標準ライブラリなど)がインストールされているディレクトリを指します。
  • GOPATH: Goのワークスペースのルートディレクトリを指します。ここには、ユーザーが開発するGoのソースコード、ダウンロードされたパッケージ、コンパイルされたバイナリなどが格納されます。

Goのビルドルールには、「非ローカルパッケージに対するローカルインポートを許可しない」というものがあります。ここでいう「ローカルインポート」とは、相対パス(例: ./mypackage)を使ったインポートを指します。一方、「非ローカルパッケージ」とは、標準ライブラリやGOPATH外のモジュールなど、現在のプロジェクトのソースツリーに直接含まれないパッケージを指します。

問題は、開発環境のセットアップによっては、GOROOTが誤ってGOPATHのサブディレクトリとして設定されてしまうケースがあったことです。このような状況下でGoのテストを実行しようとすると、Goのビルドツールは標準ライブラリのパッケージ(これらは非ローカルパッケージと見なされる)を、GOPATH内の相対パスとして解釈しようとします。しかし、Goのルールでは非ローカルパッケージに対するローカルインポートは許可されていないため、ビルドエラーが発生し、テストが失敗するという事態が生じていました。

このコミットは、この問題を解決するために、テストを実行するスクリプト(run.bashrun.bat)において、テスト開始前に明示的にGOPATH環境変数を解除することで、GoのビルドツールがGOROOT内の標準ライブラリを正しく認識し、ビルドエラーを回避するようにしています。コミットメッセージにあるFixes #3337は、Goの内部的な課題追跡システムにおける特定のバグ報告に対応するものであると考えられます。

前提知識の解説

Goの環境変数: GOROOTGOPATH

  • GOROOT: Goのインストールパスです。Goのコンパイラ、標準ライブラリ、ツールなどがこのディレクトリに格納されています。通常、ユーザーが手動で設定する必要はありませんが、複数のGoバージョンを切り替える場合などに設定することがあります。
  • GOPATH: Goのワークスペースのルートパスです。Go 1.11でGo Modulesが導入される以前は、Goのプロジェクトは必ず$GOPATH/src以下に配置する必要がありました。Go Modules導入後も、go getでダウンロードされるパッケージや、go installで生成されるバイナリはGOPATH配下に格納されます。GOPATHは複数のパスを設定することも可能で、Goツールはこれらのパスを順に検索します。

Goのパッケージインポートルール

Goのパッケージインポートには、主に以下の2種類があります。

  1. 絶対パスインポート: fmtnet/httpgithub.com/user/repo/packageのように、パッケージの完全なインポートパスを指定する方法です。Goツールは、GOROOTGOPATH、またはGo Modulesのキャッシュからこれらのパッケージを探します。
  2. 相対パスインポート: ./mypackage../anotherpackageのように、現在のファイルからの相対パスでパッケージを指定する方法です。これは、通常、同じモジュール内または同じGOPATHワークスペース内のローカルパッケージをインポートする場合にのみ使用されます。

Goのビルドルールでは、非ローカルパッケージ(つまり、現在のモジュールやGOPATHワークスペースに属さない外部パッケージや標準ライブラリ)を相対パスでインポートすることは許可されていません。これは、インポートパスの曖昧さをなくし、ビルドの再現性を高めるための重要な制約です。

ビルドとテストのプロセス

Goプロジェクトのビルドやテストは、go buildgo testコマンドによって行われます。これらのコマンドは、Goの環境変数(特にGOROOTGOPATH)を参照して、ソースコードの場所、依存関係、およびコンパイル済みバイナリの出力先を決定します。

技術的詳細

このコミットが解決しようとしている問題は、GoのビルドシステムがGOPATHGOROOTの特定の関係性によって誤動作するという、環境設定に起因するものです。

具体的には、もしGOROOT(例: /usr/local/go)がGOPATH(例: /home/user/go)のサブディレクトリとして設定されてしまった場合(例: /home/user/go/goのような不適切な設定)、Goのビルドツールは混乱します。Goの標準ライブラリ(fmt, net/httpなど)はGOROOT内に存在しますが、GOPATHが設定されていると、GoツールはまずGOPATH配下でパッケージを探そうとします。

この時、Goのビルドツールは、標準ライブラリのパッケージをGOPATH内の相対パスとして解釈しようとする可能性があります。例えば、fmtパッケージをインポートする際に、GOPATHが設定されていると、Goツールは$GOPATH/src/fmtのようなパスを探索しようとします。しかし、fmtは標準ライブラリであり、GOROOT内に存在するため、これは「非ローカルパッケージ」に該当します。Goのルールでは、非ローカルパッケージを相対パスでインポートすることは許可されていないため、この状況下でビルドエラーが発生します。

このコミットは、テスト実行前にGOPATHを一時的に解除することで、この問題を回避します。GOPATHが解除されると、Goツールは標準ライブラリの探索においてGOROOTを優先的に参照するようになります。これにより、標準ライブラリが非ローカルパッケージとして正しく認識され、相対パスでのインポート試行によるビルドエラーが回避され、テストが正常に実行できるようになります。

この変更は、Goのビルドスクリプト(run.bashrun.bat)に直接行われているため、Goのソースコードをビルド・テストする際の環境設定に影響を与えます。これは、Goの開発者がGo自身のテストを実行する際の安定性を確保するために重要な修正です。

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

diff --git a/src/run.bash b/src/run.bash
index 748f6e93f5..41ab37e3c2 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -8,6 +8,8 @@ set -e
 eval $(go env)
 
 unset CDPATH	# in case user has it set
+unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
+                # to be under $GOPATH, then some tests below will fail
 
 # no core files, please
 ulimit -c 0
diff --git a/src/run.bat b/src/run.bat
index 1d5bf60f25..c7a1579728 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -12,6 +12,10 @@ setlocal
 
 set GOBUILDFAIL=0
 
+:: we disallow local import for non-local packages, if %GOROOT% happens
+:: to be under %GOPATH%, then some tests below will fail
+set GOPATH=
+
 rem TODO avoid rebuild if possible
 
 if x%1==x--no-rebuild goto norebuild

コアとなるコードの解説

このコミットは、Goのビルドおよびテスト実行に使用されるシェルスクリプト(src/run.bash)とバッチスクリプト(src/run.bat)に、それぞれ1行の変更とコメントの追加を行っています。

src/run.bash (Unix/Linux/macOS向けシェルスクリプト)

unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
                # to be under $GOPATH, then some tests below will fail
  • unset GOPATH: このコマンドは、現在のシェルセッションからGOPATH環境変数を解除します。これにより、Goのビルドツールは、テスト実行中にGOPATHの値を参照しなくなります。
  • コメント: GOPATHを解除する理由が明確に説明されています。「非ローカルパッケージに対するローカルインポートを許可しない」というGoのルールと、GOROOTGOPATHの配下にある場合にテストが失敗する可能性が指摘されています。

src/run.bat (Windows向けバッチスクリプト)

set GOPATH=
  • set GOPATH=: このコマンドは、WindowsのバッチファイルにおいてGOPATH環境変数を空文字列に設定することで、実質的にGOPATHを解除します。Unix系のunsetコマンドと同様の効果があります。
  • コメント: シェルスクリプトと同様に、GOPATHを解除する理由が説明されています。

これらの変更により、Goのテストが実行される前にGOPATHが確実に解除されるため、GOROOTGOPATHの間の潜在的な競合が解消され、テストのビルドが安定して行われるようになります。これは、Goのビルドシステムの堅牢性を高めるための重要な修正です。

関連リンク

参考にした情報源リンク