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

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

このコミットは、Go言語のリンカー (cmd/ld) において、ホストリンキング時に clang を使用する場合に -Qunused-arguments フラグを渡すように変更を加えるものです。これにより、clang が認識しない引数に関する警告を抑制し、ビルドプロセスの堅牢性を向上させます。

コミット

commit 1b42d25ae3cd831d2b437744c49385b15b29fd63
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sat Mar 29 17:10:25 2014 -0400

    cmd/ld: pass -Qunused-arguments to clang during host linking.
    
    LGTM=iant
    R=iant
    CC=golang-codereviews
    https://golang.org/cl/82140043

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

https://github.com/golang/go/commit/1b42d25ae3cd831d2b437744c49385b15b29fd63

元コミット内容

このコミットは、Goリンカー (cmd/ld) が外部リンカーとして clang を呼び出す際に、追加のコマンドライン引数 -Qunused-arguments を渡すように修正します。これにより、clang が認識しない、または現在のコンパイルステップでは使用しない引数に対して警告を発することを防ぎます。具体的には、src/cmd/ld/lib.c ファイルが変更され、hostlink 関数内で clang が使用されている場合にこのフラグが追加されるようになります。また、引数リストを格納するためのメモリ割り当てサイズが1つ増えています。

変更の背景

Go言語は、その強力なクロスコンパイル機能で知られています。純粋なGoプログラムの場合、GOOSGOARCH 環境変数を設定するだけで、異なるオペレーティングシステムやアーキテクチャ向けのバイナリを簡単に生成できます。しかし、CGO(GoからCコードを呼び出すメカニズム)を使用する場合、状況はより複雑になります。CGOを使用するGoプログラムは、C/C++ライブラリに依存するため、GoツールチェインはCコードをコンパイルするためにCツールチェイン(gccclang など)に依存します。

この「ホストリンキング」のプロセスにおいて、Goリンカーは外部のCリンカーを呼び出して、GoのオブジェクトファイルとCのオブジェクトファイル、および必要なCライブラリを結合します。この際、Goリンカーが外部リンカーに渡す引数の中には、特定のリンカー(例えば gcc)には有効でも、別のリンカー(例えば clang)には認識されないものや、現在のリンキングステップでは不要なものが含まれる可能性があります。

このような場合、clang はデフォルトで認識しない引数に対して警告を発します。ビルドシステムによっては、これらの警告がエラーとして扱われる (-Werror フラグなど) ことがあり、その結果、ビルドが失敗する可能性があります。このコミットは、clang が発するこれらの不要な警告を抑制し、ビルドプロセスの安定性と互換性を向上させることを目的としています。特に、Goのビルドシステムが様々な環境やツールチェインで動作することを保証するために、このような細かな調整が必要となります。

前提知識の解説

  • Goリンカー (cmd/ld または cmd/link): Goツールチェインの重要なコンポーネントであり、コンパイルされたGoパッケージとその依存関係を単一の実行可能バイナリに結合する役割を担います。Goのリンカーは、Goで書かれた内部リンカーを使用することも、gccclang のような外部リンカーを使用することもできます。CGOを使用する場合、外部リンカーが頻繁に利用されます。
  • CGO: GoプログラムからC言語のコードを呼び出すためのGoの機能です。CGOを使用すると、既存のCライブラリを利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。CGOを使用するプログラムは、Goのコンパイラだけでなく、Cコンパイラ(gccclang)も必要とします。
  • ホストリンキング (Host Linking): クロスコンパイルの文脈で、ターゲットシステムではなく、ビルドを実行しているホストシステム上のCツールチェインとライブラリを使用してリンクを行うプロセスを指します。CGOを使用する場合、GoプログラムはホストのCリンカーを呼び出して、CコードとGoコードを結合します。
  • clang: LLVMプロジェクトの一部であるC、C++、Objective-C、Objective-C++コンパイラです。モダンで高速なコンパイラとして広く利用されています。
  • -Qunused-arguments (Clangフラグ): clang コンパイラに渡されたコマンドライン引数のうち、現在のコンパイルステップで実際に使用されない引数に関する警告を抑制するためのフラグです。例えば、リンカーにのみ関連するフラグがコンパイルフェーズで渡された場合などに発生する警告を抑制します。これは、コード内の未使用の変数やパラメータに関する警告とは異なります。

技術的詳細

