[インデックス 17843] ファイルの概要
このコミットは、Go言語のcmd/cgo
ツール内のsrc/cmd/cgo/gcc.go
ファイルに対する変更です。cmd/cgo
は、GoプログラムがC言語のコードを呼び出すためのメカニズムを提供するツールです。gcc.go
ファイルは、cgo
がCコンパイラ(GCCやClangなど)を呼び出す際のコマンドライン引数や設定を管理する役割を担っています。具体的には、Cコードのコンパイル時に使用されるフラグの調整が行われています。
コミット
cmd/cgo
が-fno-eliminate-unused-debug-types
フラグの使用を停止するコミットです。このフラグは、OS X上のllvm-gcc
フロントエンドにおけるデバッグ情報の問題を解決するために2010年1月に導入されましたが、clang
への移行とコンパイラの進化により不要となり、むしろ新しいバージョンのclang
ではエラーとなるため削除されました。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/adda33483dbf9fe4753ecc54b56590d60c962acb
元コミット内容
commit adda33483dbf9fe4753ecc54b56590d60c962acb
Author: Russ Cox <rsc@golang.org>
Date: Mon Oct 28 22:21:26 2013 -0400
cmd/cgo: stop using -fno-eliminate-unused-debug-types
This flag was added in January 2010, in CL 181102, to fix issue 497.
(Numbers were just shorter back then.) The fix was for OS X machines
and the llvm-gcc frontend.
In July 2011 we had to change the way we get enum values, because
there were no flags available to force Xcode's llvm-gcc to include the
enum names and values in DWARF debug output.
We now use clang, not llvm-gcc, on OS X machines.
Earlier versions of clang printed a warning about not knowing the flag.
Newer versions of clang now make that an error.
That is:
- The flag was added for OS X machines.
- The flag is no longer necessary on OS X machines.
- The flag now breaks some OS X machines.
Remove it.
I have run the original program from issue 497 successfully
without the flag on both OS X and Linux machines.
Fixes #6678.
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/18850043
変更の背景
この変更の背景には、Go言語のcgo
ツールがCコードをコンパイルする際に使用するコンパイラと、デバッグ情報の生成に関する歴史的な経緯があります。
元々、2010年1月にGo Issue 497を修正するために、cmd/cgo
は-fno-eliminate-unused-debug-types
というコンパイラフラグを使用するようになりました。この問題は、特にOS X環境でllvm-gcc
フロントエンドを使用している際に、デバッグ情報(特に列挙型(enum)の値)がDWARFデバッグ出力に含まれないというものでした。このフラグは、未使用のデバッグ型がコンパイラによって削除されるのを防ぐことで、この問題を回避していました。
しかし、2011年7月には、Xcodeのllvm-gcc
が列挙型の名前と値をDWARFデバッグ出力に強制的に含めるための利用可能なフラグがないため、列挙型の値を取得する方法を変更する必要がありました。
さらに重要な変更は、OS X環境におけるGoのビルドシステムがllvm-gcc
からclang
へと移行したことです。初期のclang
バージョンでは、この-fno-eliminate-unused-debug-types
フラグは認識されず、単なる警告として扱われていました。しかし、新しいバージョンのclang
では、この未知のフラグがエラーとして扱われるようになりました。
この状況により、以下の問題が発生しました。
- このフラグは元々OS X環境向けに追加されたものでした。
- 現在では、OS X環境においてもこのフラグは不要になっています。
- さらに、このフラグが存在することで、一部のOS X環境でビルドが失敗するようになりました。
これらの理由から、このフラグを削除することが決定されました。コミットメッセージには、Issue 497の元のプログラムが、このフラグなしでOS XとLinuxの両方で正常に動作することが確認されたと記載されています。これにより、このフラグがもはや必要ないことが裏付けられました。
前提知識の解説
cmd/cgo
cmd/cgo
は、Go言語のツールチェーンの一部であり、GoプログラムがC言語の関数やデータ構造を呼び出すことを可能にするためのツールです。GoはCとの相互運用性(FFI: Foreign Function Interface)をサポートしており、cgo
はその橋渡しをします。Goのソースコード内にimport "C"
という記述があると、cgo
はGoとCの間の呼び出し規約を処理するためのラッパーコードを生成します。これにより、GoコードからC関数を呼び出したり、CコードからGo関数を呼び出したりすることが可能になります。
-fno-eliminate-unused-debug-types
これはGCC(GNU Compiler Collection)系のコンパイラで使用されるコンパイラフラグの一つです。
debug-types
: デバッグ情報に含まれる型情報(構造体、列挙型など)を指します。eliminate-unused
: コンパイラが最適化の一環として、コード内で使用されていないエンティティ(関数、変数、型など)を削除する処理を指します。no-
: その最適化を無効にする、という意味です。
したがって、-fno-eliminate-unused-debug-types
は、「コード内で直接使用されていないデバッグ型であっても、コンパイラがそれらをデバッグ情報から削除しないようにする」という指示になります。これは、デバッガがプログラムの実行中に、ソースコードには明示的に現れないが、デバッグ目的で参照したい型情報(例えば、特定の構造体の内部構造や列挙型の全メンバーなど)にアクセスできるようにするために重要となる場合があります。
DWARF
DWARF(Debugging With Attributed Record Formats)は、プログラムのソースコードとコンパイルされたバイナリコードの間のマッピングを記述するための標準的なデバッグ情報フォーマットです。デバッガはDWARF情報を使用して、実行中のプログラムの変数、関数、ソースコードの行番号などを理解し、開発者がブレークポイントを設定したり、変数の値を検査したりすることを可能にします。
DWARFは、以下のような情報を含みます。
- ソースファイルと行番号のマッピング: 実行アドレスがどのソースファイルのどの行に対応するか。
- 変数情報: 変数の名前、型、メモリ上の位置。
- 関数情報: 関数の名前、引数、戻り値、ローカル変数。
- 型情報: 構造体、共用体、列挙型、配列などの定義。
このコミットの文脈では、特に列挙型(enum)の値がDWARFデバッグ出力に含まれるかどうかが問題となっていました。
llvm-gcc
と clang
llvm-gcc
: これは、GCCのフロントエンドとLLVM(Low Level Virtual Machine)のバックエンドを組み合わせたコンパイラです。AppleがmacOS(旧OS X)のXcode開発ツールの一部として提供していました。GCCの構文解析や意味解析の能力と、LLVMの最適化およびコード生成の能力を組み合わせることで、パフォーマンスと柔軟性を両立させようとしたものです。しかし、GCCとLLVMの統合は複雑であり、最終的にはAppleはllvm-gcc
の開発を中止しました。clang
:clang
は、LLVMプロジェクトの一部として開発されたC、C++、Objective-C、Objective-C++コンパイラのフロントエンドです。GCCとは異なり、clang
は最初からLLVMのアーキテクチャに合わせて設計されており、よりモジュール化され、高速で、診断メッセージが優れているとされています。Appleはllvm-gcc
の後継としてclang
を積極的に採用し、現在ではmacOSの主要なC/C++/Objective-Cコンパイラとなっています。
このコミットは、GoのビルドシステムがOS X上でllvm-gcc
からclang
へと移行したことによって、以前のllvm-gcc
向けの回避策が不要になっただけでなく、clang
では問題を引き起こすようになったという状況を反映しています。
Go Issue 497 と Go Issue 6678
- Go Issue 497: "cmd/cgo: enum values not in debug info on OS X" (OS Xでcgoのenum値がデバッグ情報に含まれない)
- この問題は、OS X上の
llvm-gcc
でコンパイルされたCコードの列挙型が、デバッグ情報(DWARF)に適切に含まれないために、デバッガで列挙型のシンボリックな値(例えば、RED
ではなく0
)が表示されないというものでした。-fno-eliminate-unused-debug-types
フラグは、この問題を一時的に解決するために導入されました。
- この問題は、OS X上の
- Go Issue 6678: "cmd/cgo: clang warns about -fno-eliminate-unused-debug-types" (cgoが-fno-eliminate-unused-debug-typesについてclangが警告を出す)
- この問題は、
clang
が-fno-eliminate-unused-debug-types
フラグを認識せず、警告(後にエラー)を出すようになったことを報告しています。これは、clang
への移行に伴い、以前のllvm-gcc
向けのフラグが互換性の問題を引き起こすようになったことを示しています。このコミットは、このIssue 6678を修正するものです。
- この問題は、
技術的詳細
このコミットの技術的詳細を理解するためには、コンパイラのデバッグ情報生成の仕組みと、異なるコンパイラ間のフラグの互換性の問題に焦点を当てる必要があります。
デバッグ情報の生成と最適化
コンパイラは、ソースコードを機械語に変換する際に、デバッグ情報を生成することができます。このデバッグ情報は、デバッガがプログラムの実行を追跡し、変数や型を検査するために不可欠です。しかし、コンパイラは通常、生成されるバイナリのサイズを削減し、コンパイル時間を短縮するために、様々な最適化を行います。その一つが、使用されていないコードやデータの削除です。
-fno-eliminate-unused-debug-types
フラグは、この「使用されていないデバッグ型の削除」という最適化を無効にするためのものでした。Goのcgo
ツールは、Cコードをコンパイルする際に、Goコードから参照される可能性のあるCの型情報(特に列挙型)がデバッグ情報に確実に含まれるようにする必要がありました。OS Xのllvm-gcc
が、Goコードから直接参照されていない列挙型を「未使用」と判断してデバッグ情報から削除してしまう問題があったため、このフラグが導入されました。これにより、デバッガがGoとCの境界を越えてデバッグする際に、C側の列挙型のシンボリックな値を見ることができないという問題が回避されました。
コンパイラの進化とフラグの互換性
コンパイラは常に進化しており、新しい機能が追加されたり、古い機能が非推奨になったり、動作が変更されたりします。特に、llvm-gcc
からclang
への移行は、単なるバージョンアップではなく、異なる設計思想を持つコンパイラへの切り替えでした。
clang
は、LLVMの設計原則に基づいており、GCCとは異なる内部構造を持っています。そのため、GCC系のコンパイラで使用されるすべてのフラグがclang
でそのまま機能するわけではありません。初期のclang
バージョンでは、認識できないフラグに対しては単に警告を出すだけでしたが、コンパイラの厳格化や、将来的な互換性の問題を避けるために、新しいバージョンではそのような未知のフラグをエラーとして扱うようになりました。
この変更は、GoのビルドシステムがOS X上でclang
をデフォルトのCコンパイラとして使用するようになった結果として必然的に発生しました。-fno-eliminate-unused-debug-types
フラグは、もはやclang
では必要ないだけでなく、ビルドプロセスを中断させる原因となっていました。
影響の検証
コミットメッセージには、「I have run the original program from issue 497 successfully without the flag on both OS X and Linux machines.」と記載されています。これは、このフラグがなくても、元々解決しようとしていた問題(Issue 497)が再発しないことを確認したことを意味します。これは、cgo
が列挙型の値を取得する方法が2011年7月に変更されたことや、clang
がデバッグ情報をより適切に生成するようになったことなど、他の改善によって、このフラグの必要性がなくなったことを示唆しています。
このコミットは、Goのビルドシステムが特定のプラットフォーム(OS X)のコンパイラの進化に適応し、不要になった、あるいは問題を引き起こすようになったビルドフラグを削除することで、ビルドの安定性と互換性を維持するための重要なメンテナンス作業であったと言えます。
コアとなるコードの変更箇所
src/cmd/cgo/gcc.go
ファイルのgccCmd()
関数内で、Cコンパイラに渡す引数のリストから-fno-eliminate-unused-debug-types
フラグが削除されています。
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -742,13 +742,12 @@ func gccTmp() string {
// the input.
func (p *Package) gccCmd() []string {
c := append(p.gccBaseCmd(),
- "-w", // no warnings
- "-Wno-error", // warnings are not errors
- "-o"+gccTmp(), // write object to tmp
- "-gdwarf-2", // generate DWARF v2 debugging symbols
- "-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
- "-c", // do not link
- "-xc", // input language is C
+ "-w", // no warnings
+ "-Wno-error", // warnings are not errors
+ "-o"+gccTmp(), // write object to tmp
+ "-gdwarf-2", // generate DWARF v2 debugging symbols
+ "-c", // do not link
+ "-xc", // input language is C
)
if strings.Contains(c[0], "clang") {
c = append(c,
コアとなるコードの解説
変更はsrc/cmd/cgo/gcc.go
内のgccCmd()
関数にあります。この関数は、cgo
がCコンパイラ(通常はGCCまたはClang)を呼び出す際に使用するコマンドライン引数のスライス([]string
)を構築します。
元のコードでは、append
関数を使って、基本的なコンパイラコマンド(p.gccBaseCmd()
)に続けて、以下のようなフラグを追加していました。
"-w", // no warnings
"-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
"-c", // do not link
"-xc", // input language is C
このコミットでは、このリストから-fno-eliminate-unused-debug-types
の行が完全に削除されています。
"-w", // no warnings
"-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-c", // do not link
"-xc", // input language is C
この変更により、cgo
がCコードをコンパイルする際に、Cコンパイラに対して-fno-eliminate-unused-debug-types
フラグが渡されなくなります。これは、前述の「変更の背景」と「技術的詳細」で説明したように、このフラグがもはや必要なく、むしろ新しいバージョンのclang
ではビルドエラーを引き起こすようになったためです。
その他のフラグ(-w
, -Wno-error
, -o
, -gdwarf-2
, -c
, -xc
)はそのまま残されており、これらは引き続きCコードのコンパイルとデバッグ情報の生成(DWARF v2形式)に必要不可欠なものです。
この変更は、cgo
のビルドプロセスを現代のコンパイラ環境(特にOS X上のclang
)に適合させ、ビルドの安定性を向上させることを目的としています。
関連リンク
- Go Issue 497: https://github.com/golang/go/issues/497
- Go Issue 6678: https://github.com/golang/go/issues/6678
- Go Change List 181102 (original addition of the flag): https://golang.org/cl/181102 (Note: This link format might be outdated, but it refers to the original CL.)
- Go Change List 18850043 (this commit's CL): https://golang.org/cl/18850043
参考にした情報源リンク
- Go言語公式ドキュメント (cgo): https://go.dev/blog/c-go-is-not-c
- GCC Command Options (Debugging Options): https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html (
-fno-eliminate-unused-debug-types
に関する情報) - DWARF Debugging Standard: https://dwarfstd.org/
- LLVM Project: https://llvm.org/
- Clang Compiler: https://clang.llvm.org/
- Wikipedia - LLVM-GCC: https://en.wikipedia.org/wiki/LLVM-GCC
- Stack Overflow / 関連フォーラム (特定のコンパイラフラグやデバッグ情報に関する議論)
- Go言語のソースコードリポジトリ (過去のコミット履歴や関連ファイルの調査)
- Google検索 (上記キーワードを用いた情報収集)