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

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

このコミットは、Go言語のビルドシステムにおいて、Cコンパイラとしてclangのサポートを導入し、既存のgccとの互換性を維持しながら、ビルドプロセスをより柔軟にすることを目指しています。特に、cgo(GoとCの相互運用機能)のビルドにおいてclangが適切に動作するように、様々な調整が行われています。

コミット

commit 6d888f1e1b81bd2545e5da710d37a5a0ddce71d5
Author: Russ Cox <rsc@golang.org>
Date:   Fri Feb 15 13:37:43 2013 -0800

    build: clang support
    
    This works with at least one version of clang
    that existed at one moment in time.
    No guarantees about clangs past or future.
    
    To try:
            CC=clang all.bash
    
    It does not work with the Xcode clang,
    because that clang fails at printing a useful answer
    to:
            clang -print-libgcc-file-name
    The clang that works prints a full path name for
    that command, not just "libgcc.a".
    
    Fixes #4713.
    
    R=iant, minux.ma
    CC=golang-dev
    https://golang.org/cl/7323068

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

https://github.com/golang/go/commit/6d888f1e1b81bd2545e5da710d37a5a0ddce71d5

元コミット内容

Goのビルドシステムにclangコンパイラのサポートを追加します。この変更は、特定のバージョンのclangで動作することが確認されていますが、将来のバージョンや過去のバージョンでの動作は保証されません。

clangを試すには、CC=clang all.bashを実行します。

Xcodeに付属するclangでは動作しません。これは、Xcodeのclangclang -print-libgcc-file-nameコマンドに対して有用な回答(完全なパス名)を返さず、単に"libgcc.a"とだけ返すためです。動作するclangは、このコマンドに対して完全なパス名を返します。

このコミットは、Issue #4713を修正します。

変更の背景

このコミットの主な背景は、Goのビルドプロセス、特にcgoを使用する際に、gccだけでなくclangもCコンパイラとして利用できるようにすることです。これにより、ユーザーはより多様な開発環境でGoをビルドできるようになります。

コミットメッセージに記載されているように、特定のclangバージョンでの動作が確認されており、Xcodeのclangとの互換性の問題も指摘されています。これは、clangのバージョンや配布元によって挙動が異なる場合があるため、Goのビルドシステムがそれらの差異に対応する必要があったことを示唆しています。

また、Issue #4713の修正とあることから、既存のビルドシステムがclangで問題を起こしていたか、あるいはclangサポートが求められていたことが伺えます。

前提知識の解説

  • Go言語のビルドシステム: Go言語は、独自のビルドツール(go buildなど)を持っており、ソースコードをコンパイルして実行可能ファイルを生成します。C言語のコードと連携するcgoを使用する場合、Goのビルドツールは外部のCコンパイラ(通常はgcc)を呼び出します。
  • cgo: Go言語とC言語のコードを相互に呼び出すためのメカニズムです。cgoを使用すると、Goプログラム内でCのライブラリを利用したり、CのコードからGoの関数を呼び出したりできます。cgoは、Goのソースコード内の特別なコメント(import "C")を解析し、Cコンパイラを呼び出してCコードをコンパイルし、Goのコードとリンクします。
  • gcc (GNU Compiler Collection): 広く使われているオープンソースのコンパイラコレクションで、C、C++、Objective-C、Fortran、Ada、Goなどの多くのプログラミング言語をサポートしています。Linux環境ではデファクトスタンダードのCコンパイラです。
  • clang: LLVMプロジェクトの一部として開発されているC、C++、Objective-C、Objective-C++コンパイラです。gccに比べてコンパイル速度が速い、エラーメッセージが分かりやすいなどの特徴があり、macOSのXcodeなど、多くの環境で採用されています。
  • 環境変数 CC: 多くのUnix系システムやビルドシステムで、Cコンパイラを指定するために使用される環境変数です。例えば、CC=clangと設定すると、ビルドプロセスはデフォルトのgccではなくclangを使用しようとします。
  • all.bash / make.bash / run.bash: Goのソースコードリポジトリに含まれるシェルスクリプトで、Goのツールチェイン全体をビルドしたり、テストを実行したりするために使用されます。これらはGoのビルドシステムの低レベルな部分を制御します。
  • gccgo: GCCのフロントエンドとして実装されたGoコンパイラです。Goの標準コンパイラ(gc)とは異なる実装であり、GCCの最適化やバックエンドを利用できます。このコミットでは、gccgcToolchainという内部的な名称がgccgoToolchainに統一されています。
  • リンカフラグ (-Wl,-(-Wl,-)): gccclangなどのコンパイラがリンカに渡すオプションの一部です。これらのフラグは、リンカに対して特定のライブラリグループを囲むように指示し、循環参照を持つライブラリが正しくリンクされるようにするために使用されます。

