[インデックス 15812] ファイルの概要
このコミットは、Go言語の配布ツール (misc/dist) におけるWindows環境での問題を修正するものです。具体的には、go tool tour コマンドに関連するバイナリのコピー処理と、ファイルパーミッションの設定に関するWindows固有の挙動に対応しています。
コミット
commit b7b4783622b4e21e7fb515b614bc651fe6210d7c
Author: Joe Poirier <jdpoirier@gmail.com>
Date: Mon Mar 18 08:56:38 2013 +1100
misc/dist: fix Windows breakage
The files could use some attention on the
Windows side but better to wait until after
the upcoming release.
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/7621044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b7b4783622b4e21e7fb515b614bc651fe6210d7c
元コミット内容
misc/dist: fix Windows breakage
The files could use some attention on the
Windows side but better to wait until after
the upcoming release.
変更の背景
このコミットの背景には、Go言語の配布ツール (misc/dist) がWindows環境で正しく動作しないという問題がありました。特に、go tool tour コマンドで使用される gotour バイナリのコピーと、ファイルパーミッションの設定において、WindowsとUnix系OS(Linux, macOSなど)との間の挙動の違いが原因で問題が発生していました。
コミットメッセージには「The files could use some attention on the Windows side but better to wait until after the upcoming release.」とあり、これはこの修正が一時的なものであり、将来的にWindows環境でのファイル処理全般についてより根本的な見直しが必要であるという認識が開発者側にあったことを示唆しています。しかし、差し迫ったリリースを控えていたため、まずは動作を保証するための最小限の修正が適用されたと考えられます。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
- Go言語のクロスコンパイルと配布: Go言語は、異なるOSやアーキテクチャ向けのバイナリを生成するクロスコンパイル機能を標準でサポートしています。
misc/distパッケージは、Goの配布物(バイナリディストリビューション)を作成するためのツール群を含んでいます。 go tool tour: これはGo言語の公式チュートリアル「A Tour of Go」をローカルで実行するためのコマンドです。通常、go tool tourと入力することでブラウザが起動し、チュートリアルが表示されます。このコマンドは内部的にgotourというバイナリを実行します。- Windowsの実行可能ファイル: Windowsでは、実行可能ファイルには通常
.exeという拡張子が付与されます。Unix系OSでは拡張子は必須ではありません。 - ファイルパーミッション (
Chmod):- Unix系OS: Unix系OSでは、ファイルの読み取り、書き込み、実行の権限をユーザー、グループ、その他の3つのカテゴリに対して細かく設定できます。これは
chmodコマンドやシステムコール (Chmod) で操作されます。 - Windows: Windowsのファイルシステム(NTFSなど)もアクセス制御リスト(ACL)によるパーミッション管理を行いますが、Unix系OSの
chmodとは概念が異なります。Go言語のos.File.Chmodメソッドは、Unix系OSではファイルのモード(パーミッション)を設定しますが、Windowsではその機能が完全に実装されていないか、挙動が異なる場合があります。特に、ファイル作成時に設定されるデフォルトのパーミッションが、Unix系OSのように後からChmodで変更できない、あるいは変更しても意味がないケースがあります。コミットメッセージの// Windows doesn't currently implement Fchmodというコメントは、このChmodのWindowsにおける実装上の制約を指しています。Fchmodはファイルディスクリプタに対するChmod操作を指します。
- Unix系OS: Unix系OSでは、ファイルの読み取り、書き込み、実行の権限をユーザー、グループ、その他の3つのカテゴリに対して細かく設定できます。これは
filepath.Join: Go言語のpath/filepathパッケージにある関数で、OS固有のパス区切り文字(Windowsでは\、Unix系では/)を使用してパスを結合します。これにより、OSに依存しないパス操作が可能になります。runtime.GOOS: Go言語のruntimeパッケージにある定数で、プログラムが実行されているOSの名前(例: "windows", "linux", "darwin")を文字列で返します。これにより、OS固有の処理を条件分岐で記述できます。
技術的詳細
このコミットは、misc/dist/bindist.go ファイルに対して2つの主要な修正を加えています。
-
gotourバイナリのファイル名に関する修正:- Unix系OSでは実行可能ファイルに拡張子は不要ですが、Windowsでは慣例的に
.exe拡張子が必要です。 - 以前のコードでは、
gotourバイナリをコピーする際に、常にgotourという名前でコピーしていました。 - 修正後、
runtime.GOOS == "windows"の場合にのみ、コピー先のファイル名をgotour.exeに変更するようにしました。これにより、Windows上でgotourが実行可能ファイルとして正しく認識されるようになります。
- Unix系OSでは実行可能ファイルに拡張子は不要ですが、Windowsでは慣例的に
-
ファイルパーミッション設定 (
Chmod) に関する修正:cp関数はファイルをコピーする際に、コピー元ファイルのパーミッションをコピー先ファイルに適用しようとします(df.Chmod(fi.Mode()))。- しかし、Windowsでは
os.File.Chmod(またはその内部で呼ばれるFchmod)が完全に実装されていないか、期待通りに動作しないという問題がありました。具体的には、ファイル作成後にパーミッションを変更しようとしてもエラーになるか、効果がない場合があります。 - この修正では、
if runtime.GOOS != "windows"という条件分岐を追加し、Windows以外のOSでのみdf.Chmod(fi.Mode())を実行するように変更しました。これにより、Windows環境でのChmod呼び出しによるエラーや予期せぬ挙動を回避し、コピー処理が正常に完了するようにしています。Windowsでは、ファイル作成時にデフォルトのパーミッションが設定されるため、明示的なChmod呼び出しは不要、あるいは無意味であると判断されたと考えられます。
これらの変更により、Goの配布ツールがWindows環境でも go tool tour を含むバイナリを正しく配置し、実行できるようになりました。
コアとなるコードの変更箇所
misc/dist/bindist.go ファイルの以下の部分が変更されました。
--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -386,9 +386,13 @@ func (b *Build) tour() error {
}\n
// Copy gotour binary to tool directory as "tour"; invoked as "go tool tour".
+\tgotour := "gotour"\n+\tif runtime.GOOS == "windows" {\n+\t\tgotour = "gotour.exe"\n+\t}\n \treturn cp(\n \t\tfilepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"),\n-\t\tfilepath.Join(b.gopath, "bin", "gotour"),\n+\t\tfilepath.Join(b.gopath, "bin", gotour),\n \t)\n }\n \n@@ -620,8 +624,11 @@ func cp(dst, src string) error {\n \t\treturn err\n \t}\n \tdefer df.Close()\n-\tif err := df.Chmod(fi.Mode()); err != nil {\n-\t\treturn err\n+\t// Windows doesn\'t currently implement Fchmod\n+\tif runtime.GOOS != "windows" {\n+\t\tif err := df.Chmod(fi.Mode()); err != nil {\n+\t\t\treturn err\n+\t\t}\n \t}\n \t_, err = io.Copy(df, sf)\n \treturn err\n```
## コアとなるコードの解説
### `func (b *Build) tour() error` 内の変更
```go
// Copy gotour binary to tool directory as "tour"; invoked as "go tool tour".
+ gotour := "gotour"
+ if runtime.GOOS == "windows" {
+ gotour = "gotour.exe"
+ }
return cp(
filepath.Join(b.root, "pkg", "tool", b.OS+"_"+b.Arch, "tour"),
- filepath.Join(b.gopath, "bin", "gotour"),
+ filepath.Join(b.gopath, "bin", gotour),
)
- 変更前:
filepath.Join(b.gopath, "bin", "gotour")で、常にgotourというファイル名でバイナリをコピーしようとしていました。 - 変更後:
gotour := "gotour"で、デフォルトのファイル名をgotourに設定します。if runtime.GOOS == "windows"で、現在のOSがWindowsであるかをチェックします。- もしWindowsであれば、
gotour = "gotour.exe"とし、ファイル名をgotour.exeに変更します。 - 最終的に
filepath.Join(b.gopath, "bin", gotour)を使用して、OSに応じた正しいファイル名でバイナリがコピーされるように修正されました。これにより、Windows環境でgotour.exeが正しく実行可能ファイルとして認識されます。
func cp(dst, src string) error 内の変更
defer df.Close()
- if err := df.Chmod(fi.Mode()); err != nil {
- return err
+ // Windows doesn't currently implement Fchmod
+ if runtime.GOOS != "windows" {
+ if err := df.Chmod(fi.Mode()); err != nil {
+ return err
+ }
}
_, err = io.Copy(df, sf)
return err
- 変更前:
df.Chmod(fi.Mode())を無条件に呼び出し、コピー先ファイルのパーミッションをコピー元ファイルと同じに設定しようとしていました。 - 変更後:
// Windows doesn't currently implement Fchmodというコメントが追加され、WindowsにおけるFchmodの実装上の制約が明記されています。if runtime.GOOS != "windows"という条件分岐が追加されました。- この条件分岐により、
df.Chmod(fi.Mode())はWindows以外のOSでのみ実行されるようになりました。Windowsではこの処理がスキップされるため、Chmod呼び出しによるエラーや予期せぬ挙動が回避され、ファイルコピー処理が安定しました。
関連リンク
- Go Code Review 7621044: https://golang.org/cl/7621044
参考にした情報源リンク
- Go言語の公式ドキュメント (特に
runtimeパッケージ、path/filepathパッケージ、osパッケージのChmodメソッドに関する記述) - Windowsの実行可能ファイルに関する一般的な知識
- Unix系OSのファイルパーミッションに関する一般的な知識
- Go言語のクロスコンパイルに関する情報
- A Tour of Go (go tool tour) に関する情報
- GitHubのコミットページ: https://github.com/golang/go/commit/b7b4783622b4e21e7fb515b614bc651fe6210d7c