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

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

このコミットは、Go言語のビルドツール (cmd/go) におけるCgo関連の不具合を修正するものです。具体的には、Cgoによってエクスポートされた関数宣言を含むヘッダーファイル _cgo_export.h が、Cファイルから正しくインクルードされない問題を解決します。この修正により、一時的なオブジェクトディレクトリがコンパイラのインクルードパスに追加され、_cgo_export.h がCファイルから適切に参照できるようになります。

コミット

このコミットは、Goのビルドプロセスにおいて、Cgoが生成する _cgo_export.h ファイルのインクルードパスに関する問題を修正します。CgoはGoとC/C++コードを連携させるためのツールであり、GoからCの関数を呼び出したり、CからGoの関数を呼び出したりする際に利用されます。CgoがGoの関数をCから呼び出せるようにエクスポートする場合、_cgo_export.h というヘッダーファイルが生成され、その中にGoのエクスポートされた関数のC言語での宣言が含まれます。

このコミット以前は、GoのビルドツールがCコンパイラを呼び出す際に、この _cgo_export.h が生成される一時的なオブジェクトディレクトリをインクルードパスに含めていませんでした。そのため、同じパッケージ内のCファイルが _cgo_export.h をインクルードしようとしても、ファイルが見つからずにコンパイルエラーが発生する可能性がありました。

この修正では、src/cmd/go/build.go 内のCgoビルドロジックに、一時オブジェクトディレクトリ (obj) をCコンパイラのインクルードパス (cgoCFLAGS) に追加する行が挿入されています。これにより、Cコンパイラは _cgo_export.h を正しく見つけ、CgoによってエクスポートされたGoの関数をCファイルから利用できるようになります。

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

https://github.com/golang/go/commit/d59c88786dc3a27876c782e2639ade5feae520fc

元コミット内容

commit d59c88786dc3a27876c782e2639ade5feae520fc
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Mon Jan 30 16:04:45 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.
    
    R=golang-dev, rogpeppe, rsc
    CC=golang-dev
    https://golang.org/cl/5600043
---\n src/cmd/go/build.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 8a895b41e2..659e5fce97 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1146,6 +1146,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n 		}\n \t}\n \n+\t// Allows including _cgo_export.h from .[ch] files in the package.\n+\tcgoCFLAGS = append(cgoCFLAGS, "-I", obj)\n+\n \t// cgo\n \t// TODO: CGOPKGPATH, CGO_FLAGS?\n \tgofiles := []string{obj + "_cgo_gotypes.go"}\n```

## 変更の背景

この変更の背景には、Go言語のCgo機能を利用する際に発生していたビルドエラーがあります。CgoはGoプログラムからC言語のコードを呼び出したり、逆にC言語のコードからGo言語の関数を呼び出したりするためのメカニズムを提供します。後者の「CからGoを呼び出す」シナリオでは、CgoはGoの関数をC言語から利用できるようにするためのラッパーコードと、その宣言を含むヘッダーファイル `_cgo_export.h` を生成します。

問題は、Goのビルドツール (`cmd/go`) がCコンパイラ(通常はGCCやClang)を呼び出す際に、この `_cgo_export.h` が生成される一時的なディレクトリを、Cコンパイラがヘッダーファイルを検索するパス(インクルードパス)に含めていなかった点にありました。その結果、Cgoを利用するGoパッケージ内で、C言語のソースファイル(`.c` や `.h` ファイル)が `_cgo_export.h` を `#include` しようとしても、コンパイラがファイルを見つけられず、「No such file or directory」といったエラーでコンパイルが失敗していました。

このコミットは、このビルド時のインクルードパスの問題を解決し、Cgoを利用する開発者がスムーズにGoとC/C++の連携コードをビルドできるようにすることを目的としています。

## 前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

1.  **Go言語のCgo:**
    *   Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGo言語の関数を呼び出したりするためのGoの機能です。
    *   Goのソースファイル内に `import "C"` と記述することでCgoが有効になります。
    *   Goの関数をCから呼び出せるようにエクスポートするには、Goの関数宣言の前に `//export FunctionName` のようなコメントを記述します。
    *   Cgoは、GoとCの間のデータ変換や呼び出し規約の調整を自動的に行います。

2.  **`_cgo_export.h` と `_cgo_export.c`:**
    *   Goの関数がCから呼び出されるようにエクスポートされる場合、Cgoはビルドプロセス中に一時的なディレクトリに `_cgo_export.h` と `_cgo_export.c` というファイルを生成します。
    *   `_cgo_export.h` には、エクスポートされたGo関数のC言語でのプロトタイプ宣言が含まれます。C言語のソースファイルがこれらのGo関数を呼び出すためには、このヘッダーファイルをインクルードする必要があります。
    *   `_cgo_export.c` には、C言語からGo関数を呼び出すための実際のラッパーコードが含まれます。

