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

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

このコミットは、Go言語のツールチェインにおけるlib9ライブラリのmain.cファイルに対する修正です。具体的には、プログラム名(argv0)の初期化コードがWindows固有の条件付きコンパイルブロック(#ifdef _WIN32)内に誤って配置されていた問題を修正し、非Windows環境(特にGOARCH=armのようなクロスコンパイル環境)でのツール実行時のエラーを解消します。

コミット

commit 9ba153e3e0969407c036deef6971d1f41cb11a18
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Mon Apr 21 00:08:39 2014 -0400

    lib9: restore argv0 initialization code.
    `GOARCH=arm go tool 6c` used to give "
    <prog>: cannot use 6c with GOARCH=arm"
    
    LGTM=r
    R=golang-codereviews, r
    CC=golang-codereviews
    https://golang.org/cl/89330043

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

https://github.com/golang/go/commit/9ba153e3e0969407c036deef6971d1f41cb11a18

元コミット内容

commit 9ba153e3e0969407c036deef6971d1f41cb11a18
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Mon Apr 21 00:08:39 2014 -0400

    lib9: restore argv0 initialization code.
    `GOARCH=arm go tool 6c` used to give "
    <prog>: cannot use 6c with GOARCH=arm"
    
    LGTM=r
    R=golang-codereviews, r
    CC=golang-codereviews
    https://golang.org/cl/89330043
---\n src/lib9/main.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/src/lib9/main.c b/src/lib9/main.c\nindex 6de53c10ab..088b09523c 100644
--- a/src/lib9/main.c
+++ b/src/lib9/main.c
@@ -52,8 +52,8 @@ main(int argc, char **argv)
  	// don\'t display the crash dialog
  	DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);\n 	SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n-\targv0 = argv[0];\n #endif\n+\targv0 = argv[0];\n \tp9main(argc, argv);\n \texits(\"main\");\n \treturn 99;\n```

## 変更の背景

このコミットの背景には、Go言語のクロスコンパイル環境における特定のツールの利用に関する問題がありました。具体的には、`GOARCH=arm`(ARMアーキテクチャ向け)を指定して`go tool 6c`(GoのCコンパイラ)を実行しようとすると、「`<prog>: cannot use 6c with GOARCH=arm`」というエラーが発生していました。

このエラーは、プログラムが自身の実行ファイル名(`argv[0]`)を正しく取得できていない、またはその情報が利用可能になる前に何らかの処理が行われようとしていることを示唆しています。`argv0`は、多くのCプログラムにおいて、エラーメッセージの表示や設定ファイルの検索など、様々な場面で利用される重要な情報です。

コミットメッセージにある「restore argv0 initialization code」という記述から、以前の変更で`argv0`の初期化コードが意図せずWindows固有のコンパイルブロック内に移動されてしまい、その結果、非Windows環境での初期化がスキップされるようになっていたと推測されます。この修正は、そのレグレッション(機能退行)を元に戻し、すべてのプラットフォームで`argv0`が適切に初期化されるようにすることを目的としています。

## 前提知識の解説

### `argv0`とは

C言語の`main`関数のシグネチャは通常、`int main(int argc, char *argv[])`または`int main(int argc, char **argv)`です。
*   `argc` (argument count) は、コマンドライン引数の数を表します。
*   `argv` (argument vector) は、コマンドライン引数を表す文字列の配列です。

この`argv`配列の最初の要素、すなわち`argv[0]`は、慣例として実行されたプログラム自身の名前(パスを含む場合もある)を指します。プログラムはこの情報を使って、例えばエラーメッセージに自身の名前を含めたり、関連するリソース(設定ファイルなど)を検索したりします。`argv0`が正しく初期化されないと、これらの機能が期待通りに動作しない可能性があります。

### `lib9`とは

