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

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

このコミットは、Goコンパイラの字句解析器(cmd/gc/lex.c)におけるバグ修正です。具体的には、Windows環境において、インポートパスがスラッシュ(/)で始まる場合のローカルパス判定ロジックが誤っていた問題を修正しています。これにより、Windows上でのGoパッケージのインポートに関する挙動が改善されました。

コミット

  • コミットハッシュ: 29199aa4e49a49c19b1169f60c62a7944baa8706
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2012年3月10日 土曜日 05:11:51 +0800

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

https://github.com/golang/go/commit/29199aa4e49a49c19b1169f60c62a7944baa8706

元コミット内容

cmd/gc: import path cannot start with slash on Windows
        For CL 5756065.

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

変更の背景

Go言語では、パッケージのインポートパスは通常、Unixライクなスラッシュ(/)区切りで記述されます。しかし、Windowsオペレーティングシステムでは、ファイルパスの区切り文字としてバックスラッシュ(\)が一般的に使用され、ドライブレター(例: C:\)から始まるパスも存在します。

このコミットが行われる前は、Goコンパイラの字句解析器(cmd/gc/lex.c)内のislocalname関数が、インポートパスがスラッシュで始まる場合に、それがローカルパスであるかどうかを判定する際に、Windows環境では常にfalseを返していました。これは、!windowsという条件が誤って含まれていたためです。

結果として、Windows上でスラッシュから始まるインポートパス(例: /path/to/package)を持つパッケージをコンパイルしようとすると、コンパイラがそのパスを正しくローカルパスとして認識できず、ビルドエラーや予期せぬ動作を引き起こす可能性がありました。このコミットは、このWindows環境におけるパス解決の不整合を解消し、Goのクロスプラットフォーム互換性を向上させることを目的としています。

前提知識の解説

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

Go言語では、importキーワードを使用して他のパッケージの機能を利用します。インポートパスは、通常、Goモジュールのルートからの相対パス、またはGo標準ライブラリのパッケージ名(例: fmt, net/http)で指定されます。Goのツールチェインは、これらのパスを解決して、対応するソースコードを見つけ出します。

WindowsとUnix系OSのファイルパスの違い

  • Unix系OS (Linux, macOSなど): ファイルパスの区切り文字はスラッシュ(/)です。絶対パスはルートディレクトリを示すスラッシュ(/)から始まります(例: /home/user/file.txt)。
  • Windows OS: ファイルパスの区切り文字はバックスラッシュ(\)が一般的ですが、スラッシュ(/)も多くのAPIで許容されます。絶対パスは通常、ドライブレター(例: C:)から始まり、その後に区切り文字が続きます(例: C:\Users\user\file.txt)。ネットワークパスは\\server\shareのような形式を取ります。

Go言語のソースコード内では、パスは一貫してスラッシュ区切りで記述されることが推奨されますが、コンパイラやランタイムは実行環境のOSのパス規則に合わせて内部的に変換を行う必要があります。

cmd/gcの役割

cmd/gcは、Go言語の公式コンパイラのフロントエンド部分です。Goのソースコードを解析し、中間表現に変換し、最終的に実行可能なバイナリを生成するプロセスの一部を担います。このコンテキストでは、特にソースコード内のimport文を解析し、対応するパッケージの場所を特定する役割が重要です。

src/cmd/gc/lex.cの役割

lex.cファイルは、Goコンパイラの字句解析器(lexer)の一部を実装しています。字句解析器は、ソースコードをトークン(キーワード、識別子、演算子など)のストリームに分解する役割を担います。このファイルには、ファイルパスやインポートパスの処理に関連するユーティリティ関数も含まれており、islocalname関数もその一つです。islocalnameは、与えられたパスがローカルファイルシステム上のパスであるかどうかを判定するために使用されます。

技術的詳細

このコミットの核心は、src/cmd/gc/lex.c内のislocalname関数の条件式から、!windowsという部分を削除した点にあります。

変更前のislocalname関数内の関連する条件式は以下の通りでした。

