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

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

このコミットは、Go言語のコマンドラインツールである cmd/go が、Goコンパイラ (gc) に渡す追加のフラグを定義する環境変数 $GCFLAGS を尊重するように変更するものです。これにより、ユーザーはビルド時にコンパイラの挙動をより細かく制御できるようになります。

コミット

commit 25c8014ed905a41a7f060efeea9a4c289c0aa0de
Author: Russ Cox <rsc@golang.org>
Date:   Wed Dec 21 09:04:34 2011 -0500

    cmd/go: respect $GCFLAGS

    R=lvd
    CC=golang-dev
    https://golang.org/cl/5500060

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

https://github.com/golang/go/commit/25c8014ed905a41a7f060efeea9a4c289c0aa0de

元コミット内容

cmd/go: respect $GCFLAGS

このコミットは、go コマンドが $GCFLAGS 環境変数を尊重するように変更します。

変更の背景

Go言語のビルドシステムにおいて、コンパイラ (gc) に特定のオプションを渡したい場合があります。例えば、デバッグ情報の詳細度を変更したり、最適化の挙動を調整したり、特定の警告を抑制したりする際に、これらのオプションが必要となります。

以前の go コマンドは、このようなコンパイラオプションを直接指定するメカニズムが不足していました。開発者が go buildgo install のようなコマンドを使用する際に、コンパイラにカスタムフラグを渡すことができないため、ビルドプロセスの柔軟性が制限されていました。

このコミットは、標準的な環境変数である $GCFLAGS を利用することで、この問題を解決します。$GCFLAGS に設定された値が go コマンドによって読み取られ、Goコンパイラ (gc) の呼び出し時にそのフラグが自動的に追加されるようになります。これにより、ユーザーは go コマンドのラッパーを記述することなく、コンパイラの挙動を簡単にカスタマイズできるようになりました。

前提知識の解説

  • Go言語のビルドシステム: Go言語は、go buildgo install といったコマンドを通じて、ソースコードのコンパイル、リンク、実行可能ファイルの生成を行います。これらのコマンドは内部的にGoコンパイラ (gc) やアセンブラ (go tool asm)、リンカ (go tool link) などのツールを呼び出します。
  • gc (Go Compiler): Go言語の公式コンパイラです。Goのソースコードを機械語に変換します。gc には、デバッグ、最適化、コード生成などに関する様々なコマンドラインフラグが存在します。
  • 環境変数 $GCFLAGS: Goのビルドシステムで認識される環境変数の一つです。この変数には、Goコンパイラ (gc) に渡したい追加のフラグをスペース区切りで指定します。例えば、GCFLAGS="-N -l" と設定すると、コンパイラの最適化を無効にし(-N)、インライン化を無効にします(-l)。これはデバッグ時に非常に役立ちます。
  • src/cmd/go/build.go: go コマンドのビルドロジックを定義しているGo言語のソースファイルです。このファイルは、パッケージの依存関係の解決、コンパイル順序の決定、コンパイラやリンカの呼び出しなど、ビルドプロセスの中心的な役割を担っています。

技術的詳細

このコミットの技術的な核心は、src/cmd/go/build.go 内で $GCFLAGS 環境変数を読み込み、その値をGoコンパイラ (gc) の呼び出し引数に動的に追加することにあります。

  1. builder 構造体へのフィールド追加: builder 構造体は、Goのビルドプロセス全体を管理する主要なオブジェクトです。この構造体に gcflags []string という新しいフィールドが追加されました。これは、$GCFLAGS 環境変数から読み込まれたコンパイラフラグを文字列スライスの形で保持するためのものです。

  2. init メソッドでの環境変数読み込み: builderinit メソッドは、ビルドプロセスの初期化時に呼び出されます。このメソッド内で os.Getenv("GCFLAGS") を使用して $GCFLAGS 環境変数の値を取得し、strings.Fields を使ってスペースで区切られた文字列を個々のフラグに分割し、b.gcflags フィールドに格納します。

  3. gc メソッドでのフラグ追加: gc メソッドは、Goコンパイラ (gc) を呼び出してGoソースファイルをコンパイルする役割を担っています。このメソッド内で、gc コマンドに渡す引数リスト (args) に、b.gcflags に格納されているすべてのフラグが append されます。これにより、$GCFLAGS で指定されたフラグが実際のコンパイルコマンドに反映されるようになります。

  4. gccCmd メソッドの変更: gccCmd メソッドは、CGO(C言語との連携)に関連する gcc コマンドの引数を構築します。このコミットでは、Windows環境での gcc の挙動を考慮し、-fPIC フラグの追加ロジックが変更されました。Windowsでは -fPIC が不要または警告を出す場合があるため、OSがWindowsでない場合にのみ -fPIC を追加するように修正されています。これは $GCFLAGS とは直接関係ありませんが、同じコミット内で関連するビルドロジックの改善として行われています。

これらの変更により、go コマンドは $GCFLAGS を透過的に処理し、ユーザーが指定したコンパイラフラグをビルドプロセスに組み込むことが可能になりました。

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