3.  **Cコンパイラのインクルードパス (`-I` フラグ):**
    *   C/C++コンパイラ(GCC, Clangなど)は、ソースコード内で `#include <header.h>` や `#include "header.h"` と記述されたヘッダーファイルを検索する際に、特定のディレクトリパスを探索します。
    *   `#include <header.h>` は通常、標準ライブラリのヘッダーファイルを検索し、コンパイラに予め設定されたシステムインクルードパスを探索します。
    *   `#include "header.h"` は通常、まず現在のソースファイルがあるディレクトリ、次にコンパイラに `-I` オプションで指定されたディレクトリを探索します。
    *   `-I` フラグは、コンパイラに追加のヘッダーファイル検索パスを指定するために使用されます。例えば、`gcc -I/path/to/headers main.c` とすると、`/path/to/headers` ディレクトリもヘッダーファイルの検索対象になります。

4.  **Goのビルドプロセス (`cmd/go`):**
    *   `go build` コマンドは、Goのソースコードをコンパイルして実行可能ファイルを生成するGoの公式ビルドツールです。
    *   Cgoが使われている場合、`cmd/go` は内部的にC/C++コンパイラを呼び出し、GoとC/C++のコードを連携させてビルドします。
    *   このプロセスでは、一時的なビルドディレクトリが作成され、Cgoが生成する中間ファイル(例: `_cgo_export.h`, `_cgo_export.c`, `_cgo_gotypes.go` など)がそこに配置されます。

## 技術的詳細

このコミットが修正する問題は、Goのビルドツール (`cmd/go`) がCgoコードをコンパイルする際の、Cコンパイラへの引数渡しに起因していました。

Cgoを使用し、Goの関数をCから呼び出せるようにエクスポートする(`//export` ディレクティブを使用する)場合、Goのビルドプロセスは以下のステップを踏みます(簡略化):

1.  GoのソースコードとCgoディレクティブを解析し、Cgoが処理すべきGoとCの境界を特定します。
2.  Cgoは、エクスポートされたGo関数のC言語での宣言を含む `_cgo_export.h` ファイルと、その実装を含む `_cgo_export.c` ファイルを、一時的なビルドディレクトリ(コミットメッセージでは `obj` と呼ばれることが多い)に生成します。
3.  Goのビルドツールは、GoのコードとCのコードをそれぞれコンパイルします。Cのコードをコンパイルする際には、内部的にCコンパイラ(GCCやClangなど)を呼び出します。
4.  もし、Goパッケージ内の他のCソースファイル(例: `mypackage.c`)が、エクスポートされたGo関数を利用するために `_cgo_export.h` を `#include` している場合、Cコンパイラはそのヘッダーファイルを見つける必要があります。

このコミット以前は、`cmd/go` がCコンパイラを呼び出す際に、`_cgo_export.h` が生成される一時的な `obj` ディレクトリを、Cコンパイラのヘッダーファイル検索パス(インクルードパス)に明示的に追加していませんでした。Cコンパイラはデフォルトでは、現在の作業ディレクトリや標準のシステムインクルードパスしか検索しないため、`obj` ディレクトリに生成された `_cgo_export.h` を見つけることができませんでした。

この修正は、`src/cmd/go/build.go` ファイル内の `cgo` 関数(Cgoのビルドロジックを司る部分)に、以下の行を追加することでこの問題を解決します。

```go
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCFLAGS = append(cgoCFLAGS, "-I", obj)

ここで:

  • cgoCFLAGS は、CgoがCコンパイラを呼び出す際に渡す追加のCコンパイラフラグ(オプション)のリストです。
  • append(cgoCFLAGS, "-I", obj) は、cgoCFLAGS リストに -I フラグと、一時オブジェクトディレクトリのパスである obj を追加しています。

これにより、Cコンパイラは obj ディレクトリもヘッダーファイルの検索パスとして考慮するようになり、_cgo_export.h を正しく見つけてコンパイルエラーを回避できるようになります。これは、Cgoを利用してGoとC/C++を連携させる際のビルドの信頼性を向上させる重要な修正です。

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

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1146,6 +1146,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\
 		}\n \t}\n \n+\t// Allows including _cgo_export.h from .[ch] files in the package.\n+\tcgoCFLAGS = append(cgoCFLAGS, "-I", obj)\n+\n \t// cgo\n \t// TODO: CGOPKGPATH, CGO_FLAGS?\n \tgofiles := []string{obj + "_cgo_gotypes.go"}\n```