技術的詳細

このコミットは、GoのビルドシステムがclangをCコンパイラとして認識し、適切に利用できるようにするための複数の変更を含んでいます。

  1. Cコンパイラの選択の柔軟性向上:

    • src/cmd/cgo/gcc.go内のgccName()関数が変更され、環境変数CCが優先的にCコンパイラとして使用されるようになりました。これにより、ユーザーはCC=clangのように設定することで、ビルド時にclangを選択できるようになります。
    • misc/cgo/testso/test.bashsrc/make.bashなどのシェルスクリプトも、ハードコードされたgccの代わりに$(go env CC)${CC:-gcc}を使用するように変更され、CC環境変数の利用がビルドシステム全体にわたって適用されるようになりました。
  2. clang固有のコンパイラフラグとエラーハンドリング:

    • src/cmd/cgo/gcc.goでは、clangが使用されている場合に-ferror-limit=0(エラー数の制限なし)と-Wno-unneeded-internal-declaration(不要な内部宣言に関する警告を抑制)というフラグが追加されるようになりました。これは、clanggccとは異なる警告やエラーを出す可能性があり、それらに対応するためのものです。
    • cgoがCコードをスニッフィング(型推論)する際のエラーメッセージの解析ロジックが拡張され、clangが生成する可能性のある異なるエラーメッセージ(例: declaration does not declare anything, unexpected type name)にも対応できるようになりました。
  3. デバッグ情報の生成方法の調整:

    • src/cmd/dist/build.cでは、デバッグ情報の生成フラグがコンパイラによって条件付けされるようになりました。clangの場合は-gが、それ以外(主にgcc)の場合は-ggdbが使用されます。これは、両コンパイラがデバッグ情報を生成する際の推奨フラグが異なるためです。
  4. gccgoToolchainへの名称統一:

    • src/cmd/go/build.go内で、GoのGCCフロントエンドを扱う内部的な型名がgccgcToolchainからgccgoToolchainに一貫して変更されました。これは機能的な変更ではなく、コードの可読性と命名規則の統一を目的としたリファクタリングです。
  5. リンカオプションの調整:

    • src/cmd/go/build.gogccgoToolchainld関数において、リンカフラグが-Wl,-(-Wl,-)で囲まれるようになりました。これは、特に循環参照を持つライブラリをリンクする際に、リンカが正しく依存関係を解決できるようにするための標準的な手法です。
  6. レース検出器テストの条件付け:

    • src/run.bashでは、レース検出器のテストがCC環境変数に*gcc*が含まれる場合にのみ実行されるように変更されました。これは、当時のclangがレース検出器の機能と完全に互換性がなかったか、あるいは問題があったため、gccを使用している場合にのみテストを実行するように制限したものです。

