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

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

このコミットは、Go言語のビルドツール cmd/go-ccflags オプションを追加するものです。これにより、GoのツールチェインがC言語のソースコードをコンパイルする際に使用するCコンパイラ(5c, 6c, 8cなど)に対して、追加の引数を渡すことが可能になります。これは、Goコンパイラ(5g, 6g, 8gなど)に引数を渡すための既存の -gcflags オプションと同様の機能を提供します。

コミット

commit 5b2cd445fbc586e6a1c12420436a5523cd9f8d78
Author: Dave Cheney <dave@cheney.net>
Date:   Thu May 31 09:10:03 2012 +1000

    cmd/go: add -ccflags
    
    Add -ccflags to pass arguments to {5,6,8}c
    similar to -gcflags for {5,6,8}g.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6260047

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

https://github.com/golang/go/commit/5b2cd445fbc586e6a1c12420436a5523cd9f8d78

元コミット内容

cmd/go: add -ccflags

Add -ccflags to pass arguments to {5,6,8}c
similar to -gcflags for {5,6,8}g.

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

変更の背景

Go言語は、C言語のコードをGoプログラムに組み込むための cgo というメカニズムを提供しています。cgo を使用すると、Goのソースコード内にC言語のコードを記述し、Goの関数からCの関数を呼び出したり、その逆を行ったりすることができます。

Goのビルドプロセスでは、Goのソースコードは 5g, 6g, 8g といったGoコンパイラによってコンパイルされ、Cのソースコードは 5c, 6c, 8c といったCコンパイラによってコンパイルされます。これらのコンパイラは、Goのツールチェインの一部として提供されるPlan 9系のコンパイラです。

従来、Goコンパイラに対しては -gcflags オプションを使って追加の引数(例えば最適化レベルの調整やデバッグ情報の追加など)を渡すことが可能でした。しかし、Cコンパイラに対して同様の引数を渡す直接的な手段が go build コマンドにはありませんでした。

このコミットの背景には、cgo を利用する際に、Cコンパイラの挙動を細かく制御したいというニーズがありました。例えば、特定のCライブラリをリンクする際に必要なコンパイラフラグや、Cコードの最適化設定などをビルド時に指定したい場合です。-ccflags の導入により、Goのビルドシステムを通じてCコンパイラに直接引数を渡せるようになり、cgo を利用したプロジェクトのビルドの柔軟性が向上しました。

前提知識の解説

Goのビルドプロセスとツールチェイン

Go言語のビルドプロセスは、go build コマンドによって管理されます。このコマンドは、ソースコードの依存関係を解決し、コンパイル、アセンブル、リンクといった一連の処理を実行して実行可能ファイルを生成します。

Goのツールチェインは、Goコンパイラ(gc)、アセンブラ(as)、リンカ(ld)など、ビルドに必要な様々なツールを含んでいます。これらのツールは、ターゲットアーキテクチャ(例: amd64, arm, 386)に応じて、それぞれ 6g, 5g, 8g のように命名されています。

  • 5g: ARMアーキテクチャ向けのGoコンパイラ
  • 6g: x86-64 (AMD64) アーキテクチャ向けのGoコンパイラ
  • 8g: x86 (386) アーキテクチャ向けのGoコンパイラ

同様に、C言語のコンパイルにはPlan 9系のCコンパイラが使用されます。

  • 5c: ARMアーキテクチャ向けのCコンパイラ
  • 6c: x86-64 (AMD64) アーキテクチャ向けのCコンパイラ
  • 8c: x86 (386) アーキテクチャ向けのCコンパイラ

cgo

cgo は、GoプログラムからC言語のコードを呼び出すためのGoの機能です。Goのソースファイル内に import "C" と記述し、その後にC言語のコードをコメント形式で記述することで、GoとCの相互運用が可能になります。cgo を使用すると、Goの標準ライブラリでは提供されていない低レベルなシステムコールや、既存のCライブラリを利用することができます。

cgo を含むGoプログラムをビルドする際、GoのビルドツールはまずC言語のコードをCコンパイラ(5c, 6c, 8cなど)でコンパイルし、その結果生成されたオブジェクトファイルをGoのオブジェクトファイルとリンクします。

コンパイラフラグ

コンパイラフラグ(またはコンパイラオプション)は、コンパイラの挙動を制御するためにコンパイラに渡されるコマンドライン引数です。これらは、コンパイル時の最適化レベル、デバッグ情報の生成、警告の表示方法、インクルードパスの指定、マクロの定義など、多岐にわたる設定を調整するために使用されます。

Goのビルドコマンドでは、これまでも以下の主要なフラグが提供されていました。

  • -gcflags: Goコンパイラ(5g, 6g, 8gなど)に渡す引数を指定します。例えば、-gcflags="-N -l" は最適化とインライン化を無効にし、デバッグを容易にします。
  • -ldflags: リンカに渡す引数を指定します。例えば、-ldflags="-s -w" はシンボルテーブルとデバッグ情報を削除し、バイナリサイズを削減します。