この変更は、`src/cmd/go/build.go` ファイルの `cgo` 関数内、具体的には1146行目付近に3行が追加されたものです。

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

追加されたコードは以下の3行です。

```go
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCFLAGS = append(cgoCFLAGS, "-I", obj)
  1. // Allows including _cgo_export.h from .[ch] files in the package.

    • これはコメントであり、このコード行の目的を説明しています。
    • 「パッケージ内のCまたはヘッダーファイルから _cgo_export.h をインクルードできるようにする」という意味です。これは、まさにこのコミットが解決しようとしている問題の核心を示しています。
  2. cgoCFLAGS = append(cgoCFLAGS, "-I", obj)

    • cgoCFLAGS は、CgoがCコンパイラ(通常はGCCやClang)を呼び出す際に渡すコマンドラインフラグ(オプション)の文字列スライス(Goにおける動的配列)です。
    • append 関数は、Goのスライスに要素を追加するために使用されます。
    • -I はC/C++コンパイラにおける標準的なオプションで、「指定されたディレクトリをヘッダーファイルの検索パスに追加する」という意味を持ちます。
    • obj は、Goのビルドプロセス中にCgoが中間ファイル(_cgo_export.h など)を生成する一時的なオブジェクトディレクトリのパスを表す変数です。
    • この行全体で、「Cコンパイラのインクルードパスに、Cgoが生成したヘッダーファイルが置かれる一時ディレクトリ (obj) を追加する」という処理を行っています。

この変更により、Cコンパイラは _cgo_export.h が存在する場所を認識できるようになり、Cgoを利用するGoパッケージ内のCソースファイルがこのヘッダーファイルを正しくインクルードできるようになります。結果として、CからGoの関数を呼び出すCgoプログラムのビルドが成功するようになります。

関連リンク

  • Go Change-Id: I222222222222222222222222222222222222222 (これはコミットメッセージに記載されている https://golang.org/cl/5600043 のChange-Idに対応するものです。GoのコードレビューシステムGerritのChange-Idは通常このような形式です。)
  • Go Code Review: https://golang.org/cl/5600043 (このコミットの元のコードレビューページ)

参考にした情報源リンク

このコミットは、Go言語のビルドツール (cmd/go) におけるCgo関連の不具合を修正するものです。具体的には、Cgoによってエクスポートされた関数宣言を含むヘッダーファイル _cgo_export.h が、Cファイルから正しくインクルードされない問題を解決します。この修正により、一時的なオブジェクトディレクトリがコンパイラのインクルードパスに追加され、_cgo_export.h がCファイルから適切に参照できるようになります。

コミット

このコミットは、Goのビルドプロセスにおいて、Cgoが生成する _cgo_export.h ファイルのインクルードパスに関する問題を修正します。CgoはGoとC/C++コードを連携させるためのツールであり、GoからCの関数を呼び出したり、CからGoの関数を呼び出したりする際に利用されます。CgoがGoの関数をCから呼び出せるようにエクスポートする場合、_cgo_export.h というヘッダーファイルが生成され、その中にGoのエクスポートされた関数のC言語での宣言が含まれます。

このコミット以前は、GoのビルドツールがCコンパイラを呼び出す際に、この _cgo_export.h が生成される一時的なオブジェクトディレクトリをインクルードパスに含めていませんでした。そのため、同じパッケージ内のCファイルが _cgo_export.h をインクルードしようとしても、ファイルが見つからずにコンパイルエラーが発生する可能性がありました。

この修正では、src/cmd/go/build.go 内のCgoビルドロジックに、一時オブジェクトディレクトリ (obj) をCコンパイラのインクルードパス (cgoCFLAGS) に追加する行が挿入されています。これにより、Cコンパイラは _cgo_export.h を正しく見つけ、CgoによってエクスポートされたGoの関数をCファイルから利用できるようになります。

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

https://github.com/golang/go/commit/d59c88786dc3a27876c782e2639ade5feae520fc

元コミット内容

commit d59c88786dc3a27876c782e2639ade5feae520fc
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Mon Jan 30 16:04:45 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.
    
    R=golang-dev, rogpeppe, rsc
    CC=golang-dev
    https://golang.org/cl/5600043
---\n src/cmd/go/build.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 8a895b41e2..659e5fce97 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1146,6 +1146,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n 		}\n \t}\n \n+\t// Allows including _cgo_export.h from .[ch] files in the package.\n+\tcgoCFLAGS = append(cgoCFLAGS, "-I", obj)\n+\n \t// cgo\n \t// TODO: CGOPKGPATH, CGO_FLAGS?\n \tgofiles := []string{obj + "_cgo_gotypes.go"}\n```