これらの変更により、Goのビルドシステムはclangをより適切にサポートし、異なるCコンパイラ環境でのビルドの信頼性を向上させています。

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

  • include/libc.h: ARGBEGINマクロの内部で、未使用の式結果に関する警告を抑制するために(void)キャストが追加されました。
  • misc/cgo/testso/test.bash: gccの代わりに$(go env CC)を使用するように変更され、Cコンパイラが環境変数CCで指定可能になりました。
  • src/cmd/cgo/gcc.go:
    • #lineディレクティブの開始行が0から1に変更されました。
    • guessKinds関数で、clangが生成する可能性のある追加のエラーメッセージパターンに対応するようになりました。
    • gccName()関数がCC環境変数を優先的に使用するように変更されました。
    • clangが使用されている場合に、-ferror-limit=0-Wno-unneeded-internal-declarationフラグが追加されるようになりました。
  • src/cmd/dist/build.c:
    • proto_gccargsから-ggdbが削除されました。
    • コンパイラがclangであるかどうかに応じて、-gまたは-ggdbを条件付きで追加するロジックが導入されました。
  • src/cmd/go/build.go:
    • gccgcToolchainという型名がgccgoToolchainに一貫してリネームされました。
    • gccgoToolchainld関数で、リンカフラグが-Wl,-(-Wl,-)で囲まれるようになりました。
  • src/cmd/go/env.go: CC環境変数がGoのビルド環境にエクスポートされるようになりました。
  • src/make.bash: cmd/dist/distのビルドに${CC:-gcc}を使用するように変更され、CC環境変数が尊重されるようになりました。
  • src/run.bash: レース検出器のテストが、CC環境変数に*gcc*が含まれる場合にのみ実行されるように条件が追加されました。

コアとなるコードの解説

このコミットの最も重要な変更は、GoのビルドシステムがCコンパイラとしてclangをサポートするための基盤を確立した点です。

src/cmd/cgo/gcc.gogccName()関数は、cgoがCコンパイラを決定する際の中心的なロジックです。この関数がos.Getenv("CC")を優先するように変更されたことで、Goのビルドプロセス全体でCC環境変数がCコンパイラの選択に影響を与えるようになりました。これは、misc/cgo/testso/test.bashsrc/make.bashなどのシェルスクリプトが$(go env CC)${CC:-gcc}を使用するように変更されたことと合わせて、Goのビルドシステムがより汎用的なCコンパイラ選択メカニズムを持つようになったことを意味します。

また、src/cmd/cgo/gcc.goclang固有のコンパイラフラグ(-ferror-limit=0, -Wno-unneeded-internal-declaration)が追加されたことは、clanggccとは異なるデフォルトの挙動や警告レベルを持つことへの対応を示しています。これにより、cgoが生成するCコードがclangでコンパイルされる際に、不必要な警告やエラーでビルドが中断されることを防ぎます。

デバッグ情報の生成に関する変更(src/cmd/dist/build.c)も重要です。gccclangでは、デバッグ情報を生成するための推奨されるフラグが異なる場合があります。このコミットでは、コンパイラの種類に応じて適切なデバッグフラグ(-gまたは-ggdb)を動的に選択することで、両方のコンパイラで最適なデバッグ情報が生成されるようにしています。

最後に、src/run.bashにおけるレース検出器テストの条件付けは、当時のclangとレース検出器の間の既知の非互換性に対処するための実用的な措置です。これにより、clangを使用している場合にテストが失敗するのを防ぎ、ビルドの安定性を保っています。

これらの変更は、Goのビルドシステムが特定のCコンパイラに依存するのではなく、より広範なCコンパイラ環境に対応できるように進化していることを示しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (cgo): https://pkg.go.dev/cmd/cgo
  • GCC公式ウェブサイト: https://gcc.gnu.org/
  • LLVM Clang公式ウェブサイト: https://clang.llvm.org/
  • 環境変数 CC について: (一般的なUnix/Linuxのドキュメントやmakeのドキュメントを参照)
  • リンカオプション -Wl,-(-Wl,-) について: (GCC/Clangのドキュメントやリンカのmanページを参照)
  • Goのビルドシステムに関する情報: (Goのソースコードリポジトリ内のdoc/go1.txtsrc/cmd/go/以下のコード)