[インデックス 15920] ファイルの概要
このコミットは、Go言語のビルドシステム、特に5l
リンカ(ARMアーキテクチャ向け)と、リンキングモードに関するテストの挙動を修正するものです。具体的には、-linkmode
テストにおいて、失敗が正しく報告されるように改善されています。これにより、ビルドプロセスの堅牢性が向上し、リンキングモードのテストがより信頼性の高いものになります。
コミット
commit 976d99b9a883631af276a4cd8e0205095457b430
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Mar 25 03:18:05 2013 +0800
build, cmd/5l: actually report failures for -linkmode tests
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7938046
---\n src/cmd/5l/obj.c | 4 +++-\n src/run.bash | 1 +\n 2 files changed, 4 insertions(+), 1 deletion(-)\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/976d99b9a883631af276a4cd8e0205095457b430
元コミット内容
build, cmd/5l: actually report failures for -linkmode tests
変更の背景
このコミットの背景には、Go言語のビルドシステムにおけるリンキングモードのテストの信頼性に関する問題がありました。以前のシステムでは、-linkmode
オプションを使用したテストが失敗した場合でも、その失敗が適切に報告されない可能性がありました。これは、テストスイートが誤った成功を報告し、潜在的なビルドの問題やリンカのバグを見過ごす原因となり得ます。
特に、Goのリンカは、内部リンカ(Go自身で実装されたリンカ)と外部リンカ(Cコンパイラが提供するリンカ、例えばgcc
やclang
)の2つのモードをサポートしています。これらのリンキングモードは、生成されるバイナリの特性(例えば、静的リンクか動的リンクか、CGOの利用の有無など)に影響を与えます。そのため、これらのモードが正しく機能することを保証するためのテストは非常に重要です。
このコミットは、これらのテストが実際に失敗を検出し、報告するようにすることで、ビルドシステムの品質と安定性を向上させることを目的としています。
前提知識の解説
Go言語のビルドプロセス
Go言語のビルドプロセスは、ソースコードをコンパイルし、実行可能なバイナリを生成する一連のステップです。大まかには以下のようになります。
- コンパイル: Goのソースコード(
.go
ファイル)は、Goコンパイラ(gc
)によってアセンブリコードにコンパイルされます。 - アセンブル: アセンブリコードは、アセンブラによってオブジェクトファイル(
.o
ファイル)に変換されます。 - リンク: オブジェクトファイルは、リンカによって結合され、最終的な実行可能バイナリが生成されます。このステップで、必要なライブラリ(標準ライブラリやCGOでリンクされるCライブラリなど)も結合されます。
Goのリンカとリンキングモード
Goには主に2種類のリンカが存在します。
- 内部リンカ (internal linker): Go自身で実装されたリンカです。Goの標準ライブラリや純粋なGoコードのリンクに使用されます。クロスコンパイルが容易であるという利点があります。
- 外部リンカ (external linker): Cコンパイラ(例:
gcc
,clang
)が提供するリンカです。CGO(GoからCのコードを呼び出す機能)を使用する場合や、特定のシステムライブラリにリンクする必要がある場合に使用されます。外部リンカを使用すると、GoのバイナリがCのランタイムライブラリに依存するようになることがあります。
Goのビルドコマンド(go build
など)では、-ldflags
オプションを通じてリンカにフラグを渡すことができます。この中で、-linkmode
フラグはリンキングモードを指定するために使用されます。
-linkmode=internal
: 内部リンカを使用することを明示的に指定します。-linkmode=external
: 外部リンカを使用することを明示的に指定します。-linkmode=auto
: Goツールチェーンが自動的に最適なリンキングモードを選択します。通常、CGOが有効な場合は外部リンカが、そうでない場合は内部リンカが選択されます。
cmd/5l
cmd/5l
は、Goのツールチェーンの一部であり、ARMアーキテクチャ(GOARCH=arm
)向けのリンカです。Goのビルドシステムは、ターゲットアーキテクチャに応じて適切なリンカ(例: 5l
for ARM, 6l
for amd64, 8l
for 386など)を使用します。このコミットでは、5l
リンカのソースコードであるsrc/cmd/5l/obj.c
が変更されています。
src/run.bash
src/run.bash
は、Goプロジェクトのテストスイートを実行するためのシェルスクリプトです。Goのテストは、go test
コマンドを使用して実行されますが、このスクリプトはテスト環境のセットアップ、特定のテストの実行、および結果の検証を行うためのラッパーとして機能します。
set -e
set -e
は、Bashスクリプトにおける重要なコマンドです。このコマンドが有効になっている場合、スクリプト内の任意のコマンドが非ゼロの終了ステータス(エラーを示す)を返すと、スクリプトは即座に終了します。これにより、エラーが発生した際にスクリプトが予期せぬ動作を続けることを防ぎ、エラーの早期発見とデバッグに役立ちます。
技術的詳細
このコミットは、src/cmd/5l/obj.c
とsrc/run.bash
の2つのファイルを変更しています。
src/cmd/5l/obj.c
の変更
このファイルは、ARMアーキテクチャ向けのリンカである5l
の主要なC言語ソースコードです。変更点はmain
関数内にあります。
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -136,9 +136,11 @@ main(int argc, char *argv[])
if(argc != 1)
usage();
- if(linkmode != LinkInternal) {
+ if(linkmode == LinkExternal) {
diag("only -linkmode=internal is supported");
erroredit();
+ } else if(linkmode == LinkAuto) {
+ linkmode = LinkInternal;
}
libinit();
変更前:
if(linkmode != LinkInternal)
という条件がありました。これは、リンカがLinkInternal
モードでない場合に、「-linkmode=internal
のみがサポートされています」という診断メッセージを出力し、erroredit()
を呼び出してエラー終了していました。
このロジックの問題点は、LinkAuto
モードが指定された場合でも、それがLinkInternal
ではないため、エラーとして扱われてしまっていたことです。しかし、LinkAuto
は内部リンカを使用する可能性があり、特にCGOが有効でない場合は内部リンカが選択されるべきです。
変更後: 条件がより具体的に変更されました。
if(linkmode == LinkExternal)
: 明示的にLinkExternal
が指定された場合のみ、「-linkmode=internal
のみがサポートされています」というエラーを出力し、終了します。これは、5l
リンカが特定の状況下で外部リンカをサポートしないという制約を反映しています。else if(linkmode == LinkAuto)
:LinkAuto
が指定された場合、linkmode
変数をLinkInternal
に設定します。これにより、LinkAuto
モードが内部リンカとして適切に処理され、不必要なエラー終了が回避されます。
この変更により、5l
リンカは-linkmode=auto
が指定された際に、より賢明なデフォルト動作(内部リンカの使用)を行うようになり、テストやビルドプロセスがよりスムーズになります。
src/run.bash
の変更
このファイルは、Goのテストを実行するためのシェルスクリプトです。
--- a/src/run.bash
+++ b/src/run.bash
@@ -79,6 +79,7 @@ go run $GOROOT/test/run.go - .\n
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/test
+ set -e
go test -ldflags '-linkmode=auto'
go test -ldflags '-linkmode=internal'
case "$GOHOSTOS-$GOARCH" in
変更点:
go test -ldflags '-linkmode=auto'
とgo test -ldflags '-linkmode=internal'
のテストコマンドの前に、set -e
が追加されました。
変更の意図:
以前は、これらのgo test
コマンドが失敗した場合(例えば、リンカのエラーやテストの失敗)、スクリプトはそのまま実行を続ける可能性がありました。set -e
を追加することで、go test
コマンドが非ゼロの終了ステータスを返した場合(つまり、テストが失敗した場合)、スクリプトは即座に終了します。これにより、リンキングモードに関するテストの失敗が確実に捕捉され、テストスイートが誤った成功を報告することがなくなります。これは、CI/CDパイプラインや開発者のローカル環境でのテスト実行において、エラーの早期発見と修正を促進するために非常に重要です。
コアとなるコードの変更箇所
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 1bcf436c43..d38da204a3 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -136,9 +136,11 @@ main(int argc, char *argv[])
if(argc != 1)
usage();
-\tif(linkmode != LinkInternal) {
+\tif(linkmode == LinkExternal) {
diag("only -linkmode=internal is supported");
erroredit();
+\t} else if(linkmode == LinkAuto) {
+\t\tlinkmode = LinkInternal;
}\n
libinit();
diff --git a/src/run.bash b/src/run.bash
index 5f0af5f3f2..b7c89d96a7 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -79,6 +79,7 @@ go run $GOROOT/test/run.go - .\n
[ "$CGO_ENABLED" != 1 ] ||
(xcd ../misc/cgo/test
+ set -e
go test -ldflags '-linkmode=auto'
go test -ldflags '-linkmode=internal'
case "$GOHOSTOS-$GOARCH" in
コアとなるコードの解説
src/cmd/5l/obj.c
の変更解説
この変更は、5l
リンカが-linkmode
オプションをどのように解釈するかを改善します。
-
旧コード:
if(linkmode != LinkInternal)
- これは、
linkmode
がLinkInternal
以外であれば、すべてエラーとして扱っていました。これには、自動選択モードであるLinkAuto
も含まれていました。 - 結果として、
go test -ldflags '-linkmode=auto'
のようなコマンドが、5l
リンカのコンテキストで不必要にエラーとなる可能性がありました。
- これは、
-
新コード:
if(linkmode == LinkExternal) { diag("only -linkmode=internal is supported"); erroredit(); } else if(linkmode == LinkAuto) { linkmode = LinkInternal; }
if(linkmode == LinkExternal)
:5l
リンカが外部リンカをサポートしない場合にのみ、明示的にエラーを報告します。これは、5l
リンカの特定の制約を尊重しつつ、より正確なエラーハンドリングを提供します。else if(linkmode == LinkAuto)
:LinkAuto
が指定された場合、linkmode
をLinkInternal
に設定します。これは、5l
リンカが内部リンカとして機能することを前提とし、LinkAuto
が内部リンカを選択するシナリオでエラーを回避するためのものです。これにより、LinkAuto
モードがより柔軟に機能し、テストの実行がスムーズになります。
この変更により、5l
リンカは-linkmode=auto
の意図を正しく解釈し、不必要なエラーを発生させることなく、内部リンカとして動作するようになります。
src/run.bash
の変更解説
この変更は、テストスクリプトの堅牢性を高め、テストの失敗を確実に捕捉するためのものです。
- 追加行:
set -e
- このコマンドは、その後のコマンドが非ゼロの終了ステータス(エラー)を返した場合に、スクリプトの実行を即座に停止させるようにBashシェルに指示します。
- 以前は、
go test
コマンドが失敗しても、スクリプトは次の行に進んでしまう可能性がありました。これにより、テストスイート全体が成功したかのように見えてしまう誤った報告につながる恐れがありました。 set -e
を追加することで、go test -ldflags '-linkmode=auto'
やgo test -ldflags '-linkmode=internal'
のいずれかが失敗した場合、スクリプトは直ちに終了し、その失敗が明確に報告されるようになります。
この変更は、Goのビルドシステムにおけるテストの信頼性を大幅に向上させ、潜在的なリンカの問題やビルドの回帰を早期に発見するのに役立ちます。
関連リンク
- Go言語のビルドコマンド: https://pkg.go.dev/cmd/go#hdr-Build_commands
- Goのリンカに関する議論(Go issue trackerなど): 関連するGoのissueやデザインドキュメントを検索することで、リンカの設計思想や進化についてさらに深く理解できます。
参考にした情報源リンク
- Goの公式ドキュメント(
go build
、go test
、cgo
など) - Bashの
set -e
に関するドキュメントやチュートリアル - Goのソースコードリポジトリ(特に
src/cmd/
以下のリンカ関連のコード) - Goのコードレビューシステム(Gerrit)のCL(Change-list)ページ: https://golang.org/cl/7938046 (このコミットのCL)
- 一般的なGoのビルドプロセスに関する技術ブログや記事