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

[インデックス 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環境でのファイル処理全般についてより根本的な見直しが必要であるという認識が開発者側にあったことを示唆しています。しかし、差し迫ったリリースを控えていたため、まずは動作を保証するための最小限の修正が適用されたと考えられます。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  1. Go言語のクロスコンパイルと配布: Go言語は、異なるOSやアーキテクチャ向けのバイナリを生成するクロスコンパイル機能を標準でサポートしています。misc/dist パッケージは、Goの配布物(バイナリディストリビューション)を作成するためのツール群を含んでいます。
  2. go tool tour: これはGo言語の公式チュートリアル「A Tour of Go」をローカルで実行するためのコマンドです。通常、go tool tour と入力することでブラウザが起動し、チュートリアルが表示されます。このコマンドは内部的に gotour というバイナリを実行します。
  3. Windowsの実行可能ファイル: Windowsでは、実行可能ファイルには通常 .exe という拡張子が付与されます。Unix系OSでは拡張子は必須ではありません。
  4. ファイルパーミッション (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 操作を指します。
  5. filepath.Join: Go言語の path/filepath パッケージにある関数で、OS固有のパス区切り文字(Windowsでは \、Unix系では /)を使用してパスを結合します。これにより、OSに依存しないパス操作が可能になります。
  6. runtime.GOOS: Go言語の runtime パッケージにある定数で、プログラムが実行されているOSの名前(例: "windows", "linux", "darwin")を文字列で返します。これにより、OS固有の処理を条件分岐で記述できます。

技術的詳細

このコミットは、misc/dist/bindist.go ファイルに対して2つの主要な修正を加えています。

  1. gotour バイナリのファイル名に関する修正:

    • Unix系OSでは実行可能ファイルに拡張子は不要ですが、Windowsでは慣例的に .exe 拡張子が必要です。
    • 以前のコードでは、gotour バイナリをコピーする際に、常に gotour という名前でコピーしていました。
    • 修正後、runtime.GOOS == "windows" の場合にのみ、コピー先のファイル名を gotour.exe に変更するようにしました。これにより、Windows上で gotour が実行可能ファイルとして正しく認識されるようになります。
  2. ファイルパーミッション設定 (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言語の公式ドキュメント (特に runtime パッケージ、path/filepath パッケージ、os パッケージの Chmod メソッドに関する記述)
  • Windowsの実行可能ファイルに関する一般的な知識
  • Unix系OSのファイルパーミッションに関する一般的な知識
  • Go言語のクロスコンパイルに関する情報
  • A Tour of Go (go tool tour) に関する情報
  • GitHubのコミットページ: https://github.com/golang/go/commit/b7b4783622b4e21e7fb515b614bc651fe6210d7c