`lib9`は、Go言語のツールチェイン内で使用されるライブラリの一つで、Plan 9オペレーティングシステムに由来するシステムコールやユーティリティ関数を提供します。Go言語はPlan 9の設計思想から多くの影響を受けており、特に初期のツールチェインやランタイムの一部には、Plan 9の概念やコードが取り入れられています。`lib9`は、Goのクロスプラットフォーム対応や低レベルな操作を可能にするための基盤の一部として機能します。

### `go tool 6c`とは

Go言語のビルドシステムは、Goプログラムだけでなく、Cやアセンブリ言語で書かれた部分(例えば、Goランタイムの一部やCgoでリンクされるライブラリ)もコンパイルします。`go tool`コマンドは、Goツールチェインに含まれる様々な内部ツールを実行するための汎用コマンドです。

*   `6c`: これは、Goの初期のツールチェインにおけるCコンパイラの名前です。Goのコンパイラは、ターゲットアーキテクチャに応じて命名されていました。
    *   `6`は通常、`amd64`(64ビットIntel/AMDアーキテクチャ)を指します。
    *   `8`は`386`(32ビットIntel/AMDアーキテクチャ)を指します。
    *   `5`は`arm`(ARMアーキテクチャ)を指します。
    *   `c`はCコンパイラを意味します。
    *   `g`はGoコンパイラを意味します。
    *   `a`はアセンブラを意味します。

したがって、`go tool 6c`は、`amd64`アーキテクチャ向けのCコンパイラを意味します。しかし、このコミットの文脈では「`GOARCH=arm go tool 6c`」とあり、これは`arm`アーキテクチャ向けにビルドする際に、誤って`amd64`向けのCコンパイラ(`6c`)が使われようとしていたか、あるいは`6c`が内部的に`argv0`を必要とする何らかの共通コードパスを持っていたことを示唆しています。通常、`GOARCH=arm`であれば`go tool 5c`が使われるべきですが、ツールチェインの内部的な連携や、特定のビルドスクリプトの挙動によって、このような状況が発生したと考えられます。

### `GOARCH`環境変数

`GOARCH`はGo言語のビルド環境変数の一つで、ターゲットとするCPUアーキテクチャを指定します。例えば、`GOARCH=amd64`は64ビットIntel/AMD、`GOARCH=arm`はARMプロセッサをターゲットとします。Goは強力なクロスコンパイル機能を持ち、この環境変数を設定することで、異なるアーキテクチャ向けのバイナリを簡単に生成できます。

### `SetErrorMode` (Windows API)

`SetErrorMode`はWindows API関数で、システムが特定のエラーを処理する方法を制御します。例えば、致命的なエラーが発生した際にエラーダイアログを表示するかどうかなどを設定できます。この関数はWindows固有のものであり、`#ifdef _WIN32`ブロック内に配置されているのはそのためです。このコミットの直接的な問題とは関係ありませんが、`argv0`の初期化コードがこのWindows固有のブロック内に誤って移動された原因となった周辺コードの一部です。

## 技術的詳細

このコミットの技術的な核心は、`argv0`変数の初期化が、特定のプラットフォーム(Windows)に限定されるべきではない場所で行われていた、という点にあります。

元のコードでは、`src/lib9/main.c`の`main`関数内で、`argv0 = argv[0];`という行が`#ifdef _WIN32 ... #endif`ブロックの**内側**にありました。これは、Windows環境でのみ`argv0`が初期化され、それ以外の環境(Linux, macOS, BSDなど)では`argv0`が未初期化のままになることを意味します。

Goのツールチェインは、様々なプラットフォームで動作し、またクロスコンパイルもサポートしています。`GOARCH=arm`のようなクロスコンパイルのシナリオでは、ビルドツール自体はホスト環境(例えばLinux/amd64)で動作しますが、ターゲットアーキテクチャ(ARM)向けのコードを生成します。この際、ツールチェイン内のCコンパイラ(`6c`)のようなツールが、`lib9`の`main.c`を使用している場合、そのツールが実行されるホスト環境(非Windows)で`argv0`が初期化されないという問題が発生します。

