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

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

このコミットは、Go言語のコマンドラインツール cmd/go における、Windows環境での実行ファイル名に関する挙動の修正です。具体的には、go build コマンドで生成される実行ファイルに、Windowsでは常に .exe サフィックスが付与されるように変更されました。

コミット

commit 6a426169f531971dd69b2ad17c848dbb8fae125a
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Mar 7 14:25:24 2012 +0800

    cmd/go: always provide .exe suffix on windows
            Fixes #3190.
    
    R=rsc, tjyang2001, rsc
    CC=golang-dev
    https://golang.org/cl/5759056

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

https://github.com/golang/go/commit/6a426169f531971dd69b2ad17c848dbb8fae125a

元コミット内容

cmd/go: always provide .exe suffix on windows
        Fixes #3190.

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

変更の背景

この変更は、Go言語のIssue #3190を修正するために行われました。Issue #3190は、Windows環境で go build コマンドを使用して実行ファイルをビルドする際に、特定の条件下で .exe 拡張子が自動的に付与されないという問題点を指摘していました。

通常、Windowsの実行ファイルは .exe 拡張子を持つことが期待されます。しかし、go build が常にこの拡張子を付与するわけではなかったため、ユーザーがビルドした実行ファイルを直接実行しようとした際に、OSがそれを実行可能ファイルとして認識できず、不便が生じていました。このコミットは、この一貫性のない挙動を修正し、Windows上でのGoプログラムのビルド体験を向上させることを目的としています。

前提知識の解説

Go言語のビルドシステム (cmd/go)

cmd/go は、Go言語の公式ツールチェーンの一部であり、ソースコードのコンパイル、パッケージの管理、テストの実行など、Go開発における様々なタスクを処理します。その中でも go build コマンドは、Goのソースコードを実行可能なバイナリにコンパイルするために使用されます。

実行ファイルの拡張子とOSの挙動

オペレーティングシステム(OS)は、ファイルの種類を識別するためにファイル拡張子を利用します。

  • Windows: Windowsでは、実行可能ファイルは通常 .exe 拡張子を持ちます。OSは、この拡張子を持つファイルを直接実行可能なプログラムとして認識します。拡張子がない場合や、異なる拡張子の場合、ユーザーは手動で実行方法を指定する必要があるか、OSがそのファイルをプログラムとして認識しない可能性があります。
  • Unix系OS (Linux, macOSなど): Unix系のOSでは、ファイル拡張子はファイルの種類を示すための慣習的なものであり、実行可能性を決定する主要な要素ではありません。ファイルの実行可能性は、ファイルパーミッション(実行ビット)によって制御されます。

go build の出力ファイル名決定ロジック(変更前)

このコミット以前の go build の挙動では、出力ファイル名の決定ロジックが複雑でした。

  1. go build -o <output_name> のように -o フラグで出力ファイル名が明示的に指定された場合、その名前がそのまま使用されます。
  2. -o フラグが指定されず、ビルド対象が単一の main パッケージである場合、デフォルトの出力ファイル名が決定されます。
    • Unix系OSでは、通常、パッケージのインポートパスの最後の要素(例: github.com/user/project なら project)がファイル名となります。
    • Windowsでは、このデフォルト名に .exe が付与される場合とされない場合がありました。特に、go build main.go のように単一のGoファイルを指定してビルドした場合、.exe が付与されないことが問題となっていました。

技術的詳細

このコミットの技術的な核心は、GoのビルドツールがWindows上で実行ファイルを生成する際に、常に .exe 拡張子を付与するように、ファイル名決定ロジックを簡素化し、統一することにあります。

変更は src/cmd/go/build.go ファイルに対して行われました。このファイルは、go build コマンドの主要なロジックを含んでいます。

具体的な変更点は以下の通りです。

  1. exeSuffix 変数の導入: Goのビルドシステムは、クロスコンパイルをサポートしています。つまり、Linux上でWindows用のバイナリをビルドすることも可能です。このため、OS固有の実行ファイル拡張子をハードコードするのではなく、exeSuffix という変数(または定数)を導入し、その値がターゲットOSに応じて適切に設定されるようにします。Windowsの場合、この exeSuffix.exe となります。

  2. 出力ファイル名決定ロジックの統一: 以前は、Windowsの場合にのみ .exe を追加する条件分岐がコード内に散在していました。この変更により、*buildO += exeSuffix という形式で、常に exeSuffix を出力ファイル名に追加するように統一されました。これにより、コードの可読性と保守性が向上し、将来的に他のOSが追加された場合でも、同様のロジックで対応できるようになります。

    特に、以下の2つのケースで変更が適用されました。

    • go build コマンドで -o フラグが指定されず、かつビルド対象が単一の main パッケージである場合。
    • go build <file.go> のように単一のGoファイルを指定してビルドし、-o フラグが指定されない場合。

この修正により、Windows環境で go build を実行すると、どのような状況でも生成される実行ファイルには必ず .exe 拡張子が付与されるようになり、ユーザーは期待通りのファイル名で実行ファイルを受け取れるようになりました。

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