このコミットで追加される -ccflags は、これらのフラグと同様に、Cコンパイラに引数を渡すためのものです。

技術的詳細

このコミットの技術的な変更は、主に src/cmd/go/build.go ファイルに集中しています。このファイルは、go コマンドのビルドロジックを定義しています。

変更のポイントは以下の通りです。

  1. -ccflags オプションの追加: go build コマンドのヘルプメッセージに -ccflags オプションの説明が追加されました。これにより、ユーザーがこの新しいオプションの存在と目的を認識できるようになります。

    @@ -60,6 +60,8 @@ The build flags are shared by the build, install, run, and test commands:
     	-x
     	\t\tprint the commands.
    
    +\t-ccflags 'arg list'
    +\t\targuments to pass on each 5c, 6c, or 8c compiler invocation
     	-compiler name
     	\t\tname of compiler to use, as in runtime.Compiler (gccgo or gc)
     	-gccgoflags 'arg list'
    
  2. buildCcflags 変数の導入: buildCcflags という新しいスライス型の変数が var 宣言に追加されました。この変数は、-ccflags オプションで指定された引数を格納するために使用されます。[]string 型であることから、複数の引数をスペース区切りで受け取ることが想定されます。

    @@ -99,6 +101,7 @@ var buildX bool               // -x flag
     var buildO = cmdBuild.Flag.String("o", "", "output file")
     var buildWork bool           // -work flag
     var buildGcflags []string    // -gcflags flag
    +var buildCcflags []string    // -ccflags flag
     var buildLdflags []string    // -ldflags flag
     var buildGccgoflags []string // -gccgoflags flag
    
  3. コマンドラインフラグの登録: addBuildFlags 関数内で、buildCcflags 変数を cmd.Flag.Var を使ってコマンドラインフラグとして登録しています。(*stringsFlag)(&buildCcflags) は、stringsFlag 型(Goの flag パッケージの Value インターフェースを実装しているカスタム型)に buildCcflags をキャストすることで、スペース区切りの文字列をスライスとしてパースできるようにしています。

    @@ -146,6 +149,7 @@ func addBuildFlags(cmd *Command) {
     	cmd.Flag.BoolVar(&buildX, "x", false, "")
     	cmd.Flag.BoolVar(&buildWork, "work", false, "")
     	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
    +\tcmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
    
  4. Cコンパイラ呼び出しへの引数追加: gcToolchain 型の cc メソッドが変更されました。このメソッドは、GoのツールチェインがC言語のソースファイルをコンパイルする際にCコンパイラ(5c, 6c, 8cなど)を呼び出すロジックを含んでいます。

    変更前は、Cコンパイラに渡す引数がハードコードされていました。

    return b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",
    	"-I", objdir, "-I", inc, "-o", ofile,
    	"-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)
    

    変更後は、buildCcflags の内容が stringList ヘルパー関数を通じて既存の引数リストに結合され、Cコンパイラに渡されるようになりました。stringList は、複数の引数スライスや個別の文字列を結合して単一の []string を生成するユーティリティ関数であると推測されます。

    @@ -1277,9 +1281,8 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,\n func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {\n \tinc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))\n \tcfile = mkAbs(p.Dir, cfile)\n-\treturn b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",\n-\t\t"-I", objdir, "-I", inc, "-o", ofile,\n-\t\t"-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)\n+\targs := stringList(tool(archChar+"c"), "-FVw", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)\n+\treturn b.run(p.Dir, p.ImportPath, args)\n }\
    

    この変更により、ユーザーが -ccflags で指定した任意の引数が、Cコンパイラの呼び出し時に動的に追加されるようになります。

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

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

  1. 行 60-61: -ccflags の説明が追加されました。

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -60,6 +60,8 @@ The build flags are shared by the build, install, run, and test commands:
     	-x
     	\t\tprint the commands.
    
    +\t-ccflags 'arg list'
    +\t\targuments to pass on each 5c, 6c, or 8c compiler invocation
     	-compiler name
     	\t\tname of compiler to use, as in runtime.Compiler (gccgo or gc)
     	-gccgoflags 'arg list'
    
  2. 行 99-101: buildCcflags 変数が宣言されました。

    @@ -99,6 +101,7 @@ var buildX bool               // -x flag
     var buildO = cmdBuild.Flag.String("o", "", "output file")
     var buildWork bool           // -work flag
     var buildGcflags []string    // -gcflags flag
    +var buildCcflags []string    // -ccflags flag
     var buildLdflags []string    // -ldflags flag
     var buildGccgoflags []string // -gccgoflags flag
    
  3. 行 146-149: addBuildFlags 関数内で buildCcflags がコマンドラインフラグとして登録されました。

    @@ -146,6 +149,7 @@ func addBuildFlags(cmd *Command) {
     	cmd.Flag.BoolVar(&buildX, "x", false, "")
     	cmd.Flag.BoolVar(&buildWork, "work", false, "")
     	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
    +\tcmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
     	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
    
  4. 行 1277-1281: gcToolchain.cc メソッド内でCコンパイラへの引数リストに buildCcflags が追加されました。

    @@ -1277,9 +1281,8 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,\n func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {\n \tinc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))\n \tcfile = mkAbs(p.Dir, cfile)\n-\treturn b.run(p.Dir, p.ImportPath, tool(archChar+"c"), "-FVw",\n-\t\t"-I", objdir, "-I", inc, "-o", ofile,\n-\t\t"-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)\n+\targs := stringList(tool(archChar+"c"), "-FVw", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-DGOOS_"+goos, "-DGOARCH_"+goarch, cfile)\n+\treturn b.run(p.Dir, p.ImportPath, args)\n }\
    

