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

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

コミット

  • コミットハッシュ: 8b836fa87234c5809891eceaeb87f63223217999
  • 作者: Peter Collingbourne pcc@google.com
  • 日付: Mon Jul 14 09:51:20 2014 -0400
  • コミットメッセージ: cmd/go: introduce support for $GCCGO env var This variable allows users to select the compiler when using the gccgo toolchain. LGTM=rsc R=rsc, iant, minux, aram CC=axwalk, golang-codereviews https://golang.org/cl/106700044

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

https://github.com/golang/go/commit/8b836fa87234c5809891eceaeb87f63223217999

元コミット内容

commit 8b836fa87234c5809891eceaeb87f63223217999
Author: Peter Collingbourne <pcc@google.com>
Date:   Mon Jul 14 09:51:20 2014 -0400

    cmd/go: introduce support for $GCCGO env var
    
    This variable allows users to select the compiler when using the
    gccgo toolchain.
    
    LGTM=rsc
    R=rsc, iant, minux, aram
    CC=axwalk, golang-codereviews
    https://golang.org/cl/106700044
---
 src/cmd/go/build.go | 16 ++++++++++++----\n 1 file changed, 12 insertions(+), 4 deletions(-)\n

変更の背景

このコミットは、Go言語のビルドツールであるcmd/goに、GCCGOという新しい環境変数を導入するものです。この環境変数は、gccgoツールチェーンを使用してGoプログラムをビルドする際に、ユーザーが使用するgccgoコンパイラの実行ファイルを明示的に指定できるようにすることを目的としています。

Go言語のビルドシステムは、通常、go buildコマンドを通じてgc(Goコンパイラ)を使用します。しかし、Go言語にはGCC(GNU Compiler Collection)のフロントエンドとして実装された代替コンパイラであるgccgoも存在します。gccgoは、GCCの強力な最適化機能や、より広範なプロセッサアーキテクチャへの対応といった利点を提供します。

このコミット以前は、cmd/gogccgoツールチェーンを選択した場合、システムパスからgccgoという名前の実行ファイルを自動的に検索して使用していました。しかし、このアプローチにはいくつかの課題がありました。

  • 複数バージョンのgccgoの共存: 開発者のシステムに複数のバージョンのgccgoがインストールされている場合、cmd/goが意図しないバージョンのgccgoを選択してしまう可能性がありました。
  • 特定のgccgoバイナリの使用: ユーザーがカスタムビルドしたgccgoや、特定のパスに配置されたgccgoバイナリを使用したい場合、そのための直接的なメカニズムがありませんでした。
  • 柔軟性の欠如: ビルド環境の多様化に対応するためには、コンパイラの選択に対するより高い柔軟性が求められていました。

これらの課題を解決するため、GCCGO環境変数が導入されました。これにより、ユーザーはGCCGOgccgo実行ファイルのパスまたは名前を設定することで、cmd/goが使用するgccgoコンパイラを柔軟に制御できるようになり、より堅牢でカスタマイズ可能なビルドプロセスが実現されます。

前提知識の解説

このコミットの変更内容を深く理解するためには、以下のGo言語および関連技術に関する前提知識が必要です。

Go言語のツールチェーン

Go言語は、ソースコードをコンパイルして実行可能なバイナリを生成するための複数の「ツールチェーン」をサポートしています。ツールチェーンとは、コンパイラ、アセンブラ、リンカなどの一連のツール群を指します。

  1. gc (Go Compiler):

    • Go言語の公式かつデフォルトのコンパイラです。Goチームによって開発・メンテナンスされており、Go言語の最新の仕様と機能に最も早く対応します。
    • コンパイル速度が非常に高速であることで知られており、Go開発の大部分で利用されます。
    • 生成されるバイナリは通常、静的にリンクされ、外部依存性が少ないのが特徴です。
  2. gccgo:

    • GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。GCCの一部として開発されており、GCCの強力な最適化バックエンドを利用できます。
    • gcコンパイラと比較して、コンパイル時間は長くなる傾向がありますが、生成されるコードの最適化レベルが高い場合があります。
    • GCCがサポートする幅広いCPUアーキテクチャに対応しているため、gcがサポートしないニッチなアーキテクチャでのGo開発に利用されることがあります。
    • libgoというGo言語のランタイムライブラリに動的にリンクするバイナリを生成するオプションがあり、これにより実行ファイルのサイズを小さくできる可能性があります(ただし、実行環境にlibgoが必要になります)。

cmd/go