if(!windows && name->len >= 1 && name->s[0] == '/')
    return 1;

この条件式は、「windowsfalse(つまりUnix系OSである)かつパスの長さが1以上で、最初の文字がスラッシュ(/)である」場合にtrueを返していました。これは、Unix系OSではスラッシュから始まるパスが絶対パス(ローカルパス)であることを正しく判定するためのロジックです。

しかし、Go言語のインポートパスは、OSに関わらずスラッシュ区切りで記述されるという慣習があります。例えば、Goモジュール内のサブパッケージをインポートする場合、./mypackageのように相対パスで指定することもできますが、github.com/user/repo/mypackageのようにリポジトリのルートからの相対パスをスラッシュ区切りで指定するのが一般的です。

問題は、Windows環境においても、Goの内部処理でスラッシュから始まるパスをローカルパスとして扱う必要があるケースが存在するにも関わらず、上記の条件式が!windowsによって常にfalseと評価されてしまっていた点です。これにより、Windows上でスラッシュから始まるインポートパスが正しくローカルパスとして認識されず、コンパイラがパッケージを見つけられないなどの問題が発生していました。

変更後の条件式は以下の通りです。

if(name->len >= 1 && name->s[0] == '/')
    return 1;

!windowsが削除されたことで、この条件式はOSの種類に関わらず、「パスの長さが1以上で、最初の文字がスラッシュ(/)である」場合にtrueを返すようになりました。これにより、Windows環境でもスラッシュから始まるインポートパスが正しくローカルパスとして扱われるようになり、Goのクロスプラットフォームなパス解決の整合性が保たれました。

この修正は、Goコンパイラがインポートパスを解釈する際の基本的な挙動に影響を与え、特にWindows上での開発体験を向上させるものです。

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

--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -514,7 +514,7 @@ addidir(char* dir)
 static int
 islocalname(Strlit *name)
 {
-	if(!windows && name->len >= 1 && name->s[0] == '/')
+	if(name->len >= 1 && name->s[0] == '/')
 		return 1;
 	if(windows && name->len >= 3 &&
 	   yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')

コアとなるコードの解説

変更はsrc/cmd/gc/lex.cファイル内のislocalname関数にあります。

islocalname関数は、与えられた文字列(Strlit *name)がローカルファイルシステム上の名前(パス)であるかどうかを判定します。

変更前のコード:

if(!windows && name->len >= 1 && name->s[0] == '/')
    return 1;

この行は、Goコンパイラが動作している環境がWindowsではない場合(!windowsが真の場合)にのみ、パスがスラッシュで始まるかどうかをチェックしていました。これは、Unix系システムではスラッシュから始まるパスが絶対パスであることを意味するため、理にかなっています。しかし、GoのインポートパスはOSに関わらずスラッシュ区切りで表現されるため、Windows環境でもスラッシュから始まるパスをローカルパスとして認識する必要がある場合がありました。この!windowsという条件が、Windows上でのこの種のパスの正しい認識を妨げていました。

変更後のコード:

if(name->len >= 1 && name->s[0] == '/')
    return 1;

!windowsという条件が削除されました。これにより、この条件式はGoコンパイラが動作しているOSに関わらず、パスがスラッシュ(/)で始まる場合にtrueを返すようになりました。この修正によって、Windows環境においても、Goのインポートパスがスラッシュから始まる場合に、それが正しくローカルパスとして扱われるようになり、コンパイラがパッケージを適切に解決できるようになりました。

この変更は、Go言語のクロスプラットフォームな設計思想に沿ったものであり、Windows上でのGo開発におけるパス解決の堅牢性を高めるものです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント(パッケージとインポートに関する一般的な情報)
  • WindowsおよびUnix系OSのファイルパスに関する一般的な知識
  • Goコンパイラの内部構造に関する一般的な知識 (特にcmd/gcの役割)

(注: 上記の情報源は、この解説を生成するにあたり、一般的な知識として参照したものであり、特定のURLを指すものではありません。)