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

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

このコミットは、Go言語のリンカ (cmd/ld) において、gcc の呼び出しが失敗した際のエラーメッセージから、不要な cursym (現在のシンボル) の表示を削除する変更です。これにより、エラーメッセージがより簡潔になり、ユーザーにとって分かりやすくなります。

コミット

commit 0c2b980c49649635d502d9dd98f277f8480fbada
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sat Apr 20 02:44:16 2013 +0800

    cmd/ld: don't show cursym in gcc invocation failure message
    before:
    fmt.statictmp_0731:/usr/local/go/pkg/tool/linux_amd64/6l: running gcc failed: unsuccessful exit status 0x100
    now:
    /usr/local/go/pkg/tool/linux_amd64/6l: running gcc failed: unsuccessful exit status 0x100
    
    R=golang-dev, iant, r
    CC=golang-dev
    https://golang.org/cl/8827045

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

https://github.com/golang/go/commit/0c2b980c49649635d502d9dd98f277f8480fbada

元コミット内容

このコミットの目的は、Go言語のリンカ (cmd/ld) が外部の gcc コマンドを呼び出して失敗した際に表示されるエラーメッセージの改善です。具体的には、エラーメッセージの先頭に表示されていた cursym (現在のシンボル) の情報が削除されます。

変更前は、例えば fmt.statictmp_0731:/usr/local/go/pkg/tool/linux_amd64/6l: running gcc failed: unsuccessful exit status 0x100 のように、fmt.statictmp_0731 のようなシンボル名が余計に表示されていました。このコミットにより、メッセージは /usr/local/go/pkg/tool/linux_amd64/6l: running gcc failed: unsuccessful exit status 0x100 のように、より簡潔で直接的なものになります。

変更の背景

Go言語のリンカは、特定の状況下でC言語のコードをリンクするために gcc を利用することがあります。この gcc の呼び出しが何らかの理由で失敗した場合、リンカはエラーメッセージを出力します。

変更前のエラーメッセージには、cursym (current symbol) と呼ばれる情報が含まれていました。これは、リンカが現在処理しているシンボルを示す内部的な変数です。しかし、gcc の呼び出し失敗というコンテキストにおいて、この cursym の情報はユーザーにとってほとんど意味がなく、むしろエラーメッセージを冗長で分かりにくいものにしていました。

この変更の背景には、エラーメッセージの可読性とユーザーエクスペリエンスの向上が挙げられます。不要な情報を削除することで、ユーザーは問題の核心(gcc の実行失敗)をより迅速に把握できるようになります。これは、Goツールチェイン全体のエラー報告の品質を高めるための継続的な取り組みの一環と考えられます。

前提知識の解説

このコミットを理解するためには、以下のGo言語のツールチェインとリンカに関する基本的な知識が必要です。

  • Goツールチェイン: Go言語のプログラムをビルド、テスト、実行するためのツール群の総称です。これには、コンパイラ (go tool compile)、アセンブラ (go tool asm)、リンカ (go tool link または cmd/ld) などが含まれます。
  • cmd/ld (Goリンカ): Go言語のリンカは、コンパイルされたオブジェクトファイル(.o ファイル)やアーカイブファイル(.a ファイル)を結合し、実行可能なバイナリを生成する役割を担います。Goプログラムは通常、Goランタイムと標準ライブラリを静的にリンクして単一の実行ファイルを生成します。
  • gcc: GNU Compiler Collection の略で、C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラ群です。Go言語のツールチェインは、Cgo(GoとCの相互運用機能)を使用する場合や、特定のシステムライブラリをリンクする場合など、一部のケースで外部の gcc を利用することがあります。
  • cursym: Goリンカの内部で使われる変数で、リンカが現在処理しているシンボル(関数、変数など)を指します。デバッグ目的や内部的なエラー報告のために使用されることがあります。
  • S: Goリンカのコードベースにおける Sym (Symbol) 構造体のゼロ値、または無効なシンボルを意味する定数です。cursym = S と設定することは、cursym を「現在処理中のシンボルがない」状態、または「無効なシンボル」状態にリセットすることを意味します。
  • diag 関数: Goリンカ内でエラーメッセージや診断メッセージを出力するために使用される関数です。通常、diag("format string", args...) の形式で呼び出され、指定されたフォーマットでメッセージを標準エラー出力に書き込みます。

技術的詳細

このコミットの技術的な核心は、src/cmd/ld/lib.c ファイル内の hostlink 関数におけるエラー報告の改善です。hostlink 関数は、Goリンカが外部のホストリンカ(この場合は gcc)を呼び出す際の処理を担当しています。

変更前は、hostlink 関数内で gcc の呼び出しに関連するエラー(ファイルの作成失敗、書き込み失敗、gcc の実行失敗など)が発生した場合、diag 関数がエラーメッセージを出力していました。この際、diag 関数は内部的に cursym の値も参照し、その結果、エラーメッセージの先頭に cursym が指すシンボル名が付加されていました。

このコミットでは、hostlink 関数内の以下の3つのエラーパスの直前に cursym = S; という行が追加されています。

  1. create 関数(ファイル作成)が失敗した場合
  2. close 関数(ファイル書き込み完了)が失敗した場合
  3. runcmd 関数(gcc 実行)が失敗した場合

