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

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

このコミットは、Go言語のコマンドラインツール cmd/go における cgo のビルドプロセスに関するバグ修正です。具体的には、cgo が生成する _cgo_export.h ヘッダーファイルが、パッケージ内のC言語ファイルから正しくインクルードされるように、一時オブジェクトディレクトリをインクルードパスに追加する変更を行っています。

コミット

commit 9fb24b944812fe555b09395ff341c9818d98e25b
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Wed Feb 1 16:07:32 2012 -0200

    cmd/go: fix including of _cgo_export.h

    This will add the temporary object directory into the lookup
    path so that cgo-exported function declarations may be
    included from C files.

    This was previously applied by CL 5600043, and apparently
    removed by mistake on CL 5598045.

    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5610054

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

https://github.com/golang/go/commit/9fb24b944812fe555b09395ff341c9818d98e25b

元コミット内容

このコミットの目的は、cmd/go ツールが cgo を使用してGoとC/C++コードを連携させる際に発生する問題を修正することです。具体的には、cgo によってエクスポートされた関数宣言を含む _cgo_export.h ファイルが、同じパッケージ内のC言語ソースファイルから正しくインクルードできないという問題に対処しています。この修正は、一時的なオブジェクトディレクトリをCコンパイラのインクルードパスに追加することで、このヘッダーファイルが見つけられるようにします。

コミットメッセージには、この変更が以前 CL 5600043 で適用されたものの、CL 5598045 で誤って削除されたと記載されています。これは、以前の修正が意図せず元に戻されてしまったため、その修正を再適用するものであることを示唆しています。

変更の背景

Go言語は、C言語のコードをGoプログラムから呼び出すための cgo というメカニズムを提供しています。cgo を使用すると、GoとC/C++のコードを混在させ、相互に呼び出すことができます。このプロセスでは、cgo ツールがGoコードからC関数を呼び出すためのスタブコードや、CコードからGo関数を呼び出すためのヘッダーファイル(_cgo_export.h など)を生成します。

このコミットの背景には、cgo を使用するGoパッケージのビルドプロセスにおいて、生成された _cgo_export.h ファイルがCコンパイラによって見つけられないという問題がありました。_cgo_export.h には、Go側で //export ディレクティブを使ってエクスポートされたGo関数のC言語での宣言が含まれています。C言語のソースファイルがこれらのGo関数を呼び出す場合、このヘッダーファイルをインクルードする必要があります。

しかし、Goのビルドシステムが一時的なビルドディレクトリに _cgo_export.h を生成する際、そのディレクトリがCコンパイラのヘッダー検索パスに含まれていなかったため、Cコンパイラが _cgo_export.h を見つけられず、ビルドエラーが発生していました。

コミットメッセージにある CL 5600043CL 5598045 は、Goプロジェクトの変更リスト(Change List)番号を指します。これは、GoのコードレビューシステムであるGerritにおける変更の識別子です。このコミットは、以前に適用された修正(CL 5600043)が、別の変更(CL 5598045)によって誤って元に戻されてしまったため、その修正を再適用するという経緯を示しています。

前提知識の解説

  • Go言語のビルドプロセス: Goプログラムは go build コマンドによってコンパイルされます。このプロセスには、ソースコードの解析、依存関係の解決、コンパイル、リンクが含まれます。
  • cgo: Go言語とC/C++言語の相互運用を可能にするGoのツールです。GoコードからC関数を呼び出したり、CコードからGo関数を呼び出したりするために使用されます。cgo は、GoとCの間のインターフェースとなるコードを自動生成します。
  • _cgo_export.h: cgo が生成するヘッダーファイルの一つです。Go言語側で //export ディレクティブを使ってC言語から呼び出せるようにエクスポートされたGo関数のC言語でのプロトタイプ宣言が含まれています。C言語のソースファイルがこれらのGo関数を呼び出す場合、このヘッダーファイルをインクルードする必要があります。
  • Cコンパイラ (gcc/clangなど): C/C++ソースコードをコンパイルするためのツールです。ヘッダーファイルを検索する際に、特定のディレクトリパス(インクルードパス)を探索します。
  • CFLAGS: Cコンパイラに渡されるコンパイルオプションを指定するための環境変数またはビルド設定です。-I オプションは、追加のヘッダーファイル検索パスを指定するために使用されます。例えば、-I/path/to/include/path/to/include ディレクトリをヘッダー検索パスに追加します。
  • 一時オブジェクトディレクトリ: Goのビルドプロセスでは、中間ファイルや生成されたコードを一時的に保存するためのディレクトリが作成されます。cgo が生成する _cgo_export.h のようなファイルも、通常この一時ディレクトリに配置されます。

