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

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

このコミットは、Go言語のdebug/gosymパッケージにおけるテストのビルドプロセスを改善し、従来のMakefileベースのシステムからGo標準のツールチェーンへと移行するものです。具体的には、テスト用のバイナリを生成するために使用されていたMakefileを削除し、Goツール(go tool 6ago tool 6l)を用いてテストコードを直接ビルドするように変更しています。これにより、Goプロジェクト全体のビルドシステムの一貫性が向上し、依存関係の管理が簡素化されます。

コミット

commit 343059930624b1e5b54fae8a092819db95b40cca
Author: David Symonds <dsymonds@golang.org>
Date:   Thu Feb 16 14:47:14 2012 +1100

    debug/gosym: Remove Makefile, rewrite test using go tool.
    
    Update #2573.
    
    R=r
    CC=golang-dev
    https://golang.org/cl/5656071

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

https://github.com/golang/go/commit/343059930624b1e5b54fae8a092819db95b40cca

元コミット内容

debug/gosym: Remove Makefile, rewrite test using go tool.

このコミットは、debug/gosymパッケージのテストにおいて、Makefileの使用を廃止し、Goツールを用いたテストの再構築を行うものです。これはIssue #2573の更新に対応しています。

変更の背景

この変更の背景には、Goプロジェクト全体のビルドシステムの一貫性を高めるという目的があります。Go言語は、その設計思想としてシンプルなビルドプロセスを重視しており、go buildgo testといったコマンドを通じて、ほとんどのビルド作業を自動化しています。しかし、初期のGoプロジェクトの一部では、C言語のプロジェクトで一般的に使用されるMakefileが残存している箇所がありました。

特に、debug/gosymパッケージのような低レベルのデバッグ情報を取り扱う部分では、アセンブリコードのコンパイルやリンクといった特殊なビルドステップが必要となる場合があり、そのためにMakefileが利用されていました。しかし、Goツールチェーンが成熟するにつれて、これらの特殊なビルドステップもGoツール自身で処理できるようになりました。

Issue #2573は、まさにこの問題、すなわちGoのテストがGoツールではなくMakefileに依存している点を指摘し、Goツールへの移行を提案していました。このコミットは、その提案に応える形で、debug/gosymパッケージのテストビルドをGoツールに完全に移行することで、ビルドプロセスの簡素化、可搬性の向上、そしてGoエコシステム全体の一貫性強化を図っています。これにより、開発者はGoの標準的なコマンドだけでテストを実行できるようになり、異なる環境でのビルドの複雑さが軽減されます。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念について理解しておく必要があります。

  • Go言語のビルドシステム: Go言語は、go buildgo rungo testといったコマンドを通じて、ソースコードのコンパイル、実行、テストを統合的に管理します。これらのコマンドは、Goのツールチェーン(コンパイラ、リンカ、アセンブラなど)を内部的に呼び出し、依存関係の解決やバイナリの生成を自動的に行います。
  • Makefile: Makefileは、主にUnix系システムでソフトウェアのビルドプロセスを自動化するために使用されるツールです。makeコマンドによって実行され、ファイル間の依存関係を定義し、それらを解決するためのコマンドシーケンス(レシピ)を記述します。C/C++プロジェクトなどで広く利用されています。
  • debug/gosymパッケージ: Go言語の標準ライブラリの一部であり、Goバイナリに含まれるシンボルテーブル(symtab)とプログラムカウンタ-ライン番号テーブル(pclntab)を解析するための機能を提供します。これらのテーブルは、デバッガが実行中のプログラムのどの部分がソースコードのどの行に対応するかを特定するために使用されます。
  • pclntab (Program Counter Line Table): Goバイナリに埋め込まれている重要なデータ構造の一つで、プログラムカウンタ(PC)の値と、対応するソースファイルのパス、行番号、関数名などの情報をマッピングします。デバッグ情報やプロファイリングにおいて不可欠な要素です。
  • go tool 6ago tool 6l: これらはGoの初期のツールチェーンにおけるアセンブラ(6a)とリンカ(6l)のコマンドです。6は64ビットアーキテクチャ(amd64)を指し、aはアセンブラ、lはリンカを意味します。これらのツールは、Goのソースコードやアセンブリコードをコンパイルし、実行可能なバイナリにリンクするために使用されます。現代のGoでは、これらの低レベルツールは通常go buildなどの高レベルコマンドによって抽象化されており、直接呼び出すことは稀です。
  • ELF (Executable and Linkable Format): Unix系システムで広く使用されている実行可能ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。GoのバイナリもLinux上ではELF形式で生成されます。debug/elfパッケージは、GoからELFファイルを解析するための機能を提供します。
  • os/execパッケージ: Goプログラムから外部コマンドを実行するための機能を提供します。このコミットでは、go toolコマンドを呼び出すために使用されています。

