[インデックス 14137] ファイルの概要
このコミットは、Go言語のビルドツールである cmd/dist
における、誤解を招く可能性のあるメッセージの修正と、デバッグを容易にするための make.bat
スクリプトの改善を目的としています。具体的には、GOROOT
と GOROOT_FINAL
が異なる場合に表示される「バイナリがコピーまたは移動されることを期待しています」というメッセージが、ファイルシステム上の実体が同じであるにも関わらず表示される問題を解決します。また、cmd/dist
のデバッグを支援するため、make.bat
が --dist-tool
フラグをサポートするように変更されています。
コミット
commit 19dc7bb18fc4e4dab937ce13d50a86db938ab744
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Fri Oct 12 13:35:05 2012 +0800
cmd/dist: fix superfluous and confusing "binaries ... to be copied or moved" message
Also, to aid debugging cmd/dist, make make.bat support --dist-tool flag.
Fixes #3100.
R=alex.brainman
CC=golang-dev
https://golang.org/cl/6637061
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/19dc7bb18fc4e4dab937ce13d50a86db938ab744
元コミット内容
cmd/dist
: 不要で紛らわしい「バイナリがコピーまたは移動されることを期待しています」というメッセージを修正。
また、cmd/dist
のデバッグを支援するため、make.bat
が --dist-tool
フラグをサポートするように変更。
Go Issue #3100 を修正。
変更の背景
Go言語のビルドプロセスにおいて、cmd/dist
ツールはGoのソースコードからバイナリをビルドし、適切な場所に配置する役割を担っています。このツールは、ビルド時に GOROOT
(Goのソースコードのルートディレクトリ) と GOROOT_FINAL
(最終的にGoのバイナリが配置されるディレクトリ) という2つのパスを扱います。
以前のバージョンでは、GOROOT
と GOROOT_FINAL
が文字列として異なる場合、たとえそれらがファイルシステム上で同じ場所を指していても(例えば、シンボリックリンクや異なるパス表記のため)、cmd/dist
は「The binaries expect %s to be copied or moved to %s」(バイナリは %s から %s へコピーまたは移動されることを期待しています)というメッセージを表示していました。このメッセージは、実際にファイルが移動される必要がない場合に表示されるため、ユーザーにとって紛らわしく、誤解を招くものでした。
この問題は Go Issue #3100 として報告されており、このコミットはその修正を目的としています。根本的な原因は、パスの文字列比較 streq(goroot_final, goroot)
が、ファイルシステム上の同一性を正確に判断できないことにありました。
また、cmd/dist
のデバッグは、その性質上、ビルドプロセス全体に影響を与えるため、困難な場合があります。このコミットは、make.bat
に --dist-tool
フラグを追加することで、cmd/dist
ツール自体をビルドディレクトリにコピーし、デバッグを容易にするためのメカニズムを提供します。
前提知識の解説
cmd/dist
: Go言語のソースコードからGoツールチェイン(コンパイラ、リンカ、標準ライブラリなど)をビルドするための内部ツールです。Goの自己ホスト型コンパイラ(GoでGoをコンパイルする)のブートストラッププロセスにおいて重要な役割を果たします。GOROOT
: Goのソースコードが置かれているディレクトリのパスを示す環境変数です。Goのビルドシステムはこのパスを基にソースファイルを探します。GOROOT_FINAL
: ビルドされたGoのバイナリやライブラリが最終的に配置されるディレクトリのパスです。通常、GOROOT
と同じか、Goがインストールされるシステム全体のパス(例:/usr/local/go
)になります。- ファイルシステムの同一性: ファイルシステムにおいて、異なるパス表記(例:
/a/b/c
と/a/./b/c
、またはシンボリックリンクを介したパス)が、実際には同じファイルやディレクトリを指すことがあります。このような場合、文字列比較だけでは同一性を判断できません。ファイルシステム上の同一性を確認するには、ファイル記述子やinode番号などの低レベルな情報を使用する必要があります。 make.bat
: Windows環境でGoのビルドプロセスを制御するためのバッチスクリプトです。Unix/Linux環境におけるmake.bash
やall.bash
に相当します。- Go Issue #3100: このコミットが修正するGoのバグトラッカー上の課題です。
技術的詳細
このコミットの主要な技術的変更点は、ファイルシステム上の同一性を判断するための新しい関数 xsamefile
の導入と、make.bat
スクリプトの機能拡張です。
-
xsamefile
関数の導入:- この関数は、2つのパス
f1
とf2
がファイルシステム上で同じファイルまたはディレクトリを指しているかどうかを判定します。 - Unix/Plan 9 環境: これらの環境では、
xsamefile
は単純に文字列比較streq(f1, f2)
を行います。これは、これらのシステムではパスの正規化が比較的単純であり、シンボリックリンクなどの複雑なケースがこの文脈では問題にならないか、またはより高レベルで処理されるためと考えられます。コメントには「suffice for now」(今のところこれで十分)とあり、将来的に必要であればより堅牢な実装に置き換える可能性が示唆されています。 - Windows 環境: Windowsではパスの表現がより複雑であり、シンボリックリンクやジャンクションポイント、大文字小文字の区別など、ファイルシステムの同一性を判断するのが難しい場合があります。そのため、Windows版の
xsamefile
はより高度なロジックを実装しています。CreateFileW
を使用して、両方のパスに対してファイルハンドルを取得します。FILE_FLAG_BACKUP_SEMANTICS
フラグは、ディレクトリに対してもハンドルを取得できるようにするために使用されます。GetFileInformationByHandle
を使用して、各ファイルハンドルのファイル情報を取得します。この情報には、ボリュームシリアル番号 (dwVolumeSerialNumber
)、ファイルインデックスの上位 (nFileIndexHigh
)、およびファイルインデックスの下位 (nFileIndexLow
) が含まれます。- これらの3つの値が両方のファイルで一致する場合、それらは同じファイルシステム上の同じ実体を指していると判断されます。これは、Windowsにおけるファイルシステム上の同一性を判断する標準的な方法です。
- エラーハンドリングも含まれており、ファイルハンドルが取得できない場合(例: ファイルが存在しない)は
0
(異なるファイル)を返します。
- この関数は、2つのパス
-
cmd/dist/build.c
の変更:cmdbanner
関数内で、GOROOT_FINAL
とGOROOT
の比較にstreq
の代わりに新しく導入されたxsamefile
が使用されるようになりました。- これにより、パスの文字列が異なっていても、ファイルシステム上で同じ場所を指している場合には、紛らわしいメッセージが表示されなくなります。
-
src/make.bat
の変更:--dist-tool
という新しいコマンドライン引数が追加されました。make.bat
が--dist-tool
フラグを受け取ると、cmd/dist/dist.exe
をGOTOOLDIR
(Goツールが配置されるディレクトリ) にコピーします。- この機能は、
cmd/dist
ツール自体をデバッグする際に、ビルドプロセス全体を実行せずに、特定のバージョンのdist.exe
を簡単に利用できるようにするために役立ちます。
コアとなるコードの変更箇所
このコミットでは、以下のファイルが変更されています。
src/cmd/dist/a.h
:xsamefile
関数のプロトタイプ宣言が追加されました。src/cmd/dist/build.c
:cmdbanner
関数内のGOROOT_FINAL
とGOROOT
の比較がstreq
からxsamefile
に変更されました。src/cmd/dist/plan9.c
: Plan 9 環境向けのxsamefile
の実装が追加されました。これはstreq
を使用したシンプルな実装です。src/cmd/dist/unix.c
: Unix 環境向けのxsamefile
の実装が追加されました。これもstreq
を使用したシンプルな実装です。src/cmd/dist/windows.c
: Windows 環境向けのxsamefile
の実装が追加されました。これはCreateFileW
とGetFileInformationByHandle
を使用した詳細な実装です。src/make.bat
:--dist-tool
フラグを処理するためのロジックが追加され、cmd\dist\dist.exe
をGOTOOLDIR
にコピーする処理が実装されました。
コアとなるコードの解説
xsamefile
関数の導入と利用
src/cmd/dist/a.h
に追加されたプロトタイプ宣言:
int xsamefile(char*, char*);
src/cmd/dist/build.c
での利用:
- if(!streq(goroot_final, goroot)) {
+ if(!xsamefile(goroot_final, goroot)) {
xprintf("\n"
"The binaries expect %s to be copied or moved to %s\n",
goroot, goroot_final);
この変更により、GOROOT_FINAL
と GOROOT
のパスがファイルシステム上で同一である場合、たとえ文字列が異なっていても、誤解を招くメッセージが表示されなくなります。
Windows 環境における xsamefile
の実装 (src/cmd/dist/windows.c
)
// xsamefile returns whether f1 and f2 are the same file (or dir)
int
xsamefile(char *f1, char *f2)
{
Rune *ru;
HANDLE fd1, fd2;
BY_HANDLE_FILE_INFORMATION fi1, fi2;
int r;
// trivial case
if(streq(f1, f2))
return 1;
torune(&ru, f1);
// refer to ../../pkg/os/stat_windows.go:/sameFile
fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
xfree(ru);
if(fd1 == INVALID_HANDLE_VALUE)
return 0;
torune(&ru, f2);
fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
xfree(ru);
if(fd2 == INVALID_HANDLE_VALUE) {
CloseHandle(fd1);
return 0;
}
r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
CloseHandle(fd2);
CloseHandle(fd1);
if(r != 0 &&
fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
fi1.nFileIndexLow == fi2.nFileIndexLow)
return 1;
return 0;
}
このコードは、Windows API を使用してファイルの同一性を確認します。CreateFileW
でファイルハンドルを取得し、GetFileInformationByHandle
でファイルシステム上のユニークな識別子(ボリュームシリアル番号とファイルインデックス)を取得して比較します。これにより、シンボリックリンクや異なるパス表記でも、同じ実体を指しているかを正確に判断できます。
make.bat
の変更 (src/make.bat
)
+if x%1==x--dist-tool goto copydist
+if x%2==x--dist-tool goto copydist
+
...
+:copydist
+mkdir %GOTOOLDIR% 2>NUL
+copy cmd\dist\dist.exe %GOTOOLDIR%\
+goto end
この変更により、make.bat
を --dist-tool
オプション付きで実行すると、cmd/dist/dist.exe
が GOTOOLDIR
にコピーされます。これは、cmd/dist
のデバッグや特定のバージョンの dist
ツールをテストする際に非常に便利です。
関連リンク
- Go Issue #3100: https://github.com/golang/go/issues/3100
- Go CL 6637061: https://golang.org/cl/6637061 (このコミットに対応するGoの変更リスト)
参考にした情報源リンク
GetFileInformationByHandle
function (Microsoft Learn): https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandleCreateFileW
function (Microsoft Learn): https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew- Goのビルドプロセスに関する一般的な情報 (Go公式ドキュメントなど)
- Goの環境変数
GOROOT
に関する情報 (Go公式ドキュメントなど) - Windowsにおけるファイルパスの正規化と同一性に関する情報 (Microsoftドキュメントなど)
- Goのソースコード内の
pkg/os/stat_windows.go
(Windowsにおけるファイル情報の取得と同一性判定の参考)