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

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

コミット

commit 5b04d670912aaaa87fdc9a8547a7e71094150661
Author: Russ Cox <rsc@golang.org>
Date:   Mon Sep 9 13:04:14 2013 -0400

    cmd/cgo: record full source path to input .go files
    
    Fixes #5122.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/13395046

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

https://github.com/golang/go/commit/5b04d670912aaaa87fdc9a8547a7e71094150661

元コミット内容

cmd/cgo: record full source path to input .go files

このコミットは、cmd/cgo(GoのC言語連携ツール)が入力の.goファイルの完全なソースパスを記録するように変更するものです。これにより、エラーメッセージやデバッグ時の行番号情報に、より正確なファイルパスが使用されるようになります。

変更の背景

この変更は、GoのIssue 5122「go build error messages should use full path names」を修正するために行われました。

Goのツールチェイン、特にcgoを使用する際に、コンパイルエラーやデバッグ情報において、ソースファイルのパスが相対パスで表示されることがありました。これは、特に複雑なプロジェクト構造や、異なるディレクトリからビルドを実行する場合に、エラーの発生源を特定しにくくするという問題を引き起こしていました。

例えば、go buildコマンドがエラーを報告する際に、./foo.go:10: syntax errorのように表示されると、foo.goがどのディレクトリにあるのかがすぐに分かりません。しかし、go buildの他の部分では絶対パスが使用されることがあり、cgoだけが相対パスを使用していると、ツールチェイン全体での一貫性が損なわれ、ユーザー体験が悪化します。

この不整合を解消し、エラーメッセージやデバッグ情報の一貫性と正確性を向上させるために、cgoが入力ファイルの絶対パスを記録するように変更する必要がありました。

前提知識の解説

  • Go言語 (Golang): Googleによって開発されたオープンソースのプログラミング言語。シンプルさ、効率性、並行処理のサポートが特徴です。
  • cgo: GoプログラムからC言語のコードを呼び出すためのGoツール。C言語のライブラリを利用したり、既存のC言語コードベースと連携したりする際に使用されます。cgoは、Goのソースコード内にC言語のコードを埋め込むことを可能にし、GoとCの間のデータ変換や関数呼び出しを処理します。
  • ツールチェイン (Toolchain): ソフトウェア開発に必要な一連のツール群(コンパイラ、リンカ、デバッガなど)を指します。Go言語の場合、go buildgo rungo testなどのコマンドがGoツールチェインの一部です。
  • 絶対パス (Absolute Path): ファイルシステムにおけるファイルの完全な位置を示すパス。ルートディレクトリから始まり、すべてのディレクトリ階層を含みます(例: /home/user/project/main.go)。
  • 相対パス (Relative Path): 現在の作業ディレクトリからの相対的な位置を示すパス(例: ./main.go../src/utils.go)。
  • go/tokenパッケージ: Goのソースコードを解析する際に、トークン(キーワード、識別子、演算子など)の位置情報(ファイル、行番号、列番号)を管理するためのパッケージ。
  • go/astパッケージ: Goのソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのパッケージ。コンパイラやツールがソースコードを解析し、構造を理解するために使用します。
  • filepath.Abs関数: Goのpath/filepathパッケージに含まれる関数で、与えられたパスを絶対パスに変換します。

技術的詳細

このコミットの技術的な核心は、cgoがGoのソースファイルを読み込む際に、そのファイルのパスを絶対パスに変換してから処理するように変更することです。

具体的には、src/cmd/cgo/ast.goファイルのFile.ReadGo関数が変更されています。この関数は、Goのソースファイルを読み込み、その内容を解析して抽象構文木(AST)を構築する役割を担っています。

変更前は、File.ReadGo関数に渡されたファイル名(name引数)がそのまま使用されていました。このnameは、go buildコマンドがcgoを呼び出す際の引数として渡されるもので、相対パスである可能性がありました。

変更後は、File.ReadGo関数の冒頭で、filepath.Abs(name)を呼び出すことで、入力されたファイル名nameを絶対パスに変換しようと試みます。もし変換が成功し、エラーが発生しなければ、変換された絶対パスが新しいnameとして使用されます。これにより、cgoの内部処理、特にエラーメッセージの生成やデバッグ情報の記録において、常にファイルの絶対パスが参照されるようになります。