`argv0`が未初期化のまま使用されると、プログラムは自身の名前を正しく認識できず、エラーメッセージの生成や内部的なパス解決などで問題を引き起こす可能性があります。コミットメッセージにある「`<prog>: cannot use 6c with GOARCH=arm`」というエラーは、まさに`argv0`が正しく設定されていないために、ツールが自身の名前(`<prog>`の部分)を特定できず、適切なエラーメッセージを生成できなかったり、内部的なチェックで失敗したりした結果と考えられます。

この修正は、`argv0 = argv[0];`の行を`#ifdef _WIN32`ブロックの**外側**に移動することで、すべてのプラットフォームで`main`関数が実行される際に、`argv0`が確実に`argv[0]`で初期化されるようにします。これにより、非Windows環境でもツールが自身の名前を正しく認識し、期待通りに動作するようになります。

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

変更は`src/lib9/main.c`ファイルの一箇所のみです。

```diff
--- a/src/lib9/main.c
+++ b/src/lib9/main.c
@@ -52,8 +52,8 @@ main(int argc, char **argv)
  	// don\'t display the crash dialog
  	DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);\n 	SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);\n-\targv0 = argv[0];\n #endif\n+\targv0 = argv[0];\n \tp9main(argc, argv);\n \texits(\"main\");\n \treturn 99;\n```

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

この変更は非常にシンプルですが、その影響は広範囲に及びます。

*   **`- argv0 = argv[0];`**: この行は、`#ifdef _WIN32`ブロックの内部にありました。これは、Windows環境でのみ`argv0`変数が`argv[0]`(実行ファイル名)で初期化されることを意味していました。
*   **`#endif`**: Windows固有のコードブロックの終了を示します。
*   **`+ argv0 = argv[0];`**: この行は、`#endif`の直後、つまり`#ifdef _WIN32`ブロックの**外側**に移動されました。

この移動により、`argv0 = argv[0];`の初期化は、Windows固有のコンパイル条件に依存しなくなりました。結果として、Windows以外のオペレーティングシステム(Linux、macOSなど)でコンパイルおよび実行されるGoツールチェインのコンポーネント(この場合は`go tool 6c`)も、`main`関数が呼び出された際に`argv0`が適切に初期化されるようになります。

これにより、`argv0`が未初期化のまま使用されることによる問題(例: プログラム名が正しく表示されない、内部的なパス解決の失敗)が解消され、特にクロスコンパイル環境でのツールの安定性と信頼性が向上しました。

## 関連リンク

*   Go Change-ID: [https://golang.org/cl/89330043](https://golang.org/cl/89330043)

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

*   [Go言語のクロスコンパイルについて](https://go.dev/doc/install/source#environment) (Go公式ドキュメント)
*   [C言語のmain関数とargvについて](https://ja.wikipedia.org/wiki/Main%E9%96%A2%E6%95%B0) (Wikipedia)
*   [Plan 9 from Bell Labs](https://9p.io/plan9/) (Plan 9公式サイト)
*   [SetErrorMode function (errhandlingapi.h) - Win32 apps](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-seterrormode) (Microsoft Learn)
*   [Go tool commands](https://go.dev/cmd/go/#hdr-Go_tool_commands) (Go公式ドキュメント)
*   [Go source code - src/lib9/main.c](https://github.com/golang/go/blob/master/src/lib9/main.c) (GitHub)
*   [Go toolchain documentation (older versions might be relevant for 6c/8c/5c naming)](https://go.dev/doc/go1.4#toolchain) (Go公式ドキュメント - 1.4以前のツールチェインの命名規則について言及がある可能性)
*   [Go issue tracker (searching for related issues to "cannot use 6c with GOARCH=arm")](https://github.com/golang/go/issues) (GitHub - 関連するissueを検索する可能性)
*   [Go mailing lists/forums (searching for discussions on this error)](https://groups.google.com/g/golang-nuts) (Google Groups - 関連する議論を検索する可能性)