[インデックス 15661] ファイルの概要
このコミットは、Go言語のリンカ (cmd/ld
) に新しいコマンドラインフラグ -tmpdir
を追加するものです。このフラグを使用することで、リンカが生成する一時ファイルを指定したディレクトリに残すことが可能になり、デバッグやビルドプロセスの詳細な調査が容易になります。
コミット
commit e982ecacd1920d4314c84ecfca316a9bf0698fd3
Author: Russ Cox <rsc@golang.org>
Date: Sun Mar 10 12:50:44 2013 -0400
cmd/ld: add tmpdir flag to preserve temp files
R=ken2
CC=golang-dev
https://golang.org/cl/7497044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e982ecacd1920d4314c84ecfca316a9bf0698fd3
元コミット内容
cmd/ld: add tmpdir flag to preserve temp files
R=ken2
CC=golang-dev
https://golang.org/cl/7497044
変更の背景
Go言語のビルドプロセスにおいて、リンカ (cmd/ld
) は実行可能ファイルを生成する際に、中間的な一時ファイルを生成します。通常、これらのファイルはリンカの処理が完了すると自動的に削除されます。しかし、リンカの動作をデバッグしたり、生成される中間ファイルの内容を詳細に調査したりする際には、これらのファイルが削除されてしまうと不便でした。
このコミットの背景には、開発者やデバッガがリンカの内部動作をより深く理解し、問題の診断を容易にするためのニーズがあったと考えられます。一時ファイルを保持する機能は、特に複雑なビルドの問題や、リンカの最適化、あるいは特定の環境での挙動の違いを調査する際に非常に有用です。
前提知識の解説
Go言語のビルドプロセス
Go言語のプログラムは、通常、go build
コマンドによってコンパイルされ、リンクされて実行可能ファイルが生成されます。このプロセスは大きく分けて以下の段階を含みます。
- コンパイル: Goのソースコード (
.go
ファイル) は、コンパイラ (cmd/compile
) によってアセンブリコードに変換され、オブジェクトファイル (.o
ファイル) が生成されます。 - アセンブル: オブジェクトファイルは、アセンブラによって機械語に変換されます。
- リンク: リンカ (
cmd/ld
) は、生成されたオブジェクトファイル、Goランタイムライブラリ、およびその他の必要なライブラリを結合し、単一の実行可能ファイルを生成します。この際、シンボル解決、アドレスの再配置、デバッグ情報の埋め込みなどが行われます。
cmd/ld
(Goリンカ)
cmd/ld
は、Go言語のツールチェインにおけるリンカです。C言語の ld
コマンドと同様に、複数のオブジェクトファイルやライブラリを結合して実行可能ファイルや共有ライブラリを生成する役割を担います。Goのリンカは、Goプログラムの特性(例えば、静的リンクがデフォルトであること、ガベージコレクション、goroutineスケジューラなど)を考慮して設計されています。
一時ファイル
ソフトウェアのビルドプロセスでは、多くの場合、中間的な処理結果を一時ファイルとしてディスクに書き出すことがあります。リンカも同様に、シンボルテーブル、再配置情報、デバッグ情報など、最終的な実行可能ファイルに組み込まれる前の様々なデータを一時ファイルとして利用することがあります。これらのファイルは通常、処理が完了すると自動的に削除され、ユーザーからは見えません。
コマンドラインフラグ
コマンドラインフラグ(またはオプション)は、プログラムの実行時にその挙動を制御するために使用される引数です。Goのツールチェインでは、多くのコマンドが -flagname
の形式でフラグを受け入れます。例えば、go build -o myapp
は、出力ファイル名を myapp
に指定するフラグです。
技術的詳細
このコミットは、Goリンカ (cmd/ld
) の内部に、一時ファイルを保持するための新しいメカニズムを導入します。具体的には、以下の変更が行われています。
tmpdir
フラグの追加: リンカの各アーキテクチャ固有のエントリポイント (src/cmd/5l/obj.c
,src/cmd/6l/obj.c
,src/cmd/8l/obj.c
はそれぞれARM、x86-64、x86のリンカに対応) に、-tmpdir
という新しいコマンドラインフラグが追加されました。このフラグは文字列引数を取り、一時ファイルを保存するディレクトリのパスを指定します。- 一時ディレクトリ管理の変更:
src/cmd/ld/lib.c
はリンカの共通ライブラリであり、一時ディレクトリの作成とクリーンアップを担当するロジックが含まれています。- 以前は、
tmpdir
変数はstatic char *tmpdir;
としてローカルに宣言され、リンカが起動すると常に新しい一時ディレクトリを作成し、atexit(rmtemp)
を使ってプログラム終了時にそのディレクトリを削除するように設定されていました。 - 変更後、
tmpdir
変数はEXTERN char* tmpdir;
としてsrc/cmd/ld/lib.h
で外部変数として宣言され、他のファイルからアクセス可能になりました。 hostlinksetup
関数内で、tmpdir
がnil
(Goにおけるnull
に相当) である場合にのみ、新しい一時ディレクトリを作成し、クリーンアップを設定するようになりました。これにより、-tmpdir
フラグで明示的にディレクトリが指定された場合(tmpdir
がnil
でなくなる)は、リンカが自動的に一時ディレクトリを作成したり削除したりしないようになります。つまり、ユーザーが指定したディレクトリはリンカによって削除されません。
- 以前は、
flagstr
の利用: コマンドラインフラグを解析するためにflagstr
関数が使用されています。これは、文字列型のフラグを定義し、その値を指定された変数に格納するためのGoの標準的なフラグパーシングメカニズムの一部です。
この変更により、リンカはデフォルトでは引き続き一時ファイルを自動的にクリーンアップしますが、ユーザーが -tmpdir /path/to/my/temp
のようにフラグを指定すると、指定されたディレクトリに一時ファイルが生成され、リンカの終了後もそのファイルが残るようになります。これは、デバッグや詳細な分析を行う際に非常に役立ちます。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルは以下の通りです。
src/cmd/5l/obj.c
: ARMアーキテクチャ向けリンカのメイン関数に-tmpdir
フラグの定義を追加。src/cmd/6l/obj.c
: x86-64アーキテクチャ向けリンカのメイン関数に-tmpdir
フラグの定義を追加。また、flag_shared
フラグの定義順序が変更されていますが、これは機能的な変更ではありません。src/cmd/8l/obj.c
: x86アーキテクチャ向けリンカのメイン関数に-tmpdir
フラグの定義を追加。src/cmd/ld/lib.c
: リンカの共通ライブラリ。一時ディレクトリの管理ロジックが変更され、tmpdir
変数の宣言が削除され、外部変数として扱われるようになりました。また、tmpdir
がnil
の場合にのみ一時ディレクトリを作成し、クリーンアップを設定する条件が追加されました。src/cmd/ld/lib.h
: リンカの共通ヘッダファイル。tmpdir
変数がEXTERN char* tmpdir;
として外部変数宣言されました。また、segsym
セグメントの宣言が削除されていますが、これはこのコミットの主要な目的とは直接関係なく、おそらく別の変更の一部か、クリーンアップの一環です。
コアとなるコードの解説
src/cmd/5l/obj.c
, src/cmd/6l/obj.c
, src/cmd/8l/obj.c
における変更
これらのファイルでは、リンカのメイン関数内で新しいコマンドラインフラグ -tmpdir
が追加されています。
// 変更前 (例: src/cmd/5l/obj.c)
// flagcount("s", "disable symbol table", &debug['s']);
// 変更後 (例: src/cmd/5l/obj.c)
flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
// flagcount("s", "disable symbol table", &debug['s']);
flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagstr
: Goのフラグパーシングライブラリの一部で、文字列型のコマンドラインフラグを定義するために使用されます。- 第一引数
"tmpdir"
: フラグの名前です。コマンドラインで-tmpdir
として指定されます。 - 第二引数
"leave temporary files in this directory"
: フラグの短い説明です。ヘルプメッセージなどに表示されます。 - 第三引数
&tmpdir
: フラグの値が格納される変数のアドレスです。このtmpdir
変数は、src/cmd/ld/lib.h
で外部変数として宣言されています。
src/cmd/ld/lib.c
における変更
このファイルでは、一時ディレクトリの管理ロジックが変更されています。
// 変更前
// static char *tmpdir; // ローカル変数として宣言されていた
static void
rmtemp(void)
{
// ... (一時ディレクトリ削除ロジック)
}
void
hostlinksetup(void)
{
// ...
// create temporary directory and arrange cleanup
// TODO: Add flag to specify tempdir, which is then not cleaned up.
tmpdir = mktempdir(); // 常に新しい一時ディレクトリを作成
atexit(rmtemp); // 常に終了時に削除を設定
// ...
}
// 変更後
// tmpdir の宣言は lib.h に移動
static void
rmtemp(void)
{
// ... (一時ディレクトリ削除ロジック)
}
void
hostlinksetup(void)
{
// ...
if(tmpdir == nil) { // tmpdir が nil の場合のみ
tmpdir = mktempdir(); // 新しい一時ディレクトリを作成
atexit(rmtemp); // 終了時に削除を設定
}
// ...
}
static char *tmpdir;
の削除:tmpdir
変数がこのファイル内でローカルに宣言されていたものが削除され、src/cmd/ld/lib.h
で外部変数として宣言されるようになりました。これにより、コマンドラインフラグからこの変数に値を設定できるようになります。if(tmpdir == nil)
条件の追加:hostlinksetup
関数内で、一時ディレクトリの作成とクリーンアップの設定がif(tmpdir == nil)
という条件ブロック内に移動しました。tmpdir == nil
: これは、ユーザーがコマンドラインで-tmpdir
フラグを指定しなかった場合(つまり、tmpdir
変数に値が設定されていない場合)に真となります。mktempdir()
: 一時ディレクトリを作成し、そのパスを返します。atexit(rmtemp)
: プログラムが正常終了する際にrmtemp
関数を呼び出すように登録します。rmtemp
関数は、作成された一時ディレクトリを削除する役割を担います。
この変更により、ユーザーが -tmpdir
フラグでパスを指定した場合、tmpdir
は nil
ではなくなるため、リンカは自動的に一時ディレクトリを作成したり、そのディレクトリを削除したりしなくなります。これにより、ユーザーが指定した一時ファイルが保持されるようになります。
src/cmd/ld/lib.h
における変更
// 変更前
// EXTERN char*\tinterpreter;
// EXTERN Segment segsym;
// EXTERN Segment segdwarf;
// 変更後
EXTERN char*\tinterpreter;
EXTERN char*\ttmpdir; // 新しく追加
// EXTERN Segment segsym; // 削除
EXTERN Segment segdwarf;
EXTERN char* tmpdir;
の追加:tmpdir
変数が外部変数として宣言されました。これにより、リンカの異なる部分(例えば、各アーキテクチャのobj.c
ファイル)からこの変数にアクセスし、値を設定できるようになります。EXTERN Segment segsym;
の削除:segsym
セグメントの宣言が削除されています。これはこのコミットの主要な目的とは直接関係ありませんが、リンカの内部構造に関する別の変更の一部である可能性があります。
関連リンク
- Go言語のリンカに関するドキュメント (Goの公式ドキュメントやツールチェインのソースコードが参考になります)
- Go言語のビルドプロセスに関する情報
参考にした情報源リンク
- Go言語の公式ドキュメント: https://golang.org/doc/
- Go言語のソースコードリポジトリ: https://github.com/golang/go
- Go言語のコードレビューシステム (Gerrit): https://golang.org/cl/7497044 (コミットメッセージに記載されている変更リストへのリンク)
- Go言語の
flag
パッケージに関するドキュメント (Goのコマンドラインフラグの扱いについて): https://pkg.go.dev/flag (これはGoの標準ライブラリであり、リンカのC言語コードとは直接関係ありませんが、Goのツールチェイン全体でフラグがどのように扱われるかの概念理解に役立ちます。) - Go言語の
cmd/ld
のソースコード (GitHub): https://github.com/golang/go/tree/master/src/cmd/ld - Go言語の
cmd/5l
,cmd/6l
,cmd/8l
のソースコード (GitHub):