cursym = S; と設定することで、これらのエラーが発生した時点で cursym が無効なシンボルを指すようにリセットされます。これにより、その直後に呼び出される diag 関数が cursym の値を参照しても、有効なシンボル名が出力されなくなり、結果としてエラーメッセージから不要なシンボル情報が取り除かれます。

この変更は、エラーメッセージのコンテキストと cursym の関連性を考慮したものです。gcc の呼び出し失敗は、Goリンカが特定のGoシンボルを処理している最中に発生するエラーというよりも、外部プロセスの実行環境に関するエラーに近い性質を持っています。そのため、この種のエラーメッセージにGoの内部シンボル情報を付加することは適切ではないと判断されたと考えられます。

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

--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -687,6 +687,7 @@ hostlink(void)\n 		argv[argc++] = p;\n 		w = create(p, 1, 0775);\n 		if(w < 0) {\n+\t\t\tcursym = S;\n \t\t\tdiag(\"cannot create %s: %r\", p);\n \t\t\terrorexit();\n \t\t}\n@@ -698,6 +699,7 @@ hostlink(void)\n \t\t\tlen -= n;\n \t\t}\n \t\tif(close(w) < 0) {\n+\t\t\tcursym = S;\n \t\t\tdiag(\"cannot write %s: %r\", p);\n \t\t\terrorexit();\n \t\t}\n@@ -730,6 +732,7 @@ hostlink(void)\n 	}\n \n 	if(runcmd(argv) < 0) {\n+\t\tcursym = S;\n \t\tdiag(\"%s: running %s failed: %r\", argv0, argv[0]);\n \t\terrorexit();\n \t}\n```

## コアとなるコードの解説

変更は `src/cmd/ld/lib.c` ファイル内の `hostlink` 関数に集中しています。この関数は、Goリンカが外部のホストリンカ(通常は `gcc`)を呼び出して、最終的な実行ファイルを生成するプロセスの一部を担います。

追加された3行の `cursym = S;` は、それぞれ異なるエラー発生ポイントの直前に配置されています。

1.  **`if(w < 0) { cursym = S; diag("cannot create %s: %r", p); errorexit(); }`**
    *   このブロックは、`create(p, 1, 0775)` が失敗した場合、つまり一時ファイルなどの作成に失敗した場合に実行されます。
    *   `cursym = S;` が追加されたことで、ファイル作成失敗のエラーメッセージが出力される際に、`cursym` が指すシンボル情報がメッセージに含まれなくなります。ファイル作成は特定のGoシンボルとは直接関係ないため、この変更は適切です。

2.  **`if(close(w) < 0) { cursym = S; diag("cannot write %s: %r", p); errorexit(); }`**
    *   このブロックは、`close(w)` が失敗した場合、つまり作成したファイルへの書き込みが完了した後にファイルを閉じる際にエラーが発生した場合に実行されます。
    *   ここでも `cursym = S;` が追加され、ファイル書き込みエラーメッセージから不要なシンボル情報が削除されます。

3.  **`if(runcmd(argv) < 0) { cursym = S; diag("%s: running %s failed: %r", argv0, argv[0]); errorexit(); }`**
    *   このブロックは、`runcmd(argv)` が失敗した場合、つまり `gcc` などの外部コマンドの実行に失敗した場合に実行されます。
    *   これがコミットメッセージで示されている主要なケースです。`gcc` の実行失敗は、Goの特定のシンボル処理とは直接関連しないため、`cursym` をリセットすることで、エラーメッセージがより汎用的で分かりやすいものになります。

これらの変更により、`hostlink` 関数内で発生する `gcc` 関連のエラーメッセージは、Goリンカが内部的に処理しているシンボルとは無関係な、よりクリーンな形式で出力されるようになります。これは、デバッグや問題解決を行う開発者にとって、エラーメッセージのノイズを減らし、本質的な問題に集中しやすくする改善です。

## 関連リンク

*   Go言語の公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
*   Go言語のツールチェインに関するドキュメント (Go 1.4 Toolchain): [https://go.dev/doc/go1.4#toolchain](https://go.dev/doc/go1.4#toolchain) (当時のバージョンに近い情報)
*   Go言語のリンカのソースコード (`src/cmd/ld`): [https://github.com/golang/go/tree/master/src/cmd/ld](https://github.com/golang/go/tree/master/src/cmd/ld)

## 参考にした情報源リンク

*   Go言語のコミット履歴 (GitHub): [https://github.com/golang/go/commits/master](https://github.com/golang/go/commits/master)
*   Go言語のコードレビューシステム (Gerrit): [https://go-review.googlesource.com/](https://go-review.googlesource.com/) (コミットメッセージに記載されている `https://golang.org/cl/8827045` はGerritの変更リストへのリンクです)
*   `gcc` の公式ウェブサイト: [https://gcc.gnu.org/](https://gcc.gnu.org/)
*   Go言語のリンカの内部構造に関する議論やドキュメント (一般的な情報源):
    *   "Go's Linker" by Russ Cox: [https://research.swtch.com/go-linker](https://research.swtch.com/go-linker) (Goリンカの仕組みを理解する上で非常に有用な記事ですが、このコミットの直接的な情報源ではありません)
    *   Go言語のIssueトラッカー: [https://github.com/golang/go/issues](https://github.com/golang/go/issues) (エラーメッセージの改善に関する議論が見つかる可能性があります)
*   `cursym` や `diag` 関数に関するGoリンカのソースコード内のコメントや定義。
*   `Sym` 構造体に関するGoリンカのソースコード内の定義。