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

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

このコミットは、Go言語のビルドツールであるcmd/goにおいて、生成されるバイナリファイルから一時的な作業ディレクトリのパス($WORKパス)が埋め込まれる問題を修正するものです。これにより、ビルドの再現性が向上し、デバッグ情報のクリーンアップが図られます。

コミット

commit df623d03ab2518e691d198b51380a005332d251d
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Aug 7 10:00:58 2012 +0800

    cmd/go: remove $WORK paths in generated binaries
            Fixes #3748.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6357064

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

https://github.com/golang/go/commit/df623d03ab2518e691d198b51380a005332d251d

元コミット内容

cmd/go: remove $WORK paths in generated binaries Fixes #3748.

このコミットは、Goのビルドプロセスによって生成されるバイナリファイルに、ビルド時の一時作業ディレクトリのパス($WORKパス)が埋め込まれる問題を解決します。これは、GoのIssue #3748で報告された問題の修正です。

変更の背景

Go言語のビルドシステムは、コンパイルやリンクの際に一時的な作業ディレクトリ($WORK)を使用します。このディレクトリは、ソースファイルからオブジェクトファイル、アーカイブファイル、最終的な実行可能ファイルが生成される過程で中間ファイルを格納するために利用されます。

しかし、Go 1.0のリリース後、生成されたバイナリファイル(特にアーカイブファイルやデバッグ情報)に、この一時的な$WORKディレクトリの絶対パスが埋め込まれてしまうという問題が報告されました(Issue #3748)。この問題は、以下のような影響を引き起こしました。

  1. ビルドの再現性の低下: 同じソースコードからビルドしても、ビルドを実行する環境やタイミングによって$WORKディレクトリのパスが異なるため、生成されるバイナリが完全に同一にならないという問題が発生しました。これは、ソフトウェアの検証や配布において望ましくありません。
  2. デバッグ情報のノイズ: デバッグ情報に一時的なパスが含まれることで、デバッグ時の情報が冗長になったり、環境依存性が発生したりする可能性がありました。
  3. セキュリティとプライバシー: ビルド環境のファイルシステム構造に関する情報がバイナリに漏洩する可能性がありました。

このコミットは、これらの問題を解決し、生成されるバイナリのクリーンさと再現性を向上させることを目的としています。

前提知識の解説

Goのビルドプロセスと$WORKディレクトリ

Goのビルドプロセスは、go buildコマンドによって実行されます。このコマンドは、内部的に以下のステップを踏みます。

  1. 依存関係の解決: 必要なパッケージを特定し、ダウンロードします。
  2. コンパイル: 各Goソースファイル(.go)をコンパイルし、オブジェクトファイル(.o)を生成します。
  3. アーカイブ: オブジェクトファイルをまとめてアーカイブファイル(.a)を生成します。これは、C/C++における静的ライブラリに相当します。
  4. リンク: アーカイブファイルと必要なランタイムライブラリをリンクし、最終的な実行可能ファイルまたは共有ライブラリを生成します。

このプロセス中、Goツールチェーンは一時的な作業ディレクトリを作成します。このディレクトリは通常、$TMPDIR/go-buildXXXXXのような形式で、ビルドが完了すると削除されます。この一時ディレクトリが、本コミットで問題となっている$WORKパスに該当します。

packコマンド

packコマンドは、Goツールチェーンの一部であり、オブジェクトファイルをアーカイブファイルにまとめるために使用されます。これは、arコマンド(Unix系のシステムでアーカイブを作成・管理するためのユーティリティ)に似た機能を提供します。

Goのビルドプロセスにおいて、packコマンドはコンパイルされたオブジェクトファイルを収集し、それらを単一のアーカイブファイル(.a)に結合します。このアーカイブファイルは、後続のリンクステップで利用されます。

grcgrcPオプション

packコマンドには、アーカイブの作成方法を制御するための様々なオプションがあります。

  • grc: これは、Goのツールチェーンが内部的に使用するpackコマンドのオプションの一つで、"create" (作成) を意味します。
  • grcP: このコミットで導入された、または既存のpackコマンドのオプションの利用方法を変更したものです。Pは"prefix" (プレフィックス) を意味し、アーカイブ内のパスから特定のプレフィックス(この場合は$WORKパス)を取り除くことを指示します。

技術的詳細

このコミットの技術的な核心は、Goツールチェーンが内部的にpackコマンドを呼び出す際の引数を変更することによって、生成されるアーカイブファイルから$WORKパスを削除する点にあります。

変更前は、packコマンドはgrcオプションを使用してアーカイブを作成していました。この際、オブジェクトファイルのパスはそのままアーカイブに埋め込まれていました。もしオブジェクトファイルが$WORKディレクトリ内にあった場合、その絶対パスがアーカイブに記録されていました。

変更後は、packコマンドの呼び出しにgrcPオプションと、b.workという引数が追加されました。

  • grcP: このオプションは、packコマンドに対して、アーカイブに含めるファイルのパスから指定されたプレフィックス(b.work、つまり$WORKディレクトリのパス)を取り除くように指示します。
  • b.work: これは、現在のビルドプロセスで使用されている一時的な$WORKディレクトリの絶対パスを表します。

これにより、packコマンドはアーカイブを作成する際に、各オブジェクトファイルのパスから$WORKディレクトリのプレフィックスを削除します。例えば、オブジェクトファイルが/tmp/go-build12345/src/pkg/foo.oというパスにあった場合、packコマンドはアーカイブ内にsrc/pkg/foo.oとして記録するようになります。結果として、生成されるアーカイブファイルには、ビルド環境に依存しない相対パスのみが埋め込まれることになります。

この変更は、src/cmd/go/build.goファイル内のgcToolchain.packメソッドに適用されています。このメソッドは、Goの標準コンパイラ(gc)ツールチェーンがパッケージをアーカイブする際のロジックを定義しています。

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

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1299,7 +1299,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 	for _, f := range ofiles {
 		absOfiles = append(absOfiles, mkAbs(objDir, f))\n 	}
-\treturn b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)\n+\treturn b.run(p.Dir, p.ImportPath, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)\n }\n 
 func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {

コアとなるコードの解説

変更はsrc/cmd/go/build.goファイルのgcToolchain.packメソッド内の一行に集約されています。

元のコード:

return b.run(p.Dir, p.ImportPath, tool("pack"), "grc", mkAbs(objDir, afile), absOfiles)

この行では、packコマンドをgrcオプションと共に実行し、オブジェクトファイル(absOfiles)をアーカイブファイル(mkAbs(objDir, afile))にまとめる処理を行っていました。

変更後のコード:

return b.run(p.Dir, p.ImportPath, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)

この変更では、packコマンドのオプションが"grc"から"grcP"に変更され、さらにb.workという新しい引数が追加されています。

  • tool("pack"): packコマンドの実行可能ファイルへのパスを取得します。
  • "grcP": packコマンドに渡される新しいオプションです。前述の通り、これはアーカイブ内のパスから指定されたプレフィックス(b.work)を取り除くことを指示します。
  • b.work: builder構造体(b)のworkフィールドは、現在のビルドプロセスで使用されている一時的な$WORKディレクトリの絶対パスを保持しています。このパスがgrcPオプションの引数としてpackコマンドに渡されます。
  • mkAbs(objDir, afile): 生成されるアーカイブファイルの絶対パスです。
  • absOfiles: アーカイブに含めるオブジェクトファイルの絶対パスのリストです。

この変更により、packコマンドはabsOfiles内の各パスからb.workで指定されたプレフィックスを削除した上で、アーカイブに格納するようになります。これにより、生成されるアーカイブファイルには、ビルド環境に依存しない相対パスのみが記録され、Issue #3748で報告された問題が解決されます。

関連リンク

参考にした情報源リンク