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

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

このコミットは、Go言語のcgoツールにおける内部的なCコード生成とGCCコンパイラとの連携方法に関する改善です。具体的には、C言語の型情報を取得する際に使用するキーワードをtypeofから__typeof__へ、またGCCの警告抑制オプションを-Wno-allから-wへと変更しています。これらの変更は、cgoが生成するCコードの互換性とコンパイル時の挙動をより堅牢にするためのものです。

コミット

commit c8ddfd9ad179b03e565ad33bda13a75aa9be3ed0
Author: Russ Cox <rsc@golang.org>
Date:   Tue Oct 22 18:33:23 2013 -0400

    cmd/cgo: use __typeof__, -w instead of typeof, -Wno-all
    
    Suggested by iant in earlier CL.
    
    R=golang-dev, bradfitz, iant
    CC=golang-dev
    https://golang.org/cl/14920052

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

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

元コミット内容

cmd/cgo: use __typeof__, -w instead of typeof, -Wno-all
Suggested by iant in earlier CL.

変更の背景

この変更は、cgoツールがCコードを生成し、それをGCCでコンパイルする際の堅牢性と互換性を向上させることを目的としています。

  1. typeofから__typeof__への変更:

    • typeofはGCCが提供するC言語の拡張機能であり、式の型を取得するために使用されます。しかし、typeofというキーワードは、特定のコンテキストでユーザー定義の識別子や他のマクロと衝突する可能性があります。
    • __typeof__も同様にGCCの拡張機能ですが、これはGCCが提供する「組み込み」または「予約済み」のキーワードであることを明示する形式です。二重アンダースコアで始まる名前は、通常、コンパイラによって予約されており、ユーザーコードとの名前衝突のリスクが低減されます。これにより、cgoが生成するCコードの移植性と信頼性が向上します。この変更は、以前の変更リスト(CL)でiantによって提案されたものです。
  2. -Wno-allから-wへの変更:

    • -Wno-allはGCCのコンパイルオプションで、すべての警告を無効にするものです。
    • -wも同様にGCCのコンパイルオプションで、すべての警告を抑制します。-wはより簡潔な形式であり、特定の状況下で-Wno-allよりも優先される場合があります。この変更は、cgoが生成する一時的なCコードをコンパイルする際に、不要な警告を抑制するためのより直接的で一般的な方法を採用したものです。cgoは、GoとCの間の型チェックのために意図的にコンパイルエラーを発生させるコードを生成することがあるため、これらの警告を抑制することは重要です。

これらの変更は、cgoの内部動作をより安定させ、将来的なGCCのバージョンアップや異なるコンパイラ環境への対応を容易にすることを意図しています。

前提知識の解説

  • cgo: Go言語の標準ツールチェーンの一部であり、GoプログラムからC言語の関数を呼び出したり、C言語のデータ型を使用したりするためのブリッジを提供します。また、C言語からGoの関数を呼び出すことも可能です。cgoは、Goのソースコード内に記述された特別なコメント(import "C"ブロック)を解析し、GoとCの間の相互運用に必要なCコードとGoコードを自動生成します。
  • GCC (GNU Compiler Collection): C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラシステムです。cgoは、CコードのコンパイルにGCC(または互換性のあるコンパイラ)を利用します。
  • typeof演算子 (GNU C Extension): C言語の標準には含まれないが、GCCによって提供される拡張機能です。この演算子は、変数や式の型をコンパイル時に取得するために使用されます。例えば、typeof(x)は変数xの型を返します。これは、ジェネリックなマクロや、型に依存しないコードを書く際に非常に便利です。
  • __typeof__演算子: typeofと同様にGCCの拡張機能ですが、二重アンダースコアで囲まれているため、GCCの予約済みキーワードとして扱われます。これにより、ユーザー定義の識別子との名前衝突を避けることができます。GCCのドキュメントでは、通常、__typeof__の使用が推奨されています。
  • GCCの警告オプション:
    • -Wオプションは、特定の種類の警告を有効にするために使用されます(例: -Wallは一般的な警告をすべて有効にする)。
    • -Wno-オプションは、特定の種類の警告を無効にするために使用されます(例: -Wno-unused-variableは未使用変数の警告を無効にする)。
    • -wオプションは、すべての警告を完全に抑制します。これは、デバッグ目的や、警告が意図的である場合に便利です。
    • -Wno-allは、GCCのバージョンによっては存在しないか、-wとは異なる挙動をする場合があります。一般的には、-wが最も広範な警告抑制を提供します。
  • DWARF (Debugging With Attributed Record Formats): プログラムのデバッグ情報を格納するための標準フォーマットです。コンパイラは、デバッグ情報を生成する際にこのフォーマットを使用します。cgoは、Cコードのデバッグ情報を解析してGoの型情報と関連付けるために、DWARF情報を利用することがあります。

技術的詳細