コアとなるコードの解説

  • -ccflags 'arg list' の追加: これはユーザー向けのドキュメント変更であり、go build コマンドのヘルプメッセージに新しいオプションが追加されたことを示します。これにより、ユーザーは go build -h を実行した際に -ccflags の存在と用途を知ることができます。

  • var buildCcflags []string の宣言: buildCcflags は、go build コマンドが実行される際に、-ccflags オプションで指定されたすべての引数を文字列のスライスとして保持するためのグローバル変数です。この変数が存在することで、プログラムの他の部分から -ccflags の値にアクセスできるようになります。

  • cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", ""): この行は、Goの標準 flag パッケージを使用して、buildCcflags 変数をコマンドラインフラグ -ccflags に関連付けています。stringsFlag は、おそらく flag.Value インターフェースを実装したカスタム型で、コマンドラインから渡された文字列(例: "-ccflags='-Wall -O2'")をパースして、buildCcflags スライスに個々の引数(例: ["-Wall", "-O2"])として格納する役割を担っています。これにより、ユーザーは複数のCコンパイラフラグを単一の -ccflags オプションで指定できるようになります。

  • args := stringList(tool(archChar+"c"), ..., buildCcflags, ...) および return b.run(p.Dir, p.ImportPath, args): この部分が、実際にCコンパイラに -ccflags で指定された引数を渡す核心的な変更です。 gcToolchain.cc メソッドは、C言語のソースファイルをコンパイルするためにCコンパイラ(tool(archChar+"c")、例えば 5c, 6c, 8c)を呼び出します。 変更前は、Cコンパイラに渡す引数が固定されていましたが、変更後は stringList 関数を使って、既存の必須引数(-FVw, -I, -o, -DGOOS_, -DGOARCH_ など)に加えて、buildCcflags の内容が動的に追加されるようになりました。 b.run メソッドは、指定されたディレクトリで、指定されたインポートパスのコンテキストで、指定されたコマンド(Cコンパイラ)と引数(args)を実行します。これにより、ユーザーが -ccflags で指定した任意のコンパイラオプションが、Cコンパイラの実際の呼び出しに反映されるようになります。

関連リンク

  • Go Change-Id: I2222222222222222222222222222222222222222 (コミットメッセージの https://golang.org/cl/6260047 に対応するGoのコードレビューシステム (Gerrit) のチェンジリストID)
  • Go Issue Tracker: このコミットが解決した、または関連するGoのIssueがある場合、ここに記載されます。コミットメッセージには直接的なIssue番号の記載はありませんが、通常は関連するIssueが存在します。

参考にした情報源リンク

  • Goの公式ドキュメント: go build コマンドのオプションに関する公式ドキュメント。
  • cgoに関するGoの公式ドキュメント: cgo の使い方とGoとCの相互運用に関する詳細。
  • Plan 9 from Bell Labs: Goのツールチェインが使用するPlan 9系のコンパイラに関する背景情報。
  • Goのソースコードリポジトリ: src/cmd/go/build.go ファイルの現在のバージョンや、関連するコミット履歴を確認するためのリポジトリ。
  • Goのコードレビューシステム (Gerrit): コミットメッセージに記載されているチェンジリスト https://golang.org/cl/6260047 は、この変更が提案され、レビューされた場所です。
    • Go Code Review
    • このリンクから、コミットに至るまでの議論や、レビュー担当者からのコメントなどを確認できます。
  • Dave Cheneyのブログや記事: コミットの作者であるDave CheneyはGoコミュニティで著名な開発者であり、彼のブログや記事がこの変更の背景や意図についてさらに詳しい情報を提供している可能性があります。
  • Goのコンパイラフラグに関する議論: Goのメーリングリストやフォーラムでの -gcflags, -ldflags などに関する議論。