変更は src/cmd/go/build.go ファイルに集中しています。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -168,9 +168,7 @@ func runBuild(cmd *Command, args []string) {
 
  	if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
  		_, *buildO = path.Split(pkgs[0].ImportPath)
- 		if goos == "windows" {
- 			*buildO += ".exe"
- 		}
+ 		*buildO += exeSuffix
  	}
 
  	if *buildO != "" {
@@ -392,7 +390,7 @@ func goFilesPackage(gofiles []string) *Package {
  	if *buildO == "" {
  		if pkg.Name == "main" {
  			_, elem := filepath.Split(gofiles[0])
- 			*buildO = elem[:len(elem)-len(".go")]
+ 			*buildO = elem[:len(elem)-len(".go")] + exeSuffix
  		} else {
  			*buildO = pkg.Name + ".a"
  		}

コアとなるコードの解説

上記の差分は、src/cmd/go/build.go 内の2つの異なる場所で、出力ファイル名の決定ロジックが変更されたことを示しています。

  1. 最初の変更箇所 (L168-171):

    // 変更前
    if goos == "windows" {
        *buildO += ".exe"
    }
    // 変更後
    *buildO += exeSuffix
    

    この部分は、go build コマンドが単一の main パッケージをビルドし、かつ -o フラグで出力ファイル名が指定されていない場合のデフォルトのファイル名決定ロジックです。 変更前は、明示的に goos == "windows" という条件で .exe を追加していました。 変更後は、exeSuffix という変数(または定数)を無条件に追加するように修正されています。これにより、exeSuffix がWindows環境では .exe に解決されるため、より汎用的で簡潔な記述になっています。

  2. 二番目の変更箇所 (L392-394):

    // 変更前
    *buildO = elem[:len(elem)-len(".go")]
    // 変更後
    *buildO = elem[:len(elem)-len(".go")] + exeSuffix
    

    この部分は、go build <file.go> のように単一のGoファイルを指定してビルドし、-o フラグが指定されていない場合のデフォルトのファイル名決定ロジックです。 変更前は、.go 拡張子を取り除いたファイル名がそのまま出力ファイル名となっていました。 変更後は、.go 拡張子を取り除いたファイル名に exeSuffix を追加するように修正されています。これにより、go build main.go のようなコマンドでも、Windowsでは main.exe が生成されるようになります。

これらの変更により、Windows環境における go build の出力ファイル名が、常に .exe 拡張子を持つように統一され、ユーザーエクスペリエンスが向上しました。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語のコマンドラインツール cmd/go における、Windows環境での実行ファイル名に関する挙動の修正です。具体的には、go build コマンドで生成される実行ファイルに、Windowsでは常に .exe サフィックスが付与されるように変更されました。

コミット

commit 6a426169f531971dd69b2ad17c848dbb8fae125a
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Mar 7 14:25:24 2012 +0800

    cmd/go: always provide .exe suffix on windows
            Fixes #3190.
    
    R=rsc, tjyang2001, rsc
    CC=golang-dev
    https://golang.org/cl/5759056

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

https://github.com/golang/go/commit/6a426169f531971dd69b2ad17c848dbb8fae125a

元コミット内容

cmd/go: always provide .exe suffix on windows
        Fixes #3190.

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

変更の背景

この変更は、Go言語のIssue #3190を修正するために行われました。Issue #3190は、Windows環境で go build コマンドを使用して実行ファイルをビルドする際に、特定の条件下で .exe 拡張子が自動的に付与されないという問題点を指摘していました。

通常、Windowsの実行ファイルは .exe 拡張子を持つことが期待されます。しかし、go build が常にこの拡張子を付与するわけではなかったため、ユーザーがビルドした実行ファイルを直接実行しようとした際に、OSがそれを実行可能ファイルとして認識できず、不便が生じていました。このコミットは、この一貫性のない挙動を修正し、Windows上でのGoプログラムのビルド体験を向上させることを目的としています。

前提知識の解説

Go言語のビルドシステム (cmd/go)

cmd/go は、Go言語の公式ツールチェーンの一部であり、ソースコードのコンパイル、パッケージの管理、テストの実行など、Go開発における様々なタスクを処理します。その中でも go build コマンドは、Goのソースコードを実行可能なバイナリにコンパイルするために使用されます。

実行ファイルの拡張子とOSの挙動

オペレーティングシステム(OS)は、ファイルの種類を識別するためにファイル拡張子を利用します。

  • Windows: Windowsでは、実行可能ファイルは通常 .exe 拡張子を持ちます。OSは、この拡張子を持つファイルを直接実行可能なプログラムとして認識します。拡張子がない場合や、異なる拡張子の場合、ユーザーは手動で実行方法を指定する必要があるか、OSがそのファイルをプログラムとして認識しない可能性があります。
  • Unix系OS (Linux, macOSなど): Unix系のOSでは、ファイル拡張子はファイルの種類を示すための慣習的なものであり、実行可能性を決定する主要な要素ではありません。ファイルの実行可能性は、ファイルパーミッション(実行ビット)によって制御されます。

go build の出力ファイル名決定ロジック(変更前)

このコミット以前の go build の挙動では、出力ファイル名の決定ロジックが複雑でした。

  1. go build -o <output_name> のように -o フラグで出力ファイル名が明示的に指定された場合、その名前がそのまま使用されます。
  2. -o フラグが指定されず、ビルド対象が単一の main パッケージである場合、デフォルトの出力ファイル名が決定されます。
    • Unix系OSでは、通常、パッケージのインポートパスの最後の要素(例: github.com/user/project なら project)がファイル名となります。
    • Windowsでは、このデフォルト名に .exe が付与される場合とされない場合がありました。特に、go build main.go のように単一のGoファイルを指定してビルドした場合、.exe が付与されないことが問題となっていました。

技術的詳細

このコミットの技術的な核心は、GoのビルドツールがWindows上で実行ファイルを生成する際に、常に .exe 拡張子を付与するように、ファイル名決定ロジックを簡素化し、統一することにあります。

変更は src/cmd/go/build.go ファイルに対して行われました。このファイルは、go build コマンドの主要なロジックを含んでいます。

具体的な変更点は以下の通りです。

  1. exeSuffix 変数の導入: Goのビルドシステムは、クロスコンパイルをサポートしています。つまり、Linux上でWindows用のバイナリをビルドすることも可能です。このため、OS固有の実行ファイル拡張子をハードコードするのではなく、exeSuffix という変数(または定数)を導入し、その値がターゲットOSに応じて適切に設定されるようにします。Windowsの場合、この exeSuffix.exe となります。

  2. 出力ファイル名決定ロジックの統一: 以前は、Windowsの場合にのみ .exe を追加する条件分岐がコード内に散在していました。この変更により、*buildO += exeSuffix という形式で、常に exeSuffix を出力ファイル名に追加するように統一されました。これにより、コードの可読性と保守性が向上し、将来的に他のOSが追加された場合でも、同様のロジックで対応できるようになります。

    特に、以下の2つのケースで変更が適用されました。

    • go build コマンドで -o フラグが指定されず、かつビルド対象が単一の main パッケージである場合。
    • go build <file.go> のように単一のGoファイルを指定してビルドし、-o フラグが指定されない場合。

この修正により、Windows環境で go build を実行すると、どのような状況でも生成される実行ファイルには必ず .exe 拡張子が付与されるようになり、ユーザーは期待通りのファイル名で実行ファイルを受け取れるようになりました。

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

変更は src/cmd/go/build.go ファイルに集中しています。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -168,9 +168,7 @@ func runBuild(cmd *Command, args []string) {
 
  	if len(pkgs) == 1 && pkgs[0].Name == "main" && *buildO == "" {
  		_, *buildO = path.Split(pkgs[0].ImportPath)
- 		if goos == "windows" {
- 			*buildO += ".exe"
- 		}
+ 		*buildO += exeSuffix
  	}
 
  	if *buildO != "" {
@@ -392,7 +390,7 @@ func goFilesPackage(gofiles []string) *Package {
  	if *buildO == "" {
  		if pkg.Name == "main" {
  			_, elem := filepath.Split(gofiles[0])
- 			*buildO = elem[:len(elem)-len(".go")]
+ 			*buildO = elem[:len(elem)-len(".go")] + exeSuffix
  		} else {
  			*buildO = pkg.Name + ".a"
  		}

コアとなるコードの解説

上記の差分は、src/cmd/go/build.go 内の2つの異なる場所で、出力ファイル名の決定ロジックが変更されたことを示しています。

  1. 最初の変更箇所 (L168-171):

    // 変更前
    if goos == "windows" {
        *buildO += ".exe"
    }
    // 変更後
    *buildO += exeSuffix
    

    この部分は、go build コマンドが単一の main パッケージをビルドし、かつ -o フラグで出力ファイル名が指定されていない場合のデフォルトのファイル名決定ロジックです。 変更前は、明示的に goos == "windows" という条件で .exe を追加していました。 変更後は、exeSuffix という変数(または定数)を無条件に追加するように修正されています。これにより、exeSuffix がWindows環境では .exe に解決されるため、より汎用的で簡潔な記述になっています。

  2. 二番目の変更箇所 (L392-394):

    // 変更前
    *buildO = elem[:len(elem)-len(".go")]
    // 変更後
    *buildO = elem[:len(elem)-len(".go")] + exeSuffix
    

    この部分は、go build <file.go> のように単一のGoファイルを指定してビルドし、-o フラグが指定されていない場合のデフォルトのファイル名決定ロジックです。 変更前は、.go 拡張子を取り除いたファイル名がそのまま出力ファイル名となっていました。 変更後は、.go 拡張子を取り除いたファイル名に exeSuffix を追加するように修正されています。これにより、go build main.go のようなコマンドでも、Windowsでは main.exe が生成されるようになります。

これらの変更により、Windows環境における go build の出力ファイル名が、常に .exe 拡張子を持つように統一され、ユーザーエクスペリエンスが向上しました。

関連リンク

参考にした情報源リンク