cgoは、GoのコードからCのシンボル(変数、関数、型など)が正しく参照されているかを検証するために、一時的なCコードを生成し、それをコンパイルしてエラーをチェックするメカニズムを持っています。このプロセスにおいて、cgoはCのtypeof演算子を利用して、Goコードから参照されるCシンボルの型を推測します。

このコミットでは、その型推測のロジックにおいて、typeofの代わりに__typeof__を使用するように変更されました。これは、__typeof__がGCCの予約済みキーワードであり、より堅牢な型推測を可能にするためです。例えば、doc.goの例では、cgoが生成するCコードのプレアンブル部分で、typeof(foo)__typeof__(foo)に置き換えられています。これは、fooがCの型、変数、または定数であるかを検証するために、cgoが生成する一時的なCコードスニペットの一部です。

また、cgoが内部的にCコードをコンパイルする際に、GCCのコンパイルオプションとして-Wno-allの代わりに-wを使用するように変更されました。cgoは、GoとCの間の型チェックのために、意図的にコンパイルエラーを発生させるようなCコードを生成することがあります。この際、GCCが大量の警告を出力するのを防ぐために、警告抑制オプションが使用されます。-wは、すべての警告を抑制する最も直接的な方法であり、cgoの内部的なコンパイルプロセスをよりクリーンに保ちます。

これらの変更は、cgoの内部的なコンパイルと型チェックのメカニズムを改善し、異なるGCCのバージョンやコンパイル環境における互換性の問題を軽減することを目的としています。

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

このコミットでは、主に以下の2つのファイルが変更されています。

  1. src/cmd/cgo/doc.go: cgoのドキュメントの一部であり、cgoがどのようにCコードを生成するかを示す例が含まれています。このファイルでは、生成されるCコードの例においてtypeof__typeof__に置き換えられています。
  2. src/cmd/cgo/gcc.go: cgoがGCCコンパイラと連携するためのロジックが含まれています。このファイルでは、実際にCコードを生成する部分と、GCCを呼び出す際のコンパイルオプションが変更されています。

具体的な変更点:

  • src/cmd/cgo/doc.go:

    • void __cgo_f_xxx_1(void) { typeof(foo) *__cgo_undefined__; }void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }
    • typeof(t1) *__cgo__1;__typeof__(t1) *__cgo__1; など、typeof__typeof__に置換されています。
  • src/cmd/cgo/gcc.go:

    • void __cgo_f_xxx_1(void) { typeof(name) *__cgo_undefined__; }void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; }
    • fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\\n", n.C, i)fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\\n", n.C, i)
    • c := append(p.gccBaseCmd(), "-Wno-all", ...)c := append(p.gccBaseCmd(), "-w", ...)
    • t.C.Set("typeof(%s[%d])", sub.C, dt.Count)t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
    • t.C.Set("typeof(unsigned char[%d])", t.Size)t.C.Set("__typeof__(unsigned char[%d])", t.Size) など、同様にtypeofから__typeof__への置換と、GCCの警告オプションの変更が行われています。

コアとなるコードの解説

cgoは、GoのコードからCのシンボルを参照する際に、そのシンボルが実際に存在し、かつ正しい型を持っているかを検証するために、一時的なCコードを生成します。この検証プロセスは、Goのコンパイル時に行われ、GoとCの間の型安全性を確保する上で非常に重要です。

src/cmd/cgo/doc.goに示されているように、cgoは以下のようなCコードスニペットを生成します。

void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; }

このコードは、fooというシンボルがCのコンテキストで有効な型を持っているかをチェックするためのものです。もしfooが未定義であったり、型として使用できないものであったりすると、このCコードのコンパイルは失敗し、cgoはGoのコンパイルエラーとして報告します。__cgo_undefined__のような変数は、実際に使用されることはなく、単に型チェックのトリガーとして機能します。

src/cmd/cgo/gcc.goでは、このCコード生成ロジックと、GCCを呼び出す際のコマンドライン引数が定義されています。

  • 型推測と検証: guessKinds関数やloadDWARF関数内で、Goのコードから参照されるCシンボルの型を特定するために、__typeof__が使用されています。これは、cgoがCのヘッダーファイルを解析し、Goの型システムとCの型システムを橋渡しする上で不可欠な部分です。__cgo__%dのような一時的な変数も、DWARFデバッグ情報から型情報を抽出するために利用されます。
  • コンパイルオプション: gccCmd関数では、GCCを呼び出す際のコマンドライン引数が構築されます。ここで、以前は-Wno-allが使用されていましたが、このコミットで-wに変更されました。これは、cgoが生成するCコードが、意図的にコンパイルエラーを引き起こす可能性のある構造を含んでいるため、GCCからの大量の警告を抑制する必要があるためです。-wは、すべての警告を抑制する最も包括的なオプションです。

これらの変更は、cgoの内部的な型チェックとコンパイルのメカニズムをより堅牢にし、GoとCの相互運用における潜在的な問題を未然に防ぐためのものです。

関連リンク

参考にした情報源リンク