技術的詳細

このコミットの技術的な核心は、debug/gosymパッケージのテストスイートが、外部のMakefileに依存することなく、Goの標準ツールチェーン(go toolコマンド)を使用してテスト用のバイナリを生成するように変更された点にあります。

具体的な変更点は以下の通りです。

  1. Makefileの削除:

    • src/pkg/debug/gosym/Makefileが完全に削除されました。このMakefileは、pclinetest.sというアセンブリファイルをコンパイルし、_test/pclinetestというテストバイナリを生成するために使用されていました。
    • Makefileには、make-pclinetestというターゲットがあり、$(AS)(アセンブラ)と$(LD)(リンカ)を直接呼び出してバイナリを生成するロジックが含まれていました。この依存関係が解消されたことで、ビルドプロセスがGoツールに一元化されました。
  2. アセンブリファイルの名称変更:

    • src/pkg/debug/gosym/pclinetest.ssrc/pkg/debug/gosym/pclinetest.asmに名称変更されました。
    • この名称変更は、Goツールが.s拡張子を持つファイルをGoのアセンブリファイルとして自動的に認識し、コンパイルしようとする挙動を回避するためのものです。pclinetest.asmは、Goツールが直接処理するのではなく、os/execを通じて明示的にgo tool 6aでコンパイルされることを意図しています。これにより、Goのビルドシステムがこのファイルを通常のGoアセンブリとして扱わないようにし、テストの特殊なビルドフローを維持しています。
  3. pclntab_test.goの変更:

    • pclntab_test.go内のdotest()関数が大幅に修正されました。
    • テストバイナリの生成ロジックの組み込み: 以前はMakefileに依存していたテストバイナリ(pclinetest)の生成が、dotest()関数内で直接行われるようになりました。
    • os/execの使用: os/exec.Commandを使用して、以下のシェルコマンドが実行されます。
      go tool 6a pclinetest.asm && go tool 6l -E main -o /tmp/pclinetest pclinetest.6
      
      • go tool 6a pclinetest.asm: pclinetest.asmをアセンブルし、オブジェクトファイルpclinetest.6を生成します。
      • go tool 6l -E main -o /tmp/pclinetest pclinetest.6: pclinetest.6をリンクし、/tmp/pclinetestという実行可能バイナリを生成します。-E mainはエントリポイントを指定し、-oは出力ファイル名を指定します。
    • 一時ディレクトリへの出力: 生成されたテストバイナリは、os.TempDir()で取得される一時ディレクトリに保存されるようになりました。これにより、テスト実行後の一時ファイルのクリーンアップが容易になります。
    • プラットフォームチェックの強化: runtime.GOOSruntime.GOARCHを使用して、テストがLinux AMD64環境でのみ実行されるように明示的にチェックしています。これは、go tool 6ago tool 6lが特定のアーキテクチャに特化しているためです。
    • ファイルパスのサフィックスチェックの変更: TestPCLine関数内で、fileパスのチェックがより柔軟になりました。以前はfile[len(file)-12:] != "pclinetest.s"という厳密なサフィックスチェックを行っていましたが、!strings.HasSuffix(file, "pclinetest.s")に変更され、より堅牢なチェックになっています。これは、pclinetest.asmからビルドされたバイナリが、デバッグ情報上は依然として元の.sファイルを参照している可能性があるためです。