## 変更の背景

この変更の背景には、Go言語のCgo機能を利用する際に発生していたビルドエラーがあります。CgoはGoプログラムからC言語のコードを呼び出したり、逆にC言語のコードからGo言語の関数を呼び出したりするためのメカニズムを提供します。後者の「CからGoを呼び出す」シナリオでは、CgoはGoの関数をC言語から利用できるようにするためのラッパーコードと、その宣言を含むヘッダーファイル `_cgo_export.h` を生成します。

問題は、Goのビルドツール (`cmd/go`) がCコンパイラ(通常はGCCやClang)を呼び出す際に、この `_cgo_export.h` が生成される一時的なディレクトリを、Cコンパイラがヘッダーファイルを検索するパス(インクルードパス)に含めていなかった点にありました。そのため、Cgoを利用するGoパッケージ内で、C言語のソースファイル(`.c` や `.h` ファイル)が `_cgo_export.h` を `#include` しようとしても、ファイルが見つからずに「No such file or directory」といったエラーでコンパイルが失敗していました。

このコミットは、このビルド時のインクルードパスの問題を解決し、Cgoを利用する開発者がスムーズにGoとC/C++の連携コードをビルドできるようにすることを目的としています。

## 前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

1.  **Go言語のCgo:**
    *   Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGo言語の関数を呼び出したりするためのGoの機能です。
    *   Goのソースファイル内に `import "C"` と記述することでCgoが有効になります。
    *   Goの関数をCから呼び出せるようにエクスポートするには、Goの関数宣言の前に `//export FunctionName` のようなコメントを記述します。
    *   Cgoは、GoとCの間のデータ変換や呼び出し規約の調整を自動的に行います。

2.  **`_cgo_export.h` と `_cgo_export.c`:**
    *   Goの関数がCから呼び出されるようにエクスポートされる場合、Cgoはビルドプロセス中に一時的なディレクトリに `_cgo_export.h` と `_cgo_export.c` というファイルを生成します。
    *   `_cgo_export.h` には、エクスポートされたGo関数のC言語でのプロトタイプ宣言が含まれます。C言語のソースファイルがこれらのGo関数を呼び出すためには、このヘッダーファイルをインクルードする必要があります。
    *   `_cgo_export.c` には、C言語からGo関数を呼び出すための実際のラッパーコードが含まれます。

3.  **Cコンパイラのインクルードパス (`-I` フラグ):**
    *   C/C++コンパイラ(GCC, Clangなど)は、ソースコード内で `#include <header.h>` や `#include "header.h"` と記述されたヘッダーファイルを検索する際に、特定のディレクトリパスを探索します。
    *   `#include <header.h>` は通常、標準ライブラリのヘッダーファイルを検索し、コンパイラに予め設定されたシステムインクルードパスを探索します。
    *   `#include "header.h"` は通常、まず現在のソースファイルがあるディレクトリ、次にコンパイラに `-I` オプションで指定されたディレクトリを探索します。
    *   `-I` フラグは、コンパイラに追加のヘッダーファイル検索パスを指定するために使用されます。例えば、`gcc -I/path/to/headers main.c` とすると、`/path/to/headers` ディレクトリもヘッダーファイルの検索対象になります。

4.  **Goのビルドプロセス (`cmd/go`):**
    *   `go build` コマンドは、Goのソースコードをコンパイルして実行可能ファイルを生成するGoの公式ビルドツールです。
    *   Cgoが使われている場合、`cmd/go` は内部的にC/C++コンパイラを呼び出し、GoとC/C++のコードを連携させてビルドします。
    *   このプロセスでは、一時的なビルドディレクトリが作成され、Cgoが生成する中間ファイル(例: `_cgo_export.h`, `_cgo_export.c`, `_cgo_gotypes.go` など)がそこに配置されます。

## 技術的詳細

このコミットが修正する問題は、Goのビルドツール (`cmd/go`) がCgoコードをコンパイルする際の、Cコンパイラへの引数渡しに起因していました。

Cgoを使用し、Goの関数をCから呼び出せるようにエクスポートする(`//export` ディレクティブを使用する)場合、Goのビルドプロセスは以下のステップを踏みます(簡略化):