cmd/goは、Go言語のソースコードのビルド、テスト、パッケージ管理、ドキュメント生成など、Go開発における中心的なコマンドラインツールです。go buildgo rungo testgo getなどのよく知られたコマンドは、すべてcmd/goによって提供されます。 cmd/goは、ユーザーが指定したコマンドや設定に基づいて、適切なツールチェーン(gcまたはgccgo)を選択し、そのツールチェーンのコンパイラやリンカなどのツールを内部的に呼び出して、実際の処理を実行します。

環境変数

環境変数とは、オペレーティングシステムが提供する、システム全体または特定のユーザーセッションで利用可能な動的な名前付きの値の集合です。プログラムはこれらの環境変数を読み取ることで、実行時の動作をカスタマイズしたり、設定情報を取得したりすることができます。 例えば、PATH環境変数は、コマンドを実行する際にシステムが実行可能ファイルを検索するディレクトリのリストを定義します。cmd/goもまた、GOPATHGOOSGOARCHなど、多くの環境変数を利用してその動作を制御しています。

技術的詳細

このコミットの技術的な実装は、cmd/gogccgoコンパイラを特定し、実行するロジックに柔軟性をもたらすことに焦点を当てています。具体的には、src/cmd/go/build.goファイル内のgccgoToolchain構造体に関連するコードが変更されました。

変更の核心は、gccgo実行ファイルのパスを決定する際に、まずGCCGOという新しい環境変数の値を優先的に使用し、それが設定されていない場合にのみ従来のデフォルトのgccgoという名前の実行ファイルをシステムパスから検索するというロロジックです。

  1. gccgoNamegccgoBin変数の導入:

    • 以前は、gccgoBinという変数が直接exec.LookPath("gccgo")の結果で初期化されていました。これは、常にgccgoという名前の実行ファイルを検索することを意味します。
    • このコミットでは、gccgoNamegccgoBinという2つの変数が導入されました。gccgoNameは使用するgccgoコンパイラの名前(またはパス)を保持し、gccgoBinはその名前からexec.LookPathで解決された実際のバイナリパスを保持します。
  2. init()関数による初期化ロジックの変更:

    • Go言語のinit()関数は、パッケージがインポートされた際に自動的に実行される特別な関数です。このコミットでは、gccgoNamegccgoBinの初期化ロジックがinit()関数内に移動されました。
    • init()関数内で、まずos.Getenv("GCCGO")を呼び出してGCCGO環境変数の値を取得します。
    • 取得した値が空文字列(つまり、GCCGO環境変数が設定されていないか、空に設定されている)の場合、gccgoNameはデフォルトの"gccgo"に設定されます。
    • GCCGO環境変数が設定されている場合、その値がgccgoNameとして使用されます。
    • 最後に、exec.LookPath(gccgoName)を呼び出して、決定されたgccgoNameに基づいて実際の実行ファイルのパスを検索し、gccgoBinに格納します。
  3. gccgoNameの動的な使用:

    • gccgoToolchain構造体のメソッド(gcasmldなど、コンパイル、アセンブル、リンクの各段階でgccgoを呼び出す部分)では、これまでハードコードされていた"gccgo"という文字列が、新しく導入されたgccgoName変数に置き換えられました。
    • これにより、cmd/gogccgoツールチェーンの各段階で外部コマンドを呼び出す際に、GCCGO環境変数の設定が動的に反映されるようになります。

この一連の変更により、ユーザーはGCCGO環境変数を設定するだけで、cmd/goが使用するgccgoコンパイラを簡単に切り替えることができるようになり、ビルドプロセスの柔軟性と制御性が大幅に向上しました。

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

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

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1775,7 +1775,15 @@ func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
 // The Gccgo toolchain.
 type gccgoToolchain struct{}
 
-var gccgoBin, _ = exec.LookPath("gccgo")
+var gccgoName, gccgoBin string
+
+func init() {
+	gccgoName = os.Getenv("GCCGO")
+	if gccgoName == "" {
+		gccgoName = "gccgo"
+	}
+	gccgoBin, _ = exec.LookPath(gccgoName)
+}
 
 func (gccgoToolchain) compiler() string {
 	return gccgoBin
@@ -1796,7 +1804,7 @@ func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs
 	if p.localPrefix != "" {
 		gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
 	}
-	args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+	args := stringList(gccgoName, importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
 	for _, f := range gofiles {
 		args = append(args, mkAbs(p.Dir, f))
 	}
@@ -1812,7 +1820,7 @@ func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) erro
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}\n\tdefs = append(defs, b.gccArchArgs()...)\n-\treturn b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile)\n+\treturn b.run(p.Dir, p.ImportPath, nil, gccgoName, "-I", obj, "-o", ofile, defs, sfile)\n }\n \n func (gccgoToolchain) pkgpath(basedir string, p *Package) string {\n@@ -1889,7 +1897,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
 	if objc {\n 		ldflags = append(ldflags, "-lobjc")\n 	}\n-\treturn b.run(\".\", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(\", ldflags, "-Wl,-)\", buildGccgoflags)\n+\treturn b.run(\".\", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(\", ldflags, "-Wl,-)\", buildGccgoflags)\n }\n \n func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {\n```