src/cmd/go/build.go ファイルにおける変更点は以下の通りです。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -139,6 +139,7 @@ type builder struct {\n 	goos        string               // the $GOOS\n 	gobin       string               // the $GOBIN\n 	exe         string               // the executable suffix - "" or ".exe"\n+	gcflags     []string             // additional flags for Go compiler\n 	actionCache map[cacheKey]*action // a cache of already-constructed actions\n 	mkdirCache  map[string]bool      // a cache of created directories\n \n@@ -202,6 +203,7 @@ func (b *builder) init(aflag, nflag, xflag bool) {\n 	if b.goos == "windows" {\n 		b.exe = ".exe"\n 	}\n+	b.gcflags = strings.Fields(os.Getenv("GCFLAGS"))\n \n 	b.arch, err = build.ArchChar(b.goarch)\n 	if err != nil {\n@@ -836,6 +838,7 @@ func mkAbs(dir, f string) string {\n // to generate the named output file. \n func (b *builder) gc(p *Package, ofile string, gcargs, importArgs []string, gofiles []string) error {\n 	args := []string{b.arch + "g", "-o", ofile}\n+\targs = append(args, b.gcflags...)\n 	args = append(args, gcargs...)\n 	args = append(args, importArgs...)\n 	for _, f := range gofiles {\n@@ -890,7 +893,13 @@ func (b *builder) gccld(p *Package, out string, flags []string, obj []string) er\n // gccCmd returns a gcc command line ending with args\n func (b *builder) gccCmd(objdir string, flags []string, args ...string) []string {\n 	// TODO: HOST_CC?\n-\ta := []string{"gcc", "-I", objdir, "-g", "-fPIC", "-O2"}\n+\ta := []string{"gcc", "-I", objdir, "-g", "-O2"}\n+\n+\t// Definitely want -fPIC but on Windows gcc complains\n+\t// "-fPIC ignored for target (all code is position independent)"\n+\tif b.goos != "windows" {\n+\t\ta = append(a, "-fPIC")\n+\t}\n \tswitch b.arch {\n \tcase "8":\n \t\ta = append(a, "-m32")\n```

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

1.  **`type builder struct { ... }` への `gcflags` フィールド追加**:
    ```go
    +	gcflags     []string             // additional flags for Go compiler
    ```
    `builder` 構造体に `gcflags` という新しいフィールドが追加されました。これは、`$GCFLAGS` 環境変数から取得したコンパイラフラグを文字列スライスとして保持するためのものです。これにより、ビルドプロセス全体でこれらのフラグにアクセスできるようになります。

2.  **`func (b *builder) init(...)` 内での `$GCFLAGS` 読み込み**:
    ```go
    +	b.gcflags = strings.Fields(os.Getenv("GCFLAGS"))
    ```
    `builder` の初期化時に、`os.Getenv("GCFLAGS")` を呼び出して環境変数 `$GCFLAGS` の値を取得します。`strings.Fields` は、取得した文字列をスペースで分割し、個々のフラグを文字列スライスとして `b.gcflags` に代入します。これにより、`$GCFLAGS` に設定されたすべてのフラグがビルドシステムに認識されます。

3.  **`func (b *builder) gc(...)` 内でのフラグ適用**:
    ```go
    +	args = append(args, b.gcflags...)
    ```
    Goコンパイラ (`gc`) を呼び出す `gc` メソッド内で、コンパイラに渡す引数リスト `args` に、`b.gcflags` の内容が追加されます。`...` はスライスを展開して個々の要素を引数として渡すGoの構文です。これにより、`$GCFLAGS` で指定されたすべてのフラグが `gc` コマンドの実行時に適用されます。

4.  **`func (b *builder) gccCmd(...)` 内の `-fPIC` 修正**:
    ```go
    -	a := []string{"gcc", "-I", objdir, "-g", "-fPIC", "-O2"}
    +	a := []string{"gcc", "-I", objdir, "-g", "-O2"}
    +
    +	// Definitely want -fPIC but on Windows gcc complains
    +	// "-fPIC ignored for target (all code is position independent)"
    +	if b.goos != "windows" {
    +		a = append(a, "-fPIC")
    +	}
    ```
    この変更は、CGOビルド時に `gcc` に渡される `-fPIC` フラグの扱いを改善するものです。Windows環境では `-fPIC` が不要であり、警告を発生させる可能性があるため、`b.goos != "windows"` の条件を追加し、Windows以外のOSでのみ `-fPIC` を追加するように修正されました。これは `$GCFLAGS` の機能とは直接関係ありませんが、ビルドシステムの堅牢性を高めるための改善です。

これらの変更により、Goのビルドプロセスは `$GCFLAGS` を介したコンパイラオプションのカスタマイズをサポートし、より柔軟な開発ワークフローを提供できるようになりました。

## 関連リンク

*   Go Change-ID: [https://golang.org/cl/5500060](https://golang.org/cl/5500060)

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

*   Go言語の公式ドキュメント (Go Compiler Flags, Environment Variables)
*   Go言語のソースコード (`src/cmd/go/build.go`)
*   Go言語の環境変数に関する一般的な知識
*   `strings.Fields` および `os.Getenv` のGo標準ライブラリドキュメント
*   `append` 関数のGo言語のドキュメント
*   `-fPIC` フラグに関するGCCのドキュメント (Position-Independent Code)