[インデックス 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プログラムの場合、GOOS
と GOARCH
環境変数を設定するだけで、異なるオペレーティングシステムやアーキテクチャ向けのバイナリを簡単に生成できます。しかし、CGO(GoからCコードを呼び出すメカニズム)を使用する場合、状況はより複雑になります。CGOを使用するGoプログラムは、C/C++ライブラリに依存するため、GoツールチェインはCコードをコンパイルするためにCツールチェイン(gcc
や clang
など)に依存します。
この「ホストリンキング」のプロセスにおいて、Goリンカーは外部のCリンカーを呼び出して、GoのオブジェクトファイルとCのオブジェクトファイル、および必要なCライブラリを結合します。この際、Goリンカーが外部リンカーに渡す引数の中には、特定のリンカー(例えば gcc
)には有効でも、別のリンカー(例えば clang
)には認識されないものや、現在のリンキングステップでは不要なものが含まれる可能性があります。
このような場合、clang
はデフォルトで認識しない引数に対して警告を発します。ビルドシステムによっては、これらの警告がエラーとして扱われる (-Werror
フラグなど) ことがあり、その結果、ビルドが失敗する可能性があります。このコミットは、clang
が発するこれらの不要な警告を抑制し、ビルドプロセスの安定性と互換性を向上させることを目的としています。特に、Goのビルドシステムが様々な環境やツールチェインで動作することを保証するために、このような細かな調整が必要となります。
前提知識の解説
- Goリンカー (
cmd/ld
またはcmd/link
): Goツールチェインの重要なコンポーネントであり、コンパイルされたGoパッケージとその依存関係を単一の実行可能バイナリに結合する役割を担います。Goのリンカーは、Goで書かれた内部リンカーを使用することも、gcc
やclang
のような外部リンカーを使用することもできます。CGOを使用する場合、外部リンカーが頻繁に利用されます。 - CGO: GoプログラムからC言語のコードを呼び出すためのGoの機能です。CGOを使用すると、既存のCライブラリを利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。CGOを使用するプログラムは、Goのコンパイラだけでなく、Cコンパイラ(
gcc
やclang
)も必要とします。 - ホストリンキング (Host Linking): クロスコンパイルの文脈で、ターゲットシステムではなく、ビルドを実行しているホストシステム上のCツールチェインとライブラリを使用してリンクを行うプロセスを指します。CGOを使用する場合、GoプログラムはホストのCリンカーを呼び出して、CコードとGoコードを結合します。
clang
: LLVMプロジェクトの一部であるC、C++、Objective-C、Objective-C++コンパイラです。モダンで高速なコンパイラとして広く利用されています。-Qunused-arguments
(Clangフラグ):clang
コンパイラに渡されたコマンドライン引数のうち、現在のコンパイルステップで実際に使用されない引数に関する警告を抑制するためのフラグです。例えば、リンカーにのみ関連するフラグがコンパイルフェーズで渡された場合などに発生する警告を抑制します。これは、コード内の未使用の変数やパラメータに関する警告とは異なります。
技術的詳細
このコミットの技術的な核心は、Goリンカーが外部のCリンカーとして clang
を使用しているかどうかを検出し、その場合にのみ特定のフラグを追加するという点にあります。
-
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つ増やすことを意味します。これにより、バッファオーバーフローを防ぎ、新しい引数を安全に追加できるようになります。 -
clang
の検出とフラグの追加: 追加されたコードブロックは以下の通りです。if(strstr(argv[0], "clang") != nil) argv[argc++] = "-Qunused-arguments";
argv[0]
は、外部リンカーとして呼び出される実行可能ファイルのパス(または名前)を指します。strstr(argv[0], "clang") != nil
は、argv[0]
の文字列内に "clang" という部分文字列が含まれているかどうかをチェックします。これにより、現在使用されている外部リンカーがclang
であるかどうかを判断します。例えば、/usr/bin/clang
やclang-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リンカーを呼び出して最終的な実行可能ファイルを生成する際の主要なロジックを含んでいます。
-
malloc
のサイズ変更:argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]);
この行は、外部リンカーに渡されるコマンドライン引数を保持するためのポインタ配列argv
のメモリを割り当てています。以前は13
だった定数が14
に変更されています。これは、新しく追加される-Qunused-arguments
という引数に対応するために、配列に1つ余分なスロットを確保する必要があるためです。nhostobj
はホストオブジェクトファイルの数、nldflag
はリンカーフラグの数、c
はその他の引数の数を表します。 -
clang
の検出とフラグの追加:if(strstr(argv[0], "clang") != nil) argv[argc++] = "-Qunused-arguments";
このコードブロックは、
argv
配列に引数を追加していく途中に挿入されています。strstr(argv[0], "clang") != nil
は、argv[0]
(これは外部リンカーの実行可能パス、例えば/usr/bin/clang
やclang
そのもの)が "clang" という文字列を含んでいるかどうかをチェックします。これにより、現在使用されている外部リンカーがclang
であることを識別します。- 条件が真(つまり
clang
が使用されている)の場合、argv[argc++] = "-Qunused-arguments";
が実行されます。これは、-Qunused-arguments
という文字列リテラルをargv
配列の現在のargc
インデックス位置に格納し、その後argc
をインクリメントして、次の引数を追加する準備をします。
この変更により、Goのビルドシステムは、clang
を外部リンカーとして使用する際に、clang
が発する可能性のある不要な警告を自動的に抑制し、ビルドの成功率を高めることができます。
関連リンク
- Go言語のクロスコンパイルに関する公式ドキュメントやブログ記事
- Clangのコマンドラインオプションに関する公式ドキュメント
- Goのリンカー (
cmd/ld
) の設計に関するドキュメントやソースコード
参考にした情報源リンク
- Go cmd/ld linker: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHsKdrCVmSGf1TV3T6pMHFITU1pzFXYIo9EM48uyezMch2Kc4Y1DZQUkUmAKZFelAbFlKhI-sqakxzjhtT9LC5BwRpXSItNYYqXYoPUL3bbhk1a_ehhISjFSqeoV1FmMr8QRfzGNzyj51Ra7iKYxyXMm-FY5NOHd16cZHLif3VlCr6GxascJfY=
- clang -Qunused-arguments: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHVu691ftd4Vh1HyFFttOfbPKvBUHgB217A9q6NYLbqnfW0R9KqFa6grgBVAtdDb-Ft8_JyajPg4YWiSyAlSULz1nM59hcqQsjdX1HIRcTcIoSqDJGyDstzHn_K9bABBuDh5DaKbPO0ctYPhHzGtZuk0F5V_8oQqBTyVYKcUN9CMOw==
- Go host linking cross compilation: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE1QUCKiAfnn4j017br6ywascOOLDEgHj3aAdmBHOMWpl0yrKDujOTxyfigUpm48sINeDAeU3HiyfRncCxQp45dn1n7swmiuoB3mr9DmuM4jePtTcPQRjbfdS-BYuWvUfaKsCqBnpeB6ao4lzP9RiGIUuiat56F5XQ=