[インデックス 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の変更リスト)
参考にした情報源リンク
GetFileInformationByHandlefunction (Microsoft Learn): https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandleCreateFileWfunction (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におけるファイル情報の取得と同一性判定の参考)