これらの変更により、debug/gosymパッケージのテストは、Goの標準的なテスト実行コマンド(go test)を通じて、完全にGoツールチェーン内で完結するようになりました。これにより、外部のビルドツールへの依存が解消され、Goプロジェクト全体のビルドとテストの自動化がさらに推進されました。

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

src/pkg/debug/gosym/Makefile (削除)

--- a/src/pkg/debug/gosym/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=debug/gosym
-GOFILES=\
-	pclntab.go\
-	symtab.go\
-
-include ../../../Make.pkg
-
-test: make-pclinetest
-
-testshort: make-pclinetest
-
-make-pclinetest:
-	@if [ "`uname`-`uname -m`\" = Linux-x86_64 -a $(GOARCH) = amd64 ]; then mkdir -p _test && $(AS) pclinetest.s && $(LD) -E main -o _test/pclinetest pclinetest.$O; fi

src/pkg/debug/gosym/pclinetest.s から src/pkg/debug/gosym/pclinetest.asm への名称変更

--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.asm
@@ -1,5 +1,3 @@
-// +build ignore
-
 TEXT linefrompc(SB),7,$0	// Each byte stores its line delta
 BYTE $2;
 BYTE $1;

src/pkg/debug/gosym/pclntab_test.go (変更)

--- a/src/pkg/debug/gosym/pclntab_test.go
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -7,14 +7,31 @@ package gosym
 import (
 	"debug/elf"
 	"os"
+	"os/exec"
 	"runtime"
+	"strings"
 	"testing"
 )
 
+var pclinetestBinary string
+
 func dotest() bool {
 	// For now, only works on ELF platforms.
-	// TODO: convert to work with new go tool
-	return false && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
+	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+		return false
+	}
+	if pclinetestBinary != "" {
+		return true
+	}
+	// This command builds pclinetest from pclinetest.asm;
+	// the resulting binary looks like it was built from pclinetest.s,
+	// but we have renamed it to keep it away from the go tool.
+	pclinetestBinary = os.TempDir() + "/pclinetest"
+	cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
+	if err := cmd.Run(); err != nil {
+		panic(err)
+	}
+	return true
 }
 
 func getTable(t *testing.T) *Table {
@@ -149,7 +166,7 @@ func TestPCLine(t *testing.T) {
 		return
 	}
 
-	f, tab := crack("_test/pclinetest", t)
+	f, tab := crack(pclinetestBinary, t)
 	text := f.Section(".text")
 	textdat, err := text.Data()
 	if err != nil {
@@ -163,10 +180,13 @@ func TestPCLine(t *testing.T) {
 		file, line, fn := tab.PCToLine(pc)
 		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
 		wantLine += int(textdat[off])
+		t.Logf("off is %d", off)
 		if fn == nil {
 			t.Errorf("failed to get line of PC %#x", pc)
-		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
-			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+		} else if !strings.HasSuffix(file, "pclinetest.s") {
+			t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.s", sym.Name, pc, file, fn.Name)
+		} else if line != wantLine || fn != sym {
+			t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
 		}
 	}
 

コアとなるコードの解説

このコミットのコアとなる変更は、src/pkg/debug/gosym/pclntab_test.go内のdotest()関数の実装に集約されています。

  1. pclinetestBinary変数の導入:

    • var pclinetestBinary stringがグローバル変数として追加されました。これは、生成されたテストバイナリのパスをキャッシュするために使用されます。これにより、テストが複数回実行される場合に、毎回バイナリを再ビルドするのを防ぎ、効率を向上させます。
  2. プラットフォームチェックの強化:

    • if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { return false }
      • この行は、テストがLinuxオペレーティングシステムとAMD64アーキテクチャでのみ実行されることを保証します。これは、go tool 6ago tool 6lが特定のプラットフォームに特化しているため、他の環境での実行を早期に終了させるためのガード句です。
  3. テストバイナリのビルドロジック:

    • if pclinetestBinary != "" { return true }
      • pclinetestBinaryが既に設定されている場合(つまり、バイナリが既にビルドされている場合)、すぐにtrueを返して再ビルドをスキップします。
    • pclinetestBinary = os.TempDir() + "/pclinetest"
      • テストバイナリの出力パスを、システムの一時ディレクトリ内に設定します。これにより、テスト実行後の一時ファイルの管理が容易になります。
    • cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
      • この行が、Makefileを置き換える主要な部分です。os/exec.Commandを使用してシェルコマンドを実行します。
      • "sh", "-c", "...": シェルを介してコマンドを実行するための標準的な方法です。
      • go tool 6a pclinetest.asm: pclinetest.asmというアセンブリファイルをGoのアセンブラ(6a)でコンパイルし、pclinetest.6というオブジェクトファイルを生成します。
      • &&: 前のコマンドが成功した場合にのみ、次のコマンドを実行します。
      • go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6: pclinetest.6オブジェクトファイルをGoのリンカ(6l)でリンクし、pclinetestBinaryで指定されたパスに実行可能バイナリを生成します。-E mainはエントリポイントをmain関数に設定し、-oは出力ファイル名を指定します。
    • if err := cmd.Run(); err != nil { panic(err) }
      • 構築したコマンドを実行し、エラーが発生した場合はパニックを引き起こします。これにより、テストバイナリの生成に失敗した場合にテストが続行されるのを防ぎます。
  4. TestPCLine関数内の変更:

    • f, tab := crack(pclinetestBinary, t)
      • 以前はハードコードされたパス"_test/pclinetest"を使用していた箇所が、pclinetestBinary変数を使用するように変更されました。これにより、動的に生成されたバイナリのパスが正しく参照されるようになります。
    • !strings.HasSuffix(file, "pclinetest.s")
      • デバッグ情報から取得したファイルパスのサフィックスチェックが、より柔軟なstrings.HasSuffixを使用するように変更されました。これは、pclinetest.asmからビルドされたバイナリのデバッグ情報が、元の.s拡張子を参照している可能性があるため、より堅牢なチェックが必要とされたためです。

これらの変更により、debug/gosymパッケージのテストは、Goの標準的なツールチェーンに完全に統合され、外部のビルドシステムへの依存が解消されました。

関連リンク

  • Go言語の公式ドキュメント: https://golang.org/doc/
  • Goのdebug/gosymパッケージ: https://pkg.go.dev/debug/gosym
  • Goのos/execパッケージ: https://pkg.go.dev/os/exec
  • GoのIssue #2573: cmd/go: make go test work for all packages (このコミットが解決したIssue) - 検索しても直接的なリンクは見つかりませんでしたが、GoのIssueトラッカーで検索すると関連情報が見つかる可能性があります。

参考にした情報源リンク

  • Go言語のソースコード (GitHub): https://github.com/golang/go
  • Goのコードレビューシステム (Gerrit): https://golang.org/cl/5656071 (コミットメッセージに記載されているChange-ID)
  • ELFファイルフォーマットに関する一般的な情報 (Wikipediaなど): https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
  • Makefileに関する一般的な情報 (GNU Makeマニュアルなど): https://www.gnu.org/software/make/manual/
  • Goのgo toolコマンドに関する情報 (Goのドキュメントやブログ記事): go toolは内部ツールであり、公式ドキュメントには詳細な説明がない場合がありますが、Goのソースコードや関連するブログ記事でその使用法が解説されていることがあります。# [インデックス 11955] ファイルの概要

このコミットは、Go言語のdebug/gosymパッケージにおけるテストのビルドプロセスを改善し、従来のMakefileベースのシステムからGo標準のツールチェーンへと移行するものです。具体的には、テスト用のバイナリを生成するために使用されていたMakefileを削除し、Goツール(go tool 6ago tool 6l)を用いてテストコードを直接ビルドするように変更しています。これにより、Goプロジェクト全体のビルドシステムの一貫性が向上し、依存関係の管理が簡素化されます。

コミット

commit 343059930624b1e5b54fae8a092819db95b40cca
Author: David Symonds <dsymonds@golang.org>
Date:   Thu Feb 16 14:47:14 2012 +1100

    debug/gosym: Remove Makefile, rewrite test using go tool.
    
    Update #2573.
    
    R=r
    CC=golang-dev
    https://golang.org/cl/5656071

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

https://github.com/golang/go/commit/343059930624b1e5b54fae8a092819db95b40cca

元コミット内容

debug/gosym: Remove Makefile, rewrite test using go tool.

このコミットは、debug/gosymパッケージのテストにおいて、Makefileの使用を廃止し、Goツールを用いたテストの再構築を行うものです。これはIssue #2573の更新に対応しています。

変更の背景

この変更の背景には、Goプロジェクト全体のビルドシステムの一貫性を高めるという目的があります。Go言語は、その設計思想としてシンプルなビルドプロセスを重視しており、go buildgo testといったコマンドを通じて、ほとんどのビルド作業を自動化しています。しかし、初期のGoプロジェクトの一部では、C言語のプロジェクトで一般的に使用されるMakefileが残存している箇所がありました。

特に、debug/gosymパッケージのような低レベルのデバッグ情報を取り扱う部分では、アセンブリコードのコンパイルやリンクといった特殊なビルドステップが必要となる場合があり、そのためにMakefileが利用されていました。しかし、Goツールチェーンが成熟するにつれて、これらの特殊なビルドステップもGoツール自身で処理できるようになりました。

Issue #2573は、まさにこの問題、すなわちGoのテストがGoツールではなくMakefileに依存している点を指摘し、Goツールへの移行を提案していました。このコミットは、その提案に応える形で、debug/gosymパッケージのテストビルドをGoツールに完全に移行することで、ビルドプロセスの簡素化、可搬性の向上、そしてGoエコシステム全体の一貫性強化を図っています。これにより、開発者はGoの標準的なコマンドだけでテストを実行できるようになり、異なる環境でのビルドの複雑さが軽減されます。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念について理解しておく必要があります。

  • Go言語のビルドシステム: Go言語は、go buildgo rungo testといったコマンドを通じて、ソースコードのコンパイル、実行、テストを統合的に管理します。これらのコマンドは、Goのツールチェーン(コンパイラ、リンカ、アセンブラなど)を内部的に呼び出し、依存関係の解決やバイナリの生成を自動的に行います。
  • Makefile: Makefileは、主にUnix系システムでソフトウェアのビルドプロセスを自動化するために使用されるツールです。makeコマンドによって実行され、ファイル間の依存関係を定義し、それらを解決するためのコマンドシーケンス(レシピ)を記述します。C/C++プロジェクトなどで広く利用されています。
  • debug/gosymパッケージ: Go言語の標準ライブラリの一部であり、Goバイナリに含まれるシンボルテーブル(symtab)とプログラムカウンタ-ライン番号テーブル(pclntab)を解析するための機能を提供します。これらのテーブルは、デバッガが実行中のプログラムのどの部分がソースコードのどの行に対応するかを特定するために使用されます。
  • pclntab (Program Counter Line Table): Goバイナリに埋め込まれている重要なデータ構造の一つで、プログラムカウンタ(PC)の値と、対応するソースファイルのパス、行番号、関数名などの情報をマッピングします。デバッグ情報やプロファイリングにおいて不可欠な要素です。
  • go tool 6ago tool 6l: これらはGoの初期のツールチェーンにおけるアセンブラ(6a)とリンカ(6l)のコマンドです。6は64ビットアーキテクチャ(amd64)を指し、aはアセンブラ、lはリンカを意味します。これらのツールは、Goのソースコードやアセンブリコードをコンパイルし、実行可能なバイナリにリンクするために使用されます。現代のGoでは、これらの低レベルツールは通常go buildなどの高レベルコマンドによって抽象化されており、直接呼び出すことは稀です。
  • ELF (Executable and Linkable Format): Unix系システムで広く使用されている実行可能ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。GoのバイナリもLinux上ではELF形式で生成されます。debug/elfパッケージは、GoからELFファイルを解析するための機能を提供します。
  • os/execパッケージ: Goプログラムから外部コマンドを実行するための機能を提供します。このコミットでは、go toolコマンドを呼び出すために使用されています。

技術的詳細

このコミットの技術的な核心は、debug/gosymパッケージのテストスイートが、外部のMakefileに依存することなく、Goの標準ツールチェーン(go toolコマンド)を使用してテスト用のバイナリを生成するように変更された点にあります。

具体的な変更点は以下の通りです。

  1. Makefileの削除:

    • src/pkg/debug/gosym/Makefileが完全に削除されました。このMakefileは、pclinetest.sというアセンブリファイルをコンパイルし、_test/pclinetestというテストバイナリを生成するために使用されていました。
    • Makefileには、make-pclinetestというターゲットがあり、$(AS)(アセンブラ)と$(LD)(リンカ)を直接呼び出してバイナリを生成するロジックが含まれていました。この依存関係が解消されたことで、ビルドプロセスがGoツールに一元化されました。
  2. アセンブリファイルの名称変更:

    • src/pkg/debug/gosym/pclinetest.ssrc/pkg/debug/gosym/pclinetest.asmに名称変更されました。
    • この名称変更は、Goツールが.s拡張子を持つファイルをGoのアセンブリファイルとして自動的に認識し、コンパイルしようとする挙動を回避するためのものです。pclinetest.asmは、Goツールが直接処理するのではなく、os/execを通じて明示的にgo tool 6aでコンパイルされることを意図しています。これにより、Goのビルドシステムがこのファイルを通常のGoアセンブリとして扱わないようにし、テストの特殊なビルドフローを維持しています。
  3. pclntab_test.goの変更:

    • pclntab_test.go内のdotest()関数が大幅に修正されました。
    • テストバイナリの生成ロジックの組み込み: 以前はMakefileに依存していたテストバイナリ(pclinetest)の生成が、dotest()関数内で直接行われるようになりました。
    • os/execの使用: os/exec.Commandを使用して、以下のシェルコマンドが実行されます。
      go tool 6a pclinetest.asm && go tool 6l -E main -o /tmp/pclinetest pclinetest.6
      
      • go tool 6a pclinetest.asm: pclinetest.asmをアセンブルし、オブジェクトファイルpclinetest.6を生成します。
      • &&: 前のコマンドが成功した場合にのみ、次のコマンドを実行します。
      • go tool 6l -E main -o /tmp/pclinetest pclinetest.6: pclinetest.6をリンクし、/tmp/pclinetestという実行可能バイナリを生成します。-E mainはエントリポイントを指定し、-oは出力ファイル名を指定します。
    • 一時ディレクトリへの出力: 生成されたテストバイナリは、os.TempDir()で取得される一時ディレクトリに保存されるようになりました。これにより、テスト実行後の一時ファイルのクリーンアップが容易になります。
    • プラットフォームチェックの強化: runtime.GOOSruntime.GOARCHを使用して、テストがLinux AMD64環境でのみ実行されるように明示的にチェックしています。これは、go tool 6ago tool 6lが特定のアーキテクチャに特化しているためです。
    • ファイルパスのサフィックスチェックの変更: TestPCLine関数内で、fileパスのチェックがより柔軟になりました。以前はfile[len(file)-12:] != "pclinetest.s"という厳密なサフィックスチェックを行っていましたが、!strings.HasSuffix(file, "pclinetest.s")に変更され、より堅牢なチェックになっています。これは、pclinetest.asmからビルドされたバイナリが、デバッグ情報上は依然として元の.sファイルを参照している可能性があるためです。

これらの変更により、debug/gosymパッケージのテストは、Goの標準的なテスト実行コマンド(go test)を通じて、完全にGoツールチェーン内で完結するようになりました。これにより、外部のビルドツールへの依存が解消され、Goプロジェクト全体のビルドとテストの自動化がさらに推進されました。

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

src/pkg/debug/gosym/Makefile (削除)

--- a/src/pkg/debug/gosym/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2009 The Go Authors.  All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-include ../../../Make.inc
-
-TARG=debug/gosym
-GOFILES=\
-	pclntab.go\
-	symtab.go\
-
-include ../../../Make.pkg
-
-test: make-pclinetest
-
-testshort: make-pclinetest
-
-make-pclinetest:
-	@if [ "`uname`-`uname -m`\" = Linux-x86_64 -a $(GOARCH) = amd64 ]; then mkdir -p _test && $(AS) pclinetest.s && $(LD) -E main -o _test/pclinetest pclinetest.$O; fi

src/pkg/debug/gosym/pclinetest.s から src/pkg/debug/gosym/pclinetest.asm への名称変更

--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.asm
@@ -1,5 +1,3 @@
-// +build ignore
-
 TEXT linefrompc(SB),7,$0	// Each byte stores its line delta
 BYTE $2;
 BYTE $1;

src/pkg/debug/gosym/pclntab_test.go (変更)

--- a/src/pkg/debug/gosym/pclntab_test.go
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -7,14 +7,31 @@ package gosym
 import (
 	"debug/elf"
 	"os"
+	"os/exec"
 	"runtime"
+	"strings"
 	"testing"
 )
 
+var pclinetestBinary string
+
 func dotest() bool {
 	// For now, only works on ELF platforms.
-	// TODO: convert to work with new go tool
-	return false && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
+	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+		return false
+	}
+	if pclinetestBinary != "" {
+		return true
+	}
+	// This command builds pclinetest from pclinetest.asm;
+	// the resulting binary looks like it was built from pclinetest.s,
+	// but we have renamed it to keep it away from the go tool.
+	pclinetestBinary = os.TempDir() + "/pclinetest"
+	cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
+	if err := cmd.Run(); err != nil {
+		panic(err)
+	}
+	return true
 }
 
 func getTable(t *testing.T) *Table {
@@ -149,7 +166,7 @@ func TestPCLine(t *testing.T) {
 		return
 	}
 
-	f, tab := crack("_test/pclinetest", t)
+	f, tab := crack(pclinetestBinary, t)
 	text := f.Section(".text")
 	textdat, err := text.Data()
 	if err != nil {
@@ -163,10 +180,13 @@ func TestPCLine(t *testing.T) {
 		file, line, fn := tab.PCToLine(pc)
 		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
 		wantLine += int(textdat[off])
+		t.Logf("off is %d", off)
 		if fn == nil {
 			t.Errorf("failed to get line of PC %#x", pc)
-		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
-			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
+		} else if !strings.HasSuffix(file, "pclinetest.s") {
+			t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.s", sym.Name, pc, file, fn.Name)
+		} else if line != wantLine || fn != sym {
+			t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
 		}
 	}
 

コアとなるコードの解説

このコミットのコアとなる変更は、src/pkg/debug/gosym/pclntab_test.go内のdotest()関数の実装に集約されています。

  1. pclinetestBinary変数の導入:

    • var pclinetestBinary stringがグローバル変数として追加されました。これは、生成されたテストバイナリのパスをキャッシュするために使用されます。これにより、テストが複数回実行される場合に、毎回バイナリを再ビルドするのを防ぎ、効率を向上させます。
  2. プラットフォームチェックの強化:

    • if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { return false }
      • この行は、テストがLinuxオペレーティングシステムとAMD64アーキテクチャでのみ実行されることを保証します。これは、go tool 6ago tool 6lが特定のプラットフォームに特化しているため、他の環境での実行を早期に終了させるためのガード句です。
  3. テストバイナリのビルドロジック:

    • if pclinetestBinary != "" { return true }
      • pclinetestBinaryが既に設定されている場合(つまり、バイナリが既にビルドされている場合)、すぐにtrueを返して再ビルドをスキップします。
    • pclinetestBinary = os.TempDir() + "/pclinetest"
      • テストバイナリの出力パスを、システムの一時ディレクトリ内に設定します。これにより、テスト実行後の一時ファイルの管理が容易になります。
    • cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
      • この行が、Makefileを置き換える主要な部分です。os/exec.Commandを使用してシェルコマンドを実行します。
      • "sh", "-c", "...": シェルを介してコマンドを実行するための標準的な方法です。
      • go tool 6a pclinetest.asm: pclinetest.asmというアセンブリファイルをGoのアセンブラ(6a)でコンパイルし、pclinetest.6というオブジェクトファイルを生成します。
      • &&: 前のコマンドが成功した場合にのみ、次のコマンドを実行します。
      • go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6: pclinetest.6オブジェクトファイルをGoのリンカ(6l)でリンクし、pclinetestBinaryで指定されたパスに実行可能バイナリを生成します。-E mainはエントリポイントをmain関数に設定し、-oは出力ファイル名を指定します。
    • if err := cmd.Run(); err != nil { panic(err) }
      • 構築したコマンドを実行し、エラーが発生した場合はパニックを引き起こします。これにより、テストバイナリの生成に失敗した場合にテストが続行されるのを防ぎます。
  4. TestPCLine関数内の変更:

    • f, tab := crack(pclinetestBinary, t)
      • 以前はハードコードされたパス"_test/pclinetest"を使用していた箇所が、pclinetestBinary変数を使用するように変更されました。これにより、動的に生成されたバイナリのパスが正しく参照されるようになります。
    • !strings.HasSuffix(file, "pclinetest.s")
      • デバッグ情報から取得したファイルパスのサフィックスチェックが、より柔軟なstrings.HasSuffixを使用するように変更されました。これは、pclinetest.asmからビルドされたバイナリのデバッグ情報が、元の.s拡張子を参照している可能性があるため、より堅牢なチェックが必要とされたためです。

これらの変更により、debug/gosymパッケージのテストは、Goの標準的なツールチェーンに完全に統合され、外部のビルドシステムへの依存が解消されました。

関連リンク

  • Go言語の公式ドキュメント: https://golang.org/doc/
  • Goのdebug/gosymパッケージ: https://pkg.go.dev/debug/gosym
  • Goのos/execパッケージ: https://pkg.go.dev/os/exec
  • GoのIssue #2573: cmd/go: make go test work for all packages (このコミットが解決したIssue) - 検索しても直接的なリンクは見つかりませんでしたが、GoのIssueトラッカーで検索すると関連情報が見つかる可能性があります。

参考にした情報源リンク

  • Go言語のソースコード (GitHub): https://github.com/golang/go
  • Goのコードレビューシステム (Gerrit): https://golang.org/cl/5656071 (コミットメッセージに記載されているChange-ID)
  • ELFファイルフォーマットに関する一般的な情報 (Wikipediaなど): https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
  • Makefileに関する一般的な情報 (GNU Makeマニュアルなど): https://www.gnu.org/software/make/manual/
  • Goのgo toolコマンドに関する情報 (Goのドキュメントやブログ記事): go toolは内部ツールであり、公式ドキュメントには詳細な説明がない場合がありますが、Goのソースコードや関連するブログ記事でその使用法が解説されていることがあります。