このコミットの技術的な核心は、Goリンカーが外部のCリンカーとして clang を使用しているかどうかを検出し、その場合にのみ特定のフラグを追加するという点にあります。

  1. malloc サイズの変更: src/cmd/ld/lib.c 内の hostlink 関数では、外部リンカーに渡すコマンドライン引数を格納するためのメモリが malloc で動的に確保されます。 変更前: argv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]); 変更後: argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]); この変更は、新しく追加される可能性のある -Qunused-arguments フラグのために、引数リストの配列サイズを1つ増やすことを意味します。これにより、バッファオーバーフローを防ぎ、新しい引数を安全に追加できるようになります。

  2. clang の検出とフラグの追加: 追加されたコードブロックは以下の通りです。

    if(strstr(argv[0], "clang") != nil)
        argv[argc++] = "-Qunused-arguments";
    
    • argv[0] は、外部リンカーとして呼び出される実行可能ファイルのパス(または名前)を指します。
    • strstr(argv[0], "clang") != nil は、argv[0] の文字列内に "clang" という部分文字列が含まれているかどうかをチェックします。これにより、現在使用されている外部リンカーが clang であるかどうかを判断します。例えば、/usr/bin/clangclang-3.4 のようなパスでも検出できます。
    • もし clang が検出された場合、argv[argc++] = "-Qunused-arguments"; によって、-Qunused-arguments フラグがコマンドライン引数リストに追加されます。argc++ は、引数の数をインクリメントし、次の引数を追加する位置を準備します。

この変更により、Goリンカーは clang を使用する際に、clang が認識しない引数に関する警告を自動的に抑制するようになります。これは、Goのビルドシステムが様々な環境でよりスムーズに動作するために重要です。特に、クロスコンパイル環境や、特定のビルドシステムが一般的なリンカーフラグをすべてに適用するような場合に役立ちます。

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

変更は src/cmd/ld/lib.c ファイルの hostlink 関数内で行われています。

--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -562,7 +562,7 @@ hostlink(void)\n \t\tp = strchr(p + 1, ' ');\n \t}\n \n-\targv = malloc((13+nhostobj+nldflag+c)*sizeof argv[0]);\n+\targv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]);\n \targc = 0;\n \tif(extld == nil)\n \t\textld = "gcc";\n@@ -605,6 +605,9 @@ hostlink(void)\n \tif(iself)\n \t\targv[argc++] = "-rdynamic";\n \n+\tif(strstr(argv[0], "clang") != nil)\n+\t\targv[argc++] = "-Qunused-arguments";\n+\n \t// already wrote main object file\n \t// copy host objects to temporary directory\n \tfor(i=0; i<nhostobj; i++) {

コアとなるコードの解説

hostlink 関数は、Goリンカーが外部のCリンカーを呼び出して最終的な実行可能ファイルを生成する際の主要なロジックを含んでいます。

  1. malloc のサイズ変更: argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]); この行は、外部リンカーに渡されるコマンドライン引数を保持するためのポインタ配列 argv のメモリを割り当てています。以前は 13 だった定数が 14 に変更されています。これは、新しく追加される -Qunused-arguments という引数に対応するために、配列に1つ余分なスロットを確保する必要があるためです。nhostobj はホストオブジェクトファイルの数、nldflag はリンカーフラグの数、c はその他の引数の数を表します。

  2. clang の検出とフラグの追加:

    if(strstr(argv[0], "clang") != nil)
        argv[argc++] = "-Qunused-arguments";
    

    このコードブロックは、argv 配列に引数を追加していく途中に挿入されています。

    • strstr(argv[0], "clang") != nil は、argv[0](これは外部リンカーの実行可能パス、例えば /usr/bin/clangclang そのもの)が "clang" という文字列を含んでいるかどうかをチェックします。これにより、現在使用されている外部リンカーが clang であることを識別します。
    • 条件が真(つまり clang が使用されている)の場合、argv[argc++] = "-Qunused-arguments"; が実行されます。これは、-Qunused-arguments という文字列リテラルを argv 配列の現在の argc インデックス位置に格納し、その後 argc をインクリメントして、次の引数を追加する準備をします。

この変更により、Goのビルドシステムは、clang を外部リンカーとして使用する際に、clang が発する可能性のある不要な警告を自動的に抑制し、ビルドの成功率を高めることができます。

関連リンク

  • Go言語のクロスコンパイルに関する公式ドキュメントやブログ記事
  • Clangのコマンドラインオプションに関する公式ドキュメント
  • Goのリンカー (cmd/ld) の設計に関するドキュメントやソースコード

参考にした情報源リンク