この変更は、Goツールチェイン全体でのパスの取り扱いの一貫性を向上させ、ユーザーがエラーメッセージから問題の箇所をより正確に特定できるようにすることを目的としています。

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

src/cmd/cgo/ast.go

--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -13,6 +13,7 @@ import (
  	"go/scanner"
  	"go/token"
  	"os"
+	"path/filepath"
  	"strings"
  )
  
@@ -44,6 +45,13 @@ func sourceLine(n ast.Node) int {
  // a list of exported functions, and the actual AST, to be rewritten and
  // printed.
  func (f *File) ReadGo(name string) {
+	// Create absolute path for file, so that it will be used in error
+	// messages and recorded in debug line number information.
+	// This matches the rest of the toolchain. See golang.org/issue/5122.
+	if aname, err := filepath.Abs(name); err == nil {
+		name = aname
+	}
+
  	// Two different parses: once with comments, once without.
  	// The printer is not good enough at printing comments in the
  	// right place when we start editing the AST behind its back,

src/cmd/go/test.bash

--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -463,6 +463,26 @@ import "C"
 rm -rf $d
 unset GOPATH
 
+TEST cgo shows full path names
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/dirname
+echo '
+package foo
+import "C"
+func f() {
+' >$d/src/x/y/dirname/foo.go
+if ./testgo build x/y/dirname >$d/err 2>&1; then
+	echo build succeeded unexpectedly.
+	ok=false
+elif ! grep x/y/dirname $d/err >/dev/null; then
+	echo error did not use full path.
+	cat $d/err
+	ok=false
+fi
+rm -rf $d
+unset GOPATH
+
 # clean up
 if $started; then stop; fi
 rm -rf testdata/bin testdata/bin1

コアとなるコードの解説

src/cmd/cgo/ast.go の変更

  • import "path/filepath" の追加: ファイルパス操作のための標準ライブラリパッケージpath/filepathがインポートされました。
  • File.ReadGo 関数の変更:
    • if aname, err := filepath.Abs(name); err == nil { name = aname } の行が追加されました。
    • このコードは、filepath.Abs(name)を呼び出して、入力されたファイル名nameの絶対パスを取得しようとします。
    • filepath.Absは、パスを絶対パスに変換する際に、シンボリックリンクの解決やカレントディレクトリの考慮などを行います。
    • もしエラーが発生せず(err == nil)、絶対パスanameが正常に取得できた場合、元のname変数をこの絶対パスanameで上書きします。
    • これにより、File.ReadGo関数以降の処理(ASTの構築、エラーメッセージの生成、デバッグ情報の記録など)では、常にファイルの絶対パスが使用されるようになります。
    • コメント // This matches the rest of the toolchain. See golang.org/issue/5122. は、この変更がGoツールチェイン全体の一貫性を保つためのものであり、関連するIssue 5122に言及しています。

src/cmd/go/test.bash の変更

  • 新しいテストケースの追加: TEST cgo shows full path names という新しいテストケースが追加されました。
  • テストの目的: このテストは、cgoがエラーメッセージで完全なパス名を表示するかどうかを検証します。
  • テストの手順:
    1. 一時ディレクトリを作成し、GOPATHとして設定します。
    2. $d/src/x/y/dirname/foo.goというパスに、意図的に構文エラーを含むGoソースファイルを作成します(func f() { の後に閉じ括弧がない)。
    3. ./testgo build x/y/dirname コマンドを実行し、ビルドエラーを発生させます。
    4. ビルドが成功した場合はテストを失敗とします(エラーが期待されるため)。
    5. エラー出力$d/errの中に、x/y/dirnameという部分パスが含まれているかどうかをgrepで確認します。
    6. もしx/y/dirnameが含まれていない場合(つまり、完全なパスが表示されていない場合)、テストを失敗とします。これは、エラーメッセージに相対パスではなく、ディレクトリ名を含む完全なパスが表示されることを期待しているためです。
    7. 一時ディレクトリをクリーンアップします。

このテストケースは、cgoがIssue 5122で報告された問題を修正し、エラーメッセージに絶対パス(または少なくともディレクトリ名を含むより詳細なパス)を正しく表示するようになったことを確認するために非常に重要です。

関連リンク

参考にした情報源リンク