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

[インデックス 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コンパイラが提供するリンカ、例えばgccclang)の2つのモードをサポートしています。これらのリンキングモードは、生成されるバイナリの特性(例えば、静的リンクか動的リンクか、CGOの利用の有無など)に影響を与えます。そのため、これらのモードが正しく機能することを保証するためのテストは非常に重要です。

このコミットは、これらのテストが実際に失敗を検出し、報告するようにすることで、ビルドシステムの品質と安定性を向上させることを目的としています。

前提知識の解説

Go言語のビルドプロセス

Go言語のビルドプロセスは、ソースコードをコンパイルし、実行可能なバイナリを生成する一連のステップです。大まかには以下のようになります。

  1. コンパイル: Goのソースコード(.goファイル)は、Goコンパイラ(gc)によってアセンブリコードにコンパイルされます。
  2. アセンブル: アセンブリコードは、アセンブラによってオブジェクトファイル(.oファイル)に変換されます。
  3. リンク: オブジェクトファイルは、リンカによって結合され、最終的な実行可能バイナリが生成されます。このステップで、必要なライブラリ(標準ライブラリや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.csrc/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が有効でない場合は内部リンカが選択されるべきです。

変更後: 条件がより具体的に変更されました。

  1. if(linkmode == LinkExternal): 明示的にLinkExternalが指定された場合のみ、「-linkmode=internalのみがサポートされています」というエラーを出力し、終了します。これは、5lリンカが特定の状況下で外部リンカをサポートしないという制約を反映しています。
  2. 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)

    • これは、linkmodeLinkInternal以外であれば、すべてエラーとして扱っていました。これには、自動選択モードである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が指定された場合、linkmodeLinkInternalに設定します。これは、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 buildgo testcgoなど)
  • Bashのset -eに関するドキュメントやチュートリアル
  • Goのソースコードリポジトリ(特にsrc/cmd/以下のリンカ関連のコード)
  • Goのコードレビューシステム(Gerrit)のCL(Change-list)ページ: https://golang.org/cl/7938046 (このコミットのCL)
  • 一般的なGoのビルドプロセスに関する技術ブログや記事