## コアとなるコードの解説

このコミットにおける最も重要なコード変更は、`src/cmd/go/build.go`ファイル内の`gccgoToolchain`構造体に関連する`gccgo`バイナリの特定と使用方法のロジックです。

1.  **`gccgoBin`と`gccgoName`変数の宣言と`init()`関数による初期化**:
    *   変更前は、`var gccgoBin, _ = exec.LookPath("gccgo")`という行で、`gccgoBin`変数がパッケージの初期化時に一度だけ、`gccgo`という名前の実行ファイルをシステムパスから検索して初期化されていました。これは、常に`gccgo`という固定の名前を使用することを意味します。
    *   変更後は、`gccgoName`と`gccgoBin`という2つの新しいパッケージレベル変数が導入されました。
    *   そして、`func init() { ... }`ブロックが追加されました。Go言語の`init()`関数は、パッケージがインポートされ、そのパッケージ内のすべてのグローバル変数が初期化された後に自動的に実行されます。
    *   この`init()`関数内で、まず`os.Getenv("GCCGO")`を呼び出して`GCCGO`環境変数の値を取得し、`gccgoName`に格納します。
    *   `if gccgoName == "" { gccgoName = "gccgo" }`という条件文により、もし`GCCGO`環境変数が設定されていない(または空文字列)であれば、`gccgoName`は従来のデフォルト値である`"gccgo"`に設定されます。
    *   最後に、`gccgoBin, _ = exec.LookPath(gccgoName)`を呼び出すことで、`gccgoName`(環境変数から取得した値、またはデフォルトの`"gccgo"`)で指定された実行ファイルをシステムパスから検索し、そのフルパスを`gccgoBin`に格納します。これにより、`GCCGO`環境変数が設定されていればその値が、設定されていなければデフォルトの`gccgo`が使用されるようになります。

2.  **`gccgoName`の使用箇所への変更**:
    *   `gccgoToolchain`構造体の主要なメソッドである`gc`(Goソースコードのコンパイル)、`asm`(アセンブリコードのアセンブル)、`ld`(オブジェクトファイルのリンク)において、外部コマンド(`gccgo`)を呼び出す際の実行ファイル名を指定する箇所が変更されました。
    *   具体的には、`stringList("gccgo", ...)`や`b.run(..., "gccgo", ...)`のようにハードコードされていた`"gccgo"`という文字列が、新しく導入された`gccgoName`変数に置き換えられました。
    *   これにより、`cmd/go`が`gccgo`ツールチェーンの各段階で`gccgo`コンパイラを呼び出す際に、`GCCGO`環境変数の設定が動的に反映されるようになります。例えば、`GCCGO=/usr/local/bin/gccgo-4.9`と設定されていれば、`cmd/go`は`gccgo-4.9`を呼び出すようになります。

これらの変更により、`cmd/go`は`gccgo`コンパイラの選択においてより柔軟になり、ユーザーは環境変数を通じて特定の`gccgo`バイナリを簡単に指定できるようになりました。これは、異なる`gccgo`バージョンを切り替えたり、カスタムビルドされた`gccgo`を使用したりする際に非常に有用です。

## 関連リンク

*   Go CL 106700044 (このコミットの元の変更リスト): [https://golang.org/cl/106700044](https://golang.org/cl/106700044)

## 参考にした情報源リンク

*   Go言語の公式ドキュメント (gccgoに関する情報): [https://go.dev/doc/install/gccgo](https://go.dev/doc/install/gccgo)
*   GCCGoに関するStack Overflowの議論 (一般的な情報収集): [https://stackoverflow.com/questions/tagged/gccgo](https://stackoverflow.com/questions/tagged/gccgo)
*   Go言語のツールチェーンに関する一般的な情報 (Go公式ブログやドキュメントを参照)