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

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

このコミットは、Go言語のテストスイートの一部である test/run.go における、Windows環境での compiledir テストの不具合を修正するものです。具体的には、Windowsで発生する「import path contains invalid character ':'」エラーを回避するために、go tool gc コマンドに -D.-I. オプションを追加しています。

コミット

commit 8dbeb0ad072354e84463f38aef790cc1d69352e2
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Jul 31 23:26:33 2012 -0400

    test/run.go: fix compiledir test on windows
        we can't import "./bug0" on windows, as it will trigger
    "import path contains invalid character ':'" error.
        instead, we pass "-D." and "-I." to gc to override this
    behavior. this idea is due to remyoudompheng.
    
    R=golang-dev, r, alex.brainman, remyoudompheng
    CC=golang-dev
    https://golang.org/cl/6441074

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

https://github.com/golang/go/commit/8dbeb0ad072354e84463f38aef790cc1d69352e2

元コミット内容

test/run.go: Windows上での compiledir テストを修正。 Windowsでは "./bug0" のようなインポートパスが「import path contains invalid character ':'」エラーを引き起こすため、インポートできません。 代わりに、この挙動を上書きするために gc-D.-I. を渡します。このアイデアはremyoudomphengによるものです。

変更の背景

Go言語のテストスイートには、特定のディレクトリ内のGoファイルをコンパイルする compiledir テストがあります。このテストは、Goのコンパイラ(gc)が正しく動作するかを確認するために重要です。しかし、Windows環境において、相対パスで指定されたインポート(例: "./bug0")が問題を引き起こしていました。

Windowsのファイルシステムでは、ドライブレター(例: C:)がパスの先頭に現れることが一般的です。Goのコンパイラは、インポートパスを解析する際に、このコロン(:)を特殊な文字として解釈し、不正な文字が含まれていると判断してしまうことがありました。結果として、「import path contains invalid character ':'」というエラーが発生し、compiledir テストがWindows上で失敗していました。

この問題は、Goのビルドシステムが内部的に使用するパスの表現と、Windowsのパス表現との間のミスマッチに起因していました。テストが異なるOS環境で一貫して動作するようにするためには、このWindows固有のパス解決の問題に対処する必要がありました。

前提知識の解説

Go言語のパッケージとインポートパス

Go言語では、コードはパッケージにまとめられ、他のパッケージの機能を利用するには import ステートメントを使用します。インポートパスは、Goのワークスペース(GOPATH)やモジュールパスからの相対パス、または標準ライブラリのパスなど、Goコンパイラがパッケージを見つけるための識別子です。

例:

  • "fmt": 標準ライブラリの fmt パッケージ
  • "github.com/user/repo/mypackage": リモートリポジトリのパッケージ
  • "./localpackage": 現在のディレクトリからの相対パスにあるローカルパッケージ

go tool gc

go tool gc は、Go言語のコンパイラ(gc は "Go compiler" の略)を直接呼び出すためのコマンドです。通常、Goプログラムのビルドは go buildgo run コマンドを通じて行われますが、これらのコマンドは内部的に go tool gc を呼び出しています。go tool gc は、Goソースファイルをコンパイルしてオブジェクトファイルを生成する役割を担います。

gc コマンドのオプション (-D, -I)

go tool gc には、コンパイルの挙動を制御するための様々なオプションがあります。このコミットで重要なのは以下の2つです。

  • -D path (Directory for imports): このオプションは、コンパイラがインポートパスを解決する際に検索するディレクトリを指定します。通常、Goコンパイラは GOPATHGOROOT、Goモジュールのキャッシュなど、いくつかの標準的な場所を検索します。-D オプションを使用すると、これらの標準的な検索パスに加えて、指定された path もインポートの解決に使用されるようになります。このコミットでは -D. が使用されており、これは「現在のディレクトリ」をインポートパスの検索対象に追加することを意味します。

  • -I path (Import directory): このオプションもインポートパスの解決に関連しますが、より具体的には、コンパイル時に必要なパッケージのアーカイブファイル(.a ファイルなど)が置かれているディレクトリを指定します。Goコンパイラは、依存するパッケージのコンパイル済みバイナリをこのディレクトリから探します。このコミットでは -I. が使用されており、これも「現在のディレクトリ」をインポートディレクトリとして指定することを意味します。

これらのオプションは、Goコンパイラが特定のパスをどのように解釈し、どこからインポートされたパッケージを探すかという挙動を上書きするために使用されます。

技術的詳細

Windows環境における「import path contains invalid character ':'」エラーは、Goコンパイラが相対パス(例: ./bug0)を絶対パスに解決しようとする際に、Windowsのドライブレター(例: C:)と混同してしまうことに起因していました。Goコンパイラは、Unix系のパス表現に慣れており、コロン(:)をパスの区切り文字や特殊な意味を持つ文字として解釈することがあります。Windowsのパスにおけるドライブレターのコロンは、Goコンパイラのこの解釈と衝突し、エラーを引き起こしていました。

この問題を解決するために、コミットでは go tool gc コマンドに -D.-I. オプションを追加しています。

  • go tool gc -e -D. -I. -o afile filepath.Join(longdir, gofile.Name())