技術的詳細

cgo を使用するGoパッケージをビルドする際、Goツールチェーンは以下の手順を実行します(簡略化されたもの):

  1. GoソースファイルとC/C++ソースファイルを解析し、cgo ディレクティブを処理します。
  2. cgo は、GoとC/C++間のインターフェースコードを生成します。これには、GoからCを呼び出すためのスタブや、CからGoを呼び出すための _cgo_export.h ヘッダーファイルなどが含まれます。これらの生成されたファイルは、通常、一時的なビルドディレクトリに配置されます。
  3. 生成されたC/C++ソースファイル(_cgo_export.c など)と、元のC/C++ソースファイルは、Cコンパイラ(通常はGCCやClang)によってコンパイルされます。
  4. コンパイルされたオブジェクトファイルとGoのオブジェクトファイルがリンクされ、最終的な実行可能ファイルまたはライブラリが生成されます。

この問題は、ステップ3でCコンパイラがC/C++ソースファイルをコンパイルする際に発生しました。C/C++ソースファイルが _cgo_export.h をインクルードしようとしたとき、Cコンパイラのデフォルトのヘッダー検索パスには、cgo_cgo_export.h を生成した一時オブジェクトディレクトリが含まれていませんでした。その結果、Cコンパイラは _cgo_export.h を見つけることができず、「file not found」のようなエラーを報告し、ビルドが失敗していました。

このコミットの修正は、Cコンパイラに渡される CFLAGS に、cgo がファイルを生成する一時オブジェクトディレクトリ(obj 変数で表される)を -I オプションを使って追加することで、この問題を解決します。これにより、Cコンパイラは _cgo_export.h を正しく見つけ、ビルドを続行できるようになります。

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

変更は src/cmd/go/build.go ファイルの cgo 関数内で行われています。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1148,6 +1148,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\
 		}
 	}\

+	// Allows including _cgo_export.h from .[ch] files in the package.
+	cgoCFLAGS = append(cgoCFLAGS, "-I", obj)
+
 	// cgo
 	// TODO: CGOPKGPATH, CGO_FLAGS?
 	gofiles := []string{obj + "_cgo_gotypes.go"}

コアとなるコードの解説

変更は以下の3行の追加です。

	// Allows including _cgo_export.h from .[ch] files in the package.
	cgoCFLAGS = append(cgoCFLAGS, "-I", obj)
  • cgoCFLAGS: これは、cgo がCコンパイラを呼び出す際に使用する CFLAGS のリスト(またはそれに相当するもの)を表すGoのスライス(動的配列)です。
  • append(cgoCFLAGS, "-I", obj): この行は、cgoCFLAGS スライスに2つの要素を追加しています。
    • "-I": これはCコンパイラ(例: gcc)に渡すオプションで、「次の引数をインクルードパスとして追加せよ」という意味です。
    • obj: これは、cgo が一時的に生成するファイル(_cgo_export.h など)が格納されるディレクトリのパスを表す変数です。

この変更により、cgo がCコンパイラを呼び出す際、obj で指定された一時ディレクトリがヘッダーファイルの検索パスに明示的に追加されます。これにより、パッケージ内のCソースファイルが _cgo_export.h をインクルードしようとしたときに、Cコンパイラがそのファイルを正しく見つけられるようになり、ビルドエラーが解消されます。

コメント // Allows including _cgo_export.h from .[ch] files in the package. は、この変更の目的を明確に説明しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード(src/cmd/go/build.go
  • Cコンパイラの -I オプションに関する一般的な知識
  • CL 5600043 golang のWeb検索結果: 検索結果は「go: update to Go 1.22.4」というタイトルで、このコミットが作成された2012年とは大きく異なる日付の変更リストを示していました。これは、Goの変更リスト番号が再利用されるか、または検索エンジンが古い変更リストを正確に特定できなかったためと考えられます。したがって、この特定のCLの内容を直接参照することはできませんでしたが、コミットメッセージの記述からその意図を推測しました。