1.  GoのソースコードとCgoディレクティブを解析し、Cgoが処理すべきGoとCの境界を特定します。
2.  Cgoは、エクスポートされたGo関数のC言語での宣言を含む `_cgo_export.h` ファイルと、その実装を含む `_cgo_export.c` ファイルを、一時的なビルドディレクトリ(コミットメッセージでは `obj` と呼ばれることが多い)に生成します。
3.  Goのビルドツールは、GoのコードとCのコードをそれぞれコンパイルします。Cのコードをコンパイルする際には、内部的にCコンパイラ(GCCやClangなど)を呼び出します。
4.  もし、Goパッケージ内の他のCソースファイル(例: `mypackage.c`)が、エクスポートされたGo関数を利用するために `_cgo_export.h` を `#include` している場合、Cコンパイラはそのヘッダーファイルを見つける必要があります。

このコミット以前は、`cmd/go` がCコンパイラを呼び出す際に、`_cgo_export.h` が生成される一時的な `obj` ディレクトリを、Cコンパイラのヘッダーファイル検索パス(インクルードパス)に明示的に追加していませんでした。Cコンパイラはデフォルトでは、現在の作業ディレクトリや標準のシステムインクルードパスしか検索しないため、`obj` ディレクトリに生成された `_cgo_export.h` を見つけることができませんでした。

この修正は、`src/cmd/go/build.go` ファイル内の `cgo` 関数(Cgoのビルドロジックを司る部分)に、以下の行を追加することでこの問題を解決します。

```go
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCFLAGS = append(cgoCFLAGS, "-I", obj)

ここで:

  • cgoCFLAGS は、CgoがCコンパイラを呼び出す際に渡す追加のCコンパイラフラグ(オプション)のリストです。
  • append(cgoCFLAGS, "-I", obj) は、cgoCFLAGS リストに -I フラグと、一時オブジェクトディレクトリのパスである obj を追加しています。

これにより、Cコンパイラは obj ディレクトリもヘッダーファイルの検索パスとして考慮するようになり、_cgo_export.h を正しく見つけてコンパイルエラーを回避できるようになります。これは、Cgoを利用してGoとC/C++を連携させる際のビルドの信頼性を向上させる重要な修正です。

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

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1146,6 +1146,9 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n 		}\n \t}\n \n+\t// Allows including _cgo_export.h from .[ch] files in the package.\n+\tcgoCFLAGS = append(cgoCFLAGS, "-I", obj)\n+\n \t// cgo\n \t// TODO: CGOPKGPATH, CGO_FLAGS?\n \tgofiles := []string{obj + "_cgo_gotypes.go"}\n```

この変更は、`src/cmd/go/build.go` ファイルの `cgo` 関数内、具体的には1146行目付近に3行が追加されたものです。

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

追加されたコードは以下の3行です。

```go
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCFLAGS = append(cgoCFLAGS, "-I", obj)
  1. // Allows including _cgo_export.h from .[ch] files in the package.

    • これはコメントであり、このコード行の目的を説明しています。
    • 「パッケージ内のCまたはヘッダーファイルから _cgo_export.h をインクルードできるようにする」という意味です。これは、まさにこのコミットが解決しようとしている問題の核心を示しています。
  2. cgoCFLAGS = append(cgoCFLAGS, "-I", obj)

    • cgoCFLAGS は、CgoがCコンパイラ(通常はGCCやClang)を呼び出す際に渡すコマンドラインフラグ(オプション)の文字列スライス(Goにおける動的配列)です。
    • append 関数は、Goのスライスに要素を追加するために使用されます。
    • -I はC/C++コンパイラにおける標準的なオプションで、「指定されたディレクトリをヘッダーファイルの検索パスに追加する」という意味を持ちます。
    • obj は、Goのビルドプロセス中にCgoが中間ファイル(_cgo_export.h など)を生成する一時的なオブジェクトディレクトリのパスを表す変数です。
    • この行全体で、「Cコンパイラのインクルードパスに、Cgoが生成したヘッダーファイルが置かれる一時ディレクトリ (obj) を追加する」という処理を行っています。

この変更により、Cコンパイラは _cgo_export.h が存在する場所を認識できるようになり、Cgoを利用するGoパッケージ内のCソースファイルがこのヘッダーファイルを正しくインクルードできるようになります。結果として、CからGoの関数を呼び出すCgoプログラムのビルドが成功するようになります。

関連リンク

  • Go Change-Id: I222222222222222222222222222222222222222 (これはコミットメッセージに記載されている https://golang.org/cl/5600043 のChange-Idに対応するものです。GoのコードレビューシステムGerritのChange-Idは通常このような形式です。)
  • Go Code Review: https://golang.org/cl/5600043 (このコミットの元のコードレビューページ)

参考にした情報源リンク