この変更のポイントは以下の通りです。

  1. -D. の追加: go tool gc-D. オプションを渡すことで、コンパイラはインポートパスを解決する際に、現在の作業ディレクトリ(.)をインポートの検索パスとして考慮するようになります。これにより、./bug0 のような相対インポートパスが、Windowsのドライブレターの問題に遭遇することなく、現在のディレクトリからの相対パスとして正しく解決される可能性が高まります。

  2. -I. の追加: 同様に、-I. オプションは、コンパイル済みのパッケージファイル(.a ファイルなど)を探すディレクトリとして現在の作業ディレクトリを指定します。これは、compiledir テストが一時ディレクトリ内でコンパイルを行う際に、そのディレクトリ内で生成された中間ファイルやパッケージを正しく参照できるようにするために重要です。

これらのオプションを組み合わせることで、GoコンパイラはWindows環境下でも相対インポートパスを正しく解釈し、テストが期待通りに動作するようになります。この解決策は、Goコンパイラの内部的なパス解決ロジックを直接変更するのではなく、外部からコンパイラの挙動を制御するオプションを利用することで、Windows固有のパス問題を回避するというアプローチを取っています。

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

--- a/test/run.go
+++ b/test/run.go
@@ -172,7 +172,7 @@ type test struct {
  	donec       chan bool // closed when done
 
  	src    string
- 	action string // "compile", "build", "run", "errorcheck", "skip", "runoutput"
+ 	action string // "compile", "build", "run", "errorcheck", "skip", "runoutput", "compiledir"
 
  	tempDir string
  	err     error
@@ -315,7 +315,7 @@ func (t *test) run() {
  		}
  		for _, gofile := range files {
  			afile := strings.Replace(gofile.Name(), ".go", "."+letter, -1)
- 			out, err := runcmd("go", "tool", gc, "-e", "-o", afile, filepath.Join(longdir, gofile.Name()))
+ 			out, err := runcmd("go", "tool", gc, "-e", "-D.", "-I.", "-o", afile, filepath.Join(longdir, gofile.Name()))
  			if err != nil {
  				t.err = fmt.Errorf("%s\\n%s", err, out)
  				break

コアとなるコードの解説

このコミットでは、test/run.go ファイルの2箇所が変更されています。

  1. action フィールドのコメント更新:

    - 	action string // "compile", "build", "run", "errorcheck", "skip", "runoutput"
    + 	action string // "compile", "build", "run", "errorcheck", "skip", "runoutput", "compiledir"
    

    test 構造体の action フィールドのコメントに "compiledir" が追加されました。これは、このコミットが compiledir テストに関連する修正であることを明確にするためのドキュメンテーション上の変更です。コードの動作には直接影響しませんが、可読性と保守性を向上させます。

  2. runcmd 関数の引数変更:

    - 			out, err := runcmd("go", "tool", gc, "-e", "-o", afile, filepath.Join(longdir, gofile.Name()))
    + 			out, err := runcmd("go", "tool", gc, "-e", "-D.", "-I.", "-o", afile, filepath.Join(longdir, gofile.Name()))
    

    これがこのコミットの主要な変更点です。runcmd 関数は、外部コマンドを実行するためのヘルパー関数です。ここでは go tool gc コマンドを実行しています。

    変更前は、go tool gc には -e-o オプションのみが渡されていました。

    • -e: エラーが発生してもコンパイルを続行する(警告などを表示するため)。
    • -o afile: 出力ファイル名を afile に指定。

    変更後、これらのオプションに加えて -D.-I. が追加されました。

    • -D.: インポートパスの検索ディレクトリとして現在のディレクトリ(.)を追加。
    • -I.: コンパイル済みパッケージの検索ディレクトリとして現在のディレクトリ(.)を追加。

    この変更により、go tool gc はWindows環境で相対インポートパスを正しく解決できるようになり、compiledir テストが期待通りに動作するようになりました。filepath.Join(longdir, gofile.Name()) は、コンパイル対象のGoファイルの絶対パスを生成しています。

関連リンク

参考にした情報源リンク

  • Go Command Documentation (go tool gc): https://pkg.go.dev/cmd/go#hdr-Go_tool_commands (一般的な go tool コマンドに関する情報)
  • Go issue tracker (関連する可能性のある問題): https://github.com/golang/go/issues (具体的な問題番号はコミットメッセージにないため、一般的な検索が必要)
  • Stack Overflow や Go フォーラムでの議論 (GoのインポートパスやWindowsでの問題に関する一般的な情報): (特定のURLは特定できないが、一般的な知識として参照)
  • Go言語のソースコード (test/run.go の歴史): https://github.com/golang/go/blob/master/test/run.go (現在のファイルと比較することで、時間の経過とともにどのように進化してきたかを確認できる)
  • Go言語のコンパイラオプションに関する情報 (gc flags): https://go.dev/doc/go1.4#gc (Go 1.4のリリースノートだが、gcのオプションに関する基本的な情報が含まれている可能性がある)
  • Go言語のビルドシステムに関するブログ記事やドキュメント (Goのビルドプロセスに関する一般的な理解): (特定のURLは特定できないが、一般的な知識として参照)
  • Windowsのパスに関するMicrosoftのドキュメント (Windowsのパスの挙動に関する一般的な情報): (特定のURLは特定できないが、一般的な知識として参照)
  • Go言語のテストに関するドキュメント: https://go.dev/doc/code#Testing (Goのテストの一般的な方法に関する情報)