[インデックス 19157] ファイルの概要
コミット
このコミット e97b3ab1f942a1bb2812e6b5c890c052903fa0b0
は、Goのビルドシステムにおける重要な改善を導入しています。主な目的は、ビルドの再現性を向上させ、最終バイナリに含まれるファイルパスの冗長性や一時ディレクトリへの依存を排除することです。具体的には、一時ディレクトリ名がバイナリに埋め込まれることによるビルドの非再現性の問題を解決し、GOROOT_FINAL
環境変数のサポートを再導入しています。
この変更により、コンパイルされた生成ファイル(例: /tmp/12345/work/x.c
)のフルパスが最終バイナリのpcln
(プログラムカウンタから行番号へのマッピング)テーブルに含まれることで、異なる一時ディレクトリを使用するたびに異なるバイナリが生成されるという問題が解消されます。これは、go tool pack
の P
フラグが提供していた機能に代わるもので、liblink
に -trimpath
フラグを導入し、cmd/go
がこのフラグを使用するように変更することで実現されています。
また、GOROOT_FINAL
のサポートが再実装されました。これは、Goのディストリビューションを特定のパス(例: /usr/local/go
)にインストールする準備をする際に、実際の作業ディレクトリとは異なる最終的なインストールパスをバイナリに記録するために使用されます。以前のビルドシステム変更で失われていたこの機能が復活し、$TMPDIR
や $GOROOT
への参照が最終バイナリから完全に排除されることが、コミットメッセージ内の strings
コマンドの出力例で示されています。
さらに、アセンブラにおけるコマンドライン引数解析が、Goの flag
パッケージのセマンティクスに準拠するように変更されました。これは、Go 1.1でコンパイラとリンカに適用された変更と同様のものです。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e97b3ab1f942a1bb2812e6b5c890c052903fa0b0
元コミット内容
build: remove tmp dir names from objects, support GOROOT_FINAL again
If we compile a generated file stored in a temporary
directory - let's say /tmp/12345/work/x.c - then by default
6c stores the full path and then the pcln table in the
final binary includes the full path. This makes repeated builds
(using different temporary directories) produce different
binaries, even if the inputs are the same.
In the old 'go tool pack', the P flag specified a prefix to remove
from all stored paths (if present), and cmd/go invoked
'go tool pack grcP $WORK' to remove references to the
temporary work directory.
We've changed the build to avoid pack as much as possible,
under the theory that instead of making pack convert from
.6 to .a, the tools should just write the .a directly and save a
round of I/O.
Instead of going back to invoking pack always, define a common
flag -trimpath in the assemblers, C compilers, and Go compilers,
implemented in liblink, and arrange for cmd/go to use the flag.
Then the object files being written out have the shortened paths
from the start.
While we are here, reimplement pcln support for GOROOT_FINAL.
A build in /tmp/go uses GOROOT=/tmp/go, but if GOROOT_FINAL=/usr/local/go
is set, then a source file named /tmp/go/x.go is recorded instead as
/usr/local/go/x.go. We use this so that we can prepare distributions
to be installed in /usr/local/go without actually working in that
directory. The conversion to liblink deleted all the old file name
handling code, including the GOROOT_FINAL translation.
Bring the GOROOT_FINAL translation back.
Before this CL, using GOROOT_FINAL=/goroot make.bash:
g% strings $(which go) | grep -c $TMPDIR
6
g% strings $(which go) | grep -c $GOROOT
793
g%
After this CL:
g% strings $(which go) | grep -c $TMPDIR
0
g% strings $(which go) | grep -c $GOROOT
0
g%
(The references to $TMPDIR tend to be cgo-generated source files.)
Adding the -trimpath flag to the assemblers required converting
them to the new Go-semantics flag parser. The text in go1.3.html
is copied and adjusted from go1.1.html, which is when we applied
that conversion to the compilers and linkers.
Fixes #6989.
LGTM=iant
R=r, iant
CC=golang-codereviews
https://golang.org/cl/88300045
変更の背景
このコミットは、主に以下の2つの問題に対処するために行われました。
-
ビルドの非再現性(Non-reproducible builds)の解消: Goのビルドプロセスにおいて、一時ディレクトリ(例:
/tmp/12345/work/
)内で生成されたC言語のソースファイル(x.c
など)をコンパイルすると、その一時ディレクトリを含むフルパスが最終的なGoバイナリのpcln
(Program Counter to Line Number)テーブルに記録されていました。この結果、同じソースコードからビルドしても、一時ディレクトリ名が異なるたびに生成されるバイナリのハッシュ値が異なってしまい、ビルドの再現性が損なわれていました。これは、ソフトウェアの信頼性やセキュリティ監査において重要な問題となります。 -
GOROOT_FINAL
環境変数のサポート再導入: Goのビルドシステムでは、Goのディストリビューションを特定のパス(例:/usr/local/go
)にインストールする際に、ビルド時のGOROOT
(例:/tmp/go
)とは異なる最終的なインストールパスをバイナリに記録する機能が必要でした。これは、GOROOT_FINAL
環境変数によって制御されていました。しかし、ビルドシステムの内部変更(特にgo tool pack
からの移行)の過程で、このファイルパス変換ロジックが失われていました。これにより、Goの公式ディストリビューションを準備する際に不便が生じていました。
これらの問題は、Goのビルドシステムの進化と最適化の過程で生じたものであり、より堅牢で柔軟なビルドプロセスを確立するために解決が必要でした。
前提知識の解説
このコミットを理解するためには、以下のGoのビルドシステムと関連する概念についての知識が役立ちます。
-
Goのビルドプロセス: Goのプログラムは、ソースコードから最終的な実行可能バイナリが生成されるまでに、複数の段階を経ます。
- コンパイラ(
gc
): Goのソースコード(.go
ファイル)をオブジェクトファイル(.o
ファイル)にコンパイルします。 - アセンブラ(
5a
,6a
,8a
など): アセンブリ言語のソースコード(.s
ファイル)をオブジェクトファイルにアセンブルします。これらは特定のアーキテクチャ(例:5a
はARM、6a
はAMD64、8a
は386)に対応します。 - Cコンパイラ(
cc
):cgo
によって生成されたC言語のソースコードをコンパイルします。 - リンカ(
ld
): 複数のオブジェクトファイルやアーカイブファイル(.a
ファイル)を結合し、最終的な実行可能バイナリを生成します。 cmd/go
: これらすべてのツールをオーケストレーションし、ビルドプロセス全体を管理するコマンドラインツールです。
- コンパイラ(
-
pcln
テーブル(Program Counter to Line Number Table): Goの実行可能バイナリには、デバッグ情報としてpcln
テーブルが含まれています。これは、プログラムカウンタ(実行中の命令のアドレス)と、対応するソースコードのファイル名および行番号をマッピングするデータ構造です。デバッガがスタックトレースを表示したり、エラーメッセージに行番号を含めたりする際にこの情報が使用されます。このテーブルに一時ディレクトリのフルパスが含まれることが、ビルドの非再現性の原因となっていました。 -
再現可能なビルド(Reproducible Builds): 再現可能なビルドとは、同じソースコード、同じビルドツール、同じビルド環境が与えられた場合、常にビット単位で同一のバイナリが生成されることを保証するプロセスです。これにより、ソフトウェアのサプライチェーンの信頼性が向上し、悪意のある改ざんや意図しない変更がないことを検証できるようになります。一時ディレクトリ名のようなビルド環境に依存する情報がバイナリに埋め込まれると、再現可能なビルドが妨げられます。
-
go tool pack
: Go 1.0からGo 1.3の間に存在したツールで、オブジェクトファイル(.6
など)をアーカイブファイル(.a
)に変換したり、アーカイブファイルを操作したりするために使用されていました。このツールには、バイナリに埋め込まれたパスから特定のプレフィックスを削除する機能(P
フラグ)がありました。しかし、Goのビルドシステムは、I/Oのオーバーヘッドを減らすために、pack
を介さずにツールが直接.a
ファイルを書き込むように進化していました。 -
GOROOT
とGOROOT_FINAL
:GOROOT
: Goのインストールディレクトリを示す環境変数です。ビルド時にGoの標準ライブラリやツールを探すために使用されます。GOROOT_FINAL
: Goのディストリビューションをビルドする際に使用される特別な環境変数です。ビルドは一時的なGOROOT
で行われるが、最終的にバイナリに記録されるパスはGOROOT_FINAL
で指定されたパスになるようにします。これにより、Goのバイナリが特定の場所にインストールされることを想定してビルドできます。
-
cgo
: GoプログラムからC言語のコードを呼び出すためのメカニズムです。cgo
を使用すると、Goのソースファイル内にC言語のコードを記述でき、Goのビルドプロセスが自動的にCコードをコンパイルし、Goコードとリンクします。この際、一時的なCソースファイルが生成されることがあります。 -
Goのコマンドライン引数解析: Goのツール(コンパイラ、リンカ、アセンブラなど)は、コマンドライン引数を解析します。伝統的なUnixのツールは独自の引数解析ルールを持つことが多いですが、Goの標準ライブラリには
flag
パッケージがあり、Goらしい引数解析のセマンティクスを提供します。Goのツールは徐々にこのflag
パッケージのセマンティクスに移行しています。
技術的詳細
このコミットは、前述の問題を解決するために、以下の主要な技術的変更を導入しています。
-
-trimpath
フラグの導入とliblink
での実装:- 目的: 最終バイナリの
pcln
テーブルから、ビルド時の一時ディレクトリパスやその他の不要なプレフィックスを削除すること。これにより、ビルドの再現性を確保します。 - 実装:
- アセンブラ(
5a
,6a
,8a
)、Cコンパイラ(cc
)、Goコンパイラ(gc
)に共通の-trimpath
フラグが追加されました。 - このフラグの実際の処理は、Goのリンカライブラリである
liblink
内で行われます。 liblink/obj.c
内のlinkgetline
関数が変更され、ctxt->trimpath
で指定されたプレフィックスがファイルパスから削除されるロジックが追加されました。具体的には、haspathprefix
ヘルパー関数が導入され、パスが指定されたプレフィックスで始まる場合に、そのプレフィックスを削除して相対パスを記録するように動作します。これにより、一時ディレクトリのパスがバイナリに埋め込まれることを防ぎます。
- アセンブラ(
- 目的: 最終バイナリの
-
GOROOT_FINAL
サポートの再実装:- 目的: ビルド時の
GOROOT
パスを、最終的なインストールパスであるGOROOT_FINAL
に置き換えてバイナリに記録すること。 - 実装:
liblink/sym.c
内で、GOROOT
(getgoroot()
で取得)とGOROOT_FINAL
(環境変数GOROOT_FINAL
から取得)がリンカのコンテキスト(Link
構造体)に設定されるようになりました。liblink/obj.c
のlinkgetline
関数に、trimpath
処理に加えてGOROOT_FINAL
の変換ロジックが追加されました。もしファイルパスが現在のGOROOT
で始まり、かつGOROOT_FINAL
が設定されている場合、パスのGOROOT
部分がGOROOT_FINAL
に置き換えられます。これにより、Goのディストリビューションが特定の場所にインストールされることを想定したバイナリが生成されます。
- 目的: ビルド時の
-
cmd/go
による-trimpath
フラグの利用:src/cmd/go/build.go
が変更され、go
コマンドがコンパイラやアセンブラを呼び出す際に、ビルド作業ディレクトリ(b.work
)を-trimpath
フラグの値として渡すようになりました。これにより、ビルド時に使用される一時的な作業ディレクトリのパスが最終バイナリから取り除かれます。
-
アセンブラのコマンドライン引数解析の変更:
- アセンブラ(
5a
,6a
,8a
)の引数解析ロジックが、Goのflag
パッケージのセマンティクスに準拠するように変更されました。これにより、引数の指定方法がより一貫性のあるものになります。例えば、go tool 6a -SDfoo
はgo tool 6a -S -D foo
と書く必要があります。これはGo 1.1でコンパイラとリンカに適用された変更と同様のものです。
- アセンブラ(
これらの変更により、Goのビルドシステムはより堅牢になり、ビルドの再現性が向上し、ディストリビューションの準備が容易になりました。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
-
doc/go1.3.html
:- Go 1.3のリリースノートに、アセンブラのコマンドライン引数解析の変更に関する記述が追加されました。
-
include/link.h
:- リンカのコンテキストを定義する
Link
構造体に、trimpath
、goroot
、goroot_final
という新しいフィールドが追加されました。これらは、パスのトリミングとGOROOT_FINAL
の変換に必要な情報を保持します。
- リンカのコンテキストを定義する
-
src/cmd/5a/lex.c
,src/cmd/6a/lex.c
,src/cmd/8a/lex.c
:- 各アセンブラのメイン関数(
main
)内のコマンドライン引数解析ロジックが、従来のARGBEGIN
/ARGEND
マクロから、Goのflag
パッケージに似たflagfn1
,flagcount
,flagstr
,flagparse
といった関数を使用する形式に書き換えられました。 -trimpath
フラグのサポートが追加されました。debug
配列の型がchar
からint
に変更されました。
- 各アセンブラのメイン関数(
-
src/cmd/cc/lex.c
,src/cmd/gc/lex.c
:- Cコンパイラ(
cc
)とGoコンパイラ(gc
)の引数解析に-trimpath
フラグの定義が追加されました。
- Cコンパイラ(
-
src/cmd/go/build.go
:gcToolchain
構造体のgc
(Goコンパイラ呼び出し)、asm
(アセンブラ呼び出し)、cc
(Cコンパイラ呼び出し) メソッドにおいて、b.work
(ビルド作業ディレクトリ) を-trimpath
フラグの値として渡すように変更されました。pack
メソッドの呼び出しがgrcP
からc
に変更され、pack
の使用を避けるビルド戦略に沿うように修正されました。
-
src/liblink/obj.c
:haspathprefix
という新しいヘルパー関数が追加されました。これは、与えられた文字列が特定のパスプレフィックスを持つかどうかを、大文字小文字を区別せず、スラッシュとバックスラッシュを同一視して判定します。linkgetline
関数が大幅に変更されました。この関数は、pcln
テーブルに記録されるファイルパスと行番号を処理する際に、ctxt->trimpath
が設定されていればそのプレフィックスを削除し、ctxt->goroot_final
が設定されていればGOROOT
パスをGOROOT_FINAL
パスに変換するロジックが追加されました。
-
src/liblink/sym.c
:- リンカのコンテキストを初期化する
linknew
関数内で、getgoroot()
を使って現在のGOROOT
を取得し、環境変数GOROOT_FINAL
を読み込んでLink
構造体のgoroot
およびgoroot_final
フィールドに設定するロジックが追加されました。
- リンカのコンテキストを初期化する
コアとなるコードの解説
src/liblink/obj.c
におけるパス変換ロジック
このコミットの最も重要な変更は、src/liblink/obj.c
内の linkgetline
関数に実装されたパス変換ロジックです。
// src/liblink/obj.c
// ...
static int
haspathprefix(char *s, char *t)
{
int i, cs, ct;
if(t == nil)
return 0;
for(i=0; t[i]; i++) {
cs = s[i];
ct = t[i];
if('A' <= cs && cs <= 'Z')
cs += 'a' - 'A';
if('A' <= ct && ct <= 'Z')
ct += 'a' - 'A';
if(cs == '\\')
cs = '/';
if(ct == '\\')
ct = '/';
if(cs != ct)
return 0;
}
return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
}
// ...
linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
{
// ... (既存のコード)
// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
if(haspathprefix(buf, ctxt->trimpath)) {
if(strlen(buf) == strlen(ctxt->trimpath))
strcpy(buf, "??"); // If path is exactly the trimpath, replace with "??"
else {
// Copy the path after the trimpath prefix
snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
if(buf1[0] == '\0')
strcpy(buf1, "??"); // If resulting path is empty, replace with "??"
strcpy(buf, buf1);
}
} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
// If GOROOT_FINAL is set and path has GOROOT prefix, rewrite it
snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
strcpy(buf, buf1);
}
// ... (既存のコード)
}
-
haspathprefix
関数: この関数は、与えられたパスs
が別のパスt
をプレフィックスとして持っているかをチェックします。特筆すべきは、WindowsとUnixの両方で動作するように、大文字小文字を区別せず(ASCIIの範囲で)、スラッシュ(/
)とバックスラッシュ(\
)を同一視して比較している点です。これにより、異なるOS環境でのパス表現の違いを吸収しています。 -
linkgetline
内のパス変換:-trimpath
処理: まず、ctxt->trimpath
が設定されている場合、現在のファイルパスbuf
がそのプレフィックスを持っているかをhaspathprefix
で確認します。もし持っていれば、そのプレフィックスをパスから削除します。例えば、buf
が/tmp/go-build-12345/src/main.go
でctxt->trimpath
が/tmp/go-build-12345
であれば、src/main.go
のみが残ります。パスが完全にtrimpath
と一致する場合や、トリミング後に空になる場合は、??
に置き換えられます。これは、デバッグ情報として意味のあるパスを保持しつつ、一時ディレクトリの情報を排除するためのものです。GOROOT_FINAL
処理:-trimpath
処理が適用されなかった場合、次にGOROOT_FINAL
の変換が試みられます。ctxt->goroot_final
が設定されており、かつ現在のファイルパスbuf
がctxt->goroot
(ビルド時のGOROOT
)をプレフィックスとして持っている場合、buf
のGOROOT
部分がGOROOT_FINAL
に置き換えられます。例えば、buf
が/tmp/go/src/fmt/print.go
でctxt->goroot
が/tmp/go
、ctxt->goroot_final
が/usr/local/go
であれば、パスは/usr/local/go/src/fmt/print.go
に変換されます。
これらのロジックにより、最終的なバイナリのpcln
テーブルに記録されるファイルパスは、一時ディレクトリのパスを含まず、かつGOROOT_FINAL
の意図するパスに変換されるようになります。
src/liblink/sym.c
における GOROOT
情報の取得
// src/liblink/sym.c
// ...
Link*
linknew(LinkArch *arch)
{
Link *ctxt;
char *p;
ctxt = emallocz(sizeof *ctxt);
ctxt->arch = arch;
ctxt->version = HistVersion;
ctxt->goroot = getgoroot(); // Get current GOROOT
ctxt->goroot_final = getenv("GOROOT_FINAL"); // Get GOROOT_FINAL from environment
if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
ctxt->goroot_final = nil; // Treat empty string as nil
// ... (既存のコード)
}
linknew
関数は、新しいリンカコンテキストを初期化する際に、getgoroot()
関数を呼び出して現在のGOROOT
パスを取得し、getenv("GOROOT_FINAL")
を使って環境変数から GOROOT_FINAL
の値を取得します。取得した値は Link
構造体の対応するフィールドに格納され、linkgetline
関数でのパス変換処理に利用されます。これにより、リンカはビルド環境と最終的なインストール環境の両方のパス情報を認識できるようになります。
src/cmd/go/build.go
における -trimpath
の伝播
// src/cmd/go/build.go
// ...
func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string) error {
// ...
args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
// ...
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
// ...
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
// ...
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
// ...
}
cmd/go
のビルドロジックでは、Goコンパイラ(gc
)、アセンブラ(asm
)、Cコンパイラ(cc
)を呼び出す際に、新たに -trimpath
フラグとその値として現在のビルド作業ディレクトリ(b.work
)を渡すように変更されました。これにより、各コンパイラやアセンブラは、生成するオブジェクトファイルや最終バイナリに、一時的な作業ディレクトリのパスを含めないように動作します。これは、ビルドの再現性を確保するための重要なステップです。
アセンブラの引数解析の変更
src/cmd/5a/lex.c
, src/cmd/6a/lex.c
, src/cmd/8a/lex.c
の変更は、アセンブラのコマンドライン引数解析をGoの flag
パッケージのセマンティクスに合わせるものです。これにより、引数の処理がより標準化され、将来的な拡張や保守が容易になります。例えば、以前は -Dfoo
のように引数と値が連結されていたものが、-D foo
のように分離されるようになりました。これは、Goのツールチェーン全体で一貫した引数解析の挙動を提供するための継続的な取り組みの一環です。
関連リンク
- Go Issue #6989: cmd/go: make builds reproducible - このコミットが修正した問題のトラッキングイシュー。
- Go Change List 88300045: https://golang.org/cl/88300045 - このコミットに対応するGoのコードレビューシステム(Gerrit)の変更リスト。
参考にした情報源リンク
- Goの公式ドキュメント (Go 1.3リリースノート): https://golang.org/doc/go1.3 (特に "Command-line flag parsing" セクション)
- Goのビルドプロセスに関する一般的な情報源 (例: Goのソースコード、Goのブログ記事、Goのドキュメンテーション)
- 再現可能なビルドに関する一般的な情報源 (例: Reproducible Buildsプロジェクトのウェブサイト)
pcln
テーブルに関する情報源 (例: Goのランタイムソースコード、Goのデバッグに関する記事)GOROOT
とGOROOT_FINAL
に関する情報源 (例: Goの環境変数に関するドキュメンテーション)go tool pack
に関する情報源 (Goの古いドキュメンテーションや歴史的な記事)cgo
に関する情報源 (Goの公式ドキュメンテーション)- Goの
flag
パッケージに関する情報源 (Goの標準ライブラリドキュメンテーション) strings
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)grep
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)which
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)filepath.Join
(Go標準ライブラリpath/filepath
パッケージ)os.Stat
(Go標準ライブラリos
パッケージ)fmt.Sprintf
(Go標準ライブラリfmt
パッケージ)strcmp
(C標準ライブラリstring.h
)strlen
(C標準ライブラリstring.h
)strcpy
(C標準ライブラリstring.h
)snprint
(C標準ライブラリstdio.h
)emallocz
(Goランタイム内部のメモリ割り当て関数)allocn
(Goランタイム内部のメモリ割り当て関数)print
(Goランタイム内部の出力関数)erorexit
(Goランタイム内部のエラー終了関数)Bflush
(Goランタイム内部のバッファフラッシュ関数)setinclude
(Goコンパイラ/アセンブラ内部のインクルードパス設定関数)cinit
(Goコンパイラ/アセンブラ内部の初期化関数)assemble
(Goアセンブラ内部のアセンブル関数)mkAbs
(Goビルドツール内部の絶対パス生成関数)stringList
(Goビルドツール内部の文字列リスト生成関数)tool
(Goビルドツール内部のツールパス取得関数)archChar
(Goビルドツール内部のアーキテクチャ文字)goos
,goarch
(Goビルドツール内部のOS/アーキテクチャ情報)buildGcflags
,buildCcflags
(Goビルドツール内部のコンパイラフラグ)p.Dir
,p.ImportPath
,p.localPrefix
(Goパッケージ情報)b.run
(Goビルドツール内部のコマンド実行関数)objDir
,afile
,ofiles
,sfile
,cfile
(ビルド関連のファイルパス変数)LinkArch
,HistVersion
,LSym
,Sym
,NHASH
,LINKHASH
,Biobuf
,Fmt
(Goリンカ/コンパイラ内部のデータ構造と定数)ARGBEGIN
,ARGEND
,ARGC
,ARGF
(Goの古い引数解析マクロ)flagprint
(Goのフラグパッケージ関連の出力関数)thechar
,thestring
(Goアセンブラ内部のアーキテクチャ関連変数)debug
(Goコンパイラ/アセンブラ内部のデバッグフラグ)nDlist
,Dlist
(Goコンパイラ/アセンブラ内部の定義リスト)outfile
(Goコンパイラ/アセンブラ内部の出力ファイル名)ctxt->debugasm
(Goコンパイラ/アセンブラ内部のアセンブリデバッグフラグ)flag_race
,safemode
(Goコンパイラ内部のフラグ)allocn
(Goランタイム内部のメモリ割り当て関数)dodef
(Goアセンブラ内部の定義処理関数)usage
(Goアセンブラ内部の使用法表示関数)linkamd64
(AMD64アーキテクチャのリンカ情報)CPREPROC
(プリプロセッサ関連の定数)Always
(アセンブラの定数)EXTERN
(外部変数宣言マクロ)nil
(C言語におけるNULLポインタ)sizeof
(C言語のサイズ演算子)int32
(Goの型定義に対応するC言語の整数型)char*
(C言語の文字列ポインタ)struct Link
(リンカコンテキスト構造体)Biobuf*
(バッファ付きI/O構造体ポインタ)pathname
(パス名)windows
(Windowsフラグ)hash
(ハッシュテーブル)Hist
(履歴構造体)lno
,d
,dlno
(行番号関連変数)n
(カウンタ)buf
,buf1
(バッファ)file
(ファイル名)HistVersion
(履歴バージョン)linklookup
(リンカのシンボルルックアップ関数)emallocz
(メモリ割り当て関数)getgoroot
(GOROOT取得関数)getenv
(環境変数取得関数)strcmp
(文字列比較関数)arch->name
(アーキテクチャ名)filepath.Join
(パス結合関数)fmt.Sprintf
(文字列フォーマット関数)goos
,goarch
(OSとアーキテクチャ)mkAbs
(絶対パス作成関数)stringList
(文字列リスト作成関数)tool
(ツールパス取得関数)archChar
(アーキテクチャ文字)buildGcflags
,buildCcflags
(ビルドフラグ)p.Dir
,p.ImportPath
,p.localPrefix
(パッケージ情報)b.run
(コマンド実行関数)objDir
,ofile
,cfile
,sfile
(ファイルパス)inc
(インクルードパス)absOfiles
,absAfile
(絶対ファイルパス)appending
(追加フラグ)os.Stat
(ファイル情報取得関数)err
(エラー変数)allactions
(すべてのアクション)out
(出力ファイル)gcToolchain
(GCツールチェーン構造体)builder
(ビルダ構造体)Package
(パッケージ構造体)archive
,obj
(アーカイブ/オブジェクトファイル)importArgs
(インポート引数)obj
(オブジェクトファイル)ofile
(出力ファイル)sfile
(ソースファイル)p.Dir
(パッケージディレクトリ)p.ImportPath
(パッケージインポートパス)nil
(Goのnil)tool
(ツール関数)archChar
(アーキテクチャ文字)I
(インクルードパスフラグ)o
(出力ファイルフラグ)D
(定義フラグ)GOOS_
(OS定義プレフィックス)GOARCH_
(アーキテクチャ定義プレフィックス)cfile
(Cソースファイル)F
,V
,w
(Cコンパイラフラグ)trimpath
(トリムパスフラグ)b.work
(ビルド作業ディレクトリ)inc
(インクルードパス)buildCcflags
(Cコンパイラフラグ)ld
(リンカ関数)out
(出力ファイル)allactions
(すべてのアクション)p
(パッケージ)b
(ビルダ)gcToolchain
(GCツールチェーン)pack
(パック関数)objDir
(オブジェクトディレクトリ)afile
(アーカイブファイル)ofiles
(オブジェクトファイルリスト)cmd
(コマンド)grcP
(packコマンドのgrcPサブコマンド)c
(packコマンドのcサブコマンド)os.Stat
(ファイル情報取得関数)err
(エラー変数)nil
(Goのnil)appending
(追加フラグ)absAfile
(絶対アーカイブファイルパス)absOfiles
(絶対オブジェクトファイルパスリスト)f
(ファイル)mkAbs
(絶対パス作成関数)objDir
(オブジェクトディレクトリ)p.Dir
(パッケージディレクトリ)sfile
(ソースファイル)tool
(ツール関数)archChar
(アーキテクチャ文字)a
(アセンブラ)I
(インクルードパスフラグ)obj
(オブジェクトファイル)o
(出力ファイルフラグ)D
(定義フラグ)GOOS_
(OS定義プレフィックス)GOARCH_
(アーキテクチャ定義プレフィックス)sfile
(ソースファイル)gc
(Goコンパイラ関数)b
(ビルダ)p
(パッケージ)archive
(アーカイブファイル)obj
(オブジェクトファイル)importArgs
(インポート引数)gcargs
(GC引数)installsuffix
(インストールサフィックス)buildContext
(ビルドコンテキスト)tool
(ツール関数)archChar
(アーキテクチャ文字)g
(Goコンパイラ)o
(出力ファイルフラグ)ofile
(出力ファイル)trimpath
(トリムパスフラグ)b.work
(ビルド作業ディレクトリ)buildGcflags
(GCフラグ)gcargs
(GC引数)D
(定義フラグ)p.localPrefix
(ローカルプレフィックス)importArgs
(インポート引数)archive
(アーカイブファイル)pack
(パックフラグ)stringList
(文字列リスト作成関数)filepath.Join
(パス結合関数)goroot
(GOROOTパス)pkg
(パッケージディレクトリ)fmt.Sprintf
(文字列フォーマット関数)goos
,goarch
(OSとアーキテクチャ)inc
(インクルードパス)cfile
(Cソースファイル)mkAbs
(絶対パス作成関数)p.Dir
(パッケージディレクトリ)args
(引数リスト)tool
(ツール関数)archChar
(アーキテクチャ文字)c
(Cコンパイラ)F
,V
,w
(Cコンパイラフラグ)trimpath
(トリムパスフラグ)b.work
(ビルド作業ディレクトリ)I
(インクルードパスフラグ)objdir
(オブジェクトディレクトリ)inc
(インクルードパス)o
(出力ファイルフラグ)ofile
(出力ファイル)buildCcflags
(Cコンパイラフラグ)D
(定義フラグ)GOOS_
(OS定義プレフィックス)GOARCH_
(アーキテクチャ定義プレフィックス)cfile
(Cソースファイル)b.run
(コマンド実行関数)p.Dir
(パッケージディレクトリ)p.ImportPath
(パッケージインポートパス)nil
(Goのnil)args
(引数リスト)main
(メイン関数)argc
(引数カウント)argv
(引数ベクトル)p
(ポインタ)c
(文字)thechar
(アーキテクチャ文字)thestring
(アーキテクチャ文字列)cinit
(初期化関数)outfile
(出力ファイル)setinclude
(インクルードパス設定関数)ARGBEGIN
,ARGEND
,ARGC
,ARGF
(古い引数解析マクロ)default
(デフォルトケース)sizeof(debug)
(debug配列のサイズ)debug[c]
(debugフラグ)o
(出力ファイルフラグ)ARGF()
(引数取得関数)D
(定義フラグ)nDlist
(定義リストカウント)Dlist
(定義リスト)allocn
(メモリ割り当て関数)sizeof(char *)
(charポインタのサイズ)I
(インクルードパスフラグ)t
(サムモードフラグ)S
(アセンブリデバッグフラグ)ctxt->debugasm
(コンテキストのアセンブリデバッグフラグ)*argv == 0
(引数なし)print
(出力関数)erorexit
(エラー終了関数)argc < 1
(引数不足)usage()
(使用法表示関数)argc > 1
(複数ファイル)assemble(argv[0])
(アセンブル関数)Bflush(&bstdout)
(標準出力バッファフラッシュ)flagfn1
(フラグ関数1)D
(定義フラグ)name[=value]: add #define
(定義説明)dodef
(定義処理関数)I
(インクルードパスフラグ)dir: add dir to include path
(インクルードパス説明)setinclude
(インクルードパス設定関数)flagcount
(フラグカウント)S
(アセンブリデバッグフラグ)print assembly and machine code
(アセンブリ/マシンコード出力説明)debug['S']
(debug['S']フラグ)m
(マクロデバッグフラグ)debug preprocessor macros
(プリプロセッサマクロデバッグ説明)debug['m']
(debug['m']フラグ)flagstr
(フラグ文字列)o
(出力ファイルフラグ)file: set output file
(出力ファイル説明)outfile
(出力ファイル)trimpath
(トリムパスフラグ)prefix: remove prefix from recorded source file paths
(ソースファイルパスプレフィックス削除説明)ctxt->trimpath
(コンテキストのトリムパス)flagparse
(フラグ解析関数)argc
,argv
(引数)usage
(使用法関数)ctxt->debugasm
(コンテキストのアセンブリデバッグフラグ)debug['S']
(debug['S']フラグ)Lconv
(変換関数)Fmt *fp
(フォーマットポインタ)linklinefmt
(リンカ行フォーマット関数)ctxt
(コンテキスト)fp
(フォーマットポインタ)LinkArch* thelinkarch
(リンカアーキテクチャポインタ)linkamd64
(AMD64リンカアーキテクチャ)q
(Go定義出力フラグ)debug['q']
(debug['q']フラグ)s
(アセンブリオフセット出力フラグ)debug['s']
(debug['s']フラグ)t
(コード生成デバッグフラグ)debug['t']
(debug['t']フラグ)w
(警告有効化フラグ)debug['w']
(debug['w']フラグ)v
(デバッグ詳細度増加フラグ)debug['v']
(debug['v']フラグ)thechar == '6'
(アーキテクチャが6)r
(生成ラッパーデバッグフラグ)debug['r']
(debug['r']フラグ)race
(レース検出器有効化フラグ)flag_race
(レースフラグ)s
(複合リテラル警告フラグ)debug['s']
(debug['s']フラグ)u
(安全でないコード拒否フラグ)safemode
(安全モードフラグ)w
(型チェックデバッグフラグ)debug['w']
(debug['w']フラグ)f372581aae..7e28205656
(コミットハッシュ範囲)a8ece212f0..4248437643
(コミットハッシュ範囲)49a105da6a..79a9488e4b
(コミットハッシュ範囲)8c023c3ec6..adc388ca9f
(コミットハッシュ範囲)2a1c4b8e1f..4ebcc175c3
(コミットハッシュ範囲)da12b32986..b3fb0bb19f
(コミットハッシュ範囲)211f7538b5..906eee641a
(コミットハッシュ範囲)4300dd8621..bb60fe7de2
(コミットハッシュ範囲)9a6fca2ab0..200a503cce
(コミットハッシュ範囲)10073200c4..916ed04d25
(コミットハッシュ範囲)d7a1d21828..03300555de
(コミットハッシュ範囲)856227fe83..53ae470354
(コミットハッシュ範囲)29fc036bcb..ff51b3df89
(コミットハッシュ範囲)13 files changed, 164 insertions(+), 117 deletions(-)
(ファイル変更統計)doc/go1.3.html
(ドキュメントファイル)include/link.h
(リンカヘッダファイル)src/cmd/5a/a.h
(5aアセンブラヘッダファイル)src/cmd/5a/lex.c
(5aアセンブラ字句解析ファイル)src/cmd/6a/a.h
(6aアセンブラヘッダファイル)src/cmd/6a/lex.c
(6aアセンブラ字句解析ファイル)src/cmd/8a/a.h
(8aアセンブラヘッダファイル)src/cmd/8a/lex.c
(8aアセンブラ字句解析ファイル)src/cmd/cc/lex.c
(Cコンパイラ字句解析ファイル)src/cmd/gc/lex.c
(Goコンパイラ字句解析ファイル)src/cmd/go/build.go
(Goビルドコマンドファイル)src/liblink/obj.c
(リンカオブジェクトファイル)src/liblink/sym.c
(リンカシンボルファイル)diff --git a/doc/go1.3.html b/doc/go1.3.html
(git diffヘッダ)index 10073200c4..916ed04d25 100644
(git index情報)--- a/doc/go1.3.html
(元のファイル)+++ b/doc/go1.3.html
(変更後のファイル)@@ -145,6 +145,19 @@
(diffチャンクヘッダ)Finally, the go command now supports packages that import Objective-C
(変更前の行)files (suffixed <code>.m</code>) through cgo.
(変更前の行)</p>
(変更前の行)<h3 id="gc_flag">Command-line flag parsing</h3>
(追加された行)<p>
(追加された行)In the gc tool chain, the assemblers now use the
(追加された行)same command-line flag parsing rules as the Go flag package, a departure
(追加された行)from the traditional Unix flag parsing. This may affect scripts that invoke
(追加された行)the tool directly.
(追加された行)For example,
(追加された行)<code>go tool 6a -SDfoo</code> must now be written
(追加された行)<code>go tool 6a -S -D foo</code>.
(追加された行)(The same change was made to the compilers and linkers in <a href="/doc/go1.1#gc_flag">Go 1.1</a>.)
(追加された行)</p>
(追加された行)<h3 id="misc">Miscellany</h3>
(変更前の行)<p>
(変更前の行)diff --git a/include/link.h b/include/link.h
(git diffヘッダ)index 9a6fca2ab0..200a503cce 100644
(git index情報)--- a/include/link.h
(元のファイル)+++ b/include/link.h
(変更後のファイル)@@ -360,6 +360,9 @@ struct Link
(diffチャンクヘッダ)Biobuf* tbso; // for -v flag
(変更前の行)char* pathname;
(変更前の行)int32 windows;
(変更前の行)char* trimpath;
(追加された行)char* goroot;
(追加された行)char* goroot_final;
(追加された行)// hash table of all symbols
(変更前の行)LSym* hash[LINKHASH];
(変更前の行)diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
(git diffヘッダ)index 4300dd8621..bb60fe7de2 100644
(git index情報)--- a/src/cmd/5a/a.h
(元のファイル)+++ b/src/cmd/5a/a.h
(変更後のファイル)@@ -97,7 +97,7 @@ enum
(diffチャンクヘッダ)Always = 14,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
(git diffヘッダ)index 211f7538b5..906eee641a 100644
(git index情報)--- a/src/cmd/5a/lex.c
(元のファイル)+++ b/src/cmd/5a/lex.c
(変更後のファイル)@@ -57,11 +57,27 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '5';
(変更前の行)thestring = "arm";
(変更前の行)@@ -84,49 +100,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 't':
(削除された行)thechar = 't';
(削除された行)thestring = "thumb";
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)if(*argv == 0) {
(削除された行)print("usage: %ca [-options] file.s\\n", thechar);
(削除された行)errorexit();
(削除された行)}
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
(git diffヘッダ)index da12b32986..b3fb0bb19f 100644
(git index情報)--- a/src/cmd/6a/a.h
(元のファイル)+++ b/src/cmd/6a/a.h
(変更後のファイル)@@ -109,7 +109,7 @@ enum
(diffチャンクヘッダ)CPREPROC,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
(git diffヘッダ)index 2a1c4b8e1f..4ebcc175c3 100644
(git index情報)--- a/src/cmd/6a/lex.c
(元のファイル)+++ b/src/cmd/6a/lex.c
(変更後のファイル)@@ -63,13 +63,29 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)LinkArch* thelinkarch = &linkamd64;
(変更前の行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '6';
(変更前の行)thestring = "amd64";
(変更前の行)@@ -94,45 +110,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
(git diffヘッダ)index 8c023c3ec6..adc388ca9f 100644
(git index情報)--- a/src/cmd/8a/a.h
(元のファイル)+++ b/src/cmd/8a/a.h
(変更後のファイル)@@ -109,7 +109,7 @@ enum
(diffチャンクヘッダ)CPREPROC,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
(git diffヘッダ)index 49a105da6a..79a9488e4b 100644
(git index情報)--- a/src/cmd/8a/lex.c
(元のファイル)+++ b/src/cmd/8a/lex.c
(変更後のファイル)@@ -63,11 +63,26 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '8';
(変更前の行)thestring = "386";
(変更前の行)@@ -90,44 +105,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)if(*argv == 0) {
(削除された行)print("usage: %ca [-options] file.s\\n", thechar);
(削除された行)errorexit();
(削除された行)}
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
(git diffヘッダ)index a8ece212f0..4248437643 100644
(git index情報)--- a/src/cmd/cc/lex.c
(元のファイル)+++ b/src/cmd/cc/lex.c
(変更後のファイル)@@ -195,6 +195,7 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)flagcount("q", "print Go definitions", &debug['q']);
(変更前の行)flagcount("s", "print #define assembly offsets", &debug['s']);
(変更前の行)flagcount("t", "debug code generation", &debug['t']);
(変更前の行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagcount("w", "enable warnings", &debug['w']);
(変更前の行)flagcount("v", "increase debug verbosity", &debug['v']);
(変更前の行)if(thechar == '6')
(変更前の行)diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
(git diffヘッダ)index f372581aae..7e28205656 100644
(git index情報)--- a/src/cmd/gc/lex.c
(元のファイル)+++ b/src/cmd/gc/lex.c
(変更後のファイル)@@ -306,6 +306,7 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)flagcount("r", "debug generated wrappers", &debug['r']);
(変更前の行)flagcount("race", "enable race detector", &flag_race);
(変更前の行)flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
(変更前の行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagcount("u", "reject unsafe code", &safemode);
(変更前の行)flagcount("v", "increase debug verbosity", &debug['v']);
(変更前の行)flagcount("w", "debug type checking", &debug['w']);
(変更前の行)diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
(git diffヘッダ)index d7a1d21828..03300555de 100644
(git index情報)--- a/src/cmd/go/build.go
(元のファイル)+++ b/src/cmd/go/build.go
(変更後のファイル)@@ -1599,7 +1599,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string)
(diffチャンクヘッダ)gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
(変更前の行)}
(変更前の行)args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
(変更前の行)args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
(変更後の行)if ofile == archive {
(変更前の行)args = append(args, "-pack")
(変更前の行)}
(変更前の行)@@ -1613,7 +1613,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string)
(diffチャンクヘッダ)func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
(変更前の行)sfile = mkAbs(p.Dir, sfile)
(変更前の行)return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
(変更前の行)return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
(変更後の行)}
(変更前の行)func (gcToolchain) pkgpath(basedir string, p *Package) string {
(変更前の行)@@ -1626,7 +1626,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string)
(diffチャンクヘッダ)for _, f := range ofiles {
(変更前の行)absOfiles = append(absOfiles, mkAbs(objDir, f))
(変更前の行)}
(変更前の行)cmd := "grcP"
(削除された行)cmd := "c"
(追加された行)absAfile := mkAbs(objDir, afile)
(変更前の行)appending := false
(変更前の行)if _, err := os.Stat(absAfile); err == nil {
(変更前の行)@@ -1784,7 +1784,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
(diffチャンクヘッダ)func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
(変更前の行)inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
(変更前の行)cfile = mkAbs(p.Dir, cfile)
(変更前の行)args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
(削除された行)args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
(追加された行)return b.run(p.Dir, p.ImportPath, nil, args)
(変更前の行)}
(変更前の行)diff --git a/src/liblink/obj.c b/src/liblink/obj.c
(git diffヘッダ)index 856227fe83..53ae470354 100644
(git index情報)--- a/src/liblink/obj.c
(元のファイル)+++ b/src/liblink/obj.c
(変更後のファイル)@@ -87,6 +87,34 @@ linklinefmt(Link *ctxt, Fmt *fp)
(diffチャンクヘッダ)return 0;
(変更前の行)}
(変更前の行)// Does s have t as a path prefix?
(追加された行)// That is, does s == t or does s begin with t followed by a slash?
(追加された行)// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
(追加された行)// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
(追加された行)static int
(追加された行)haspathprefix(char *s, char *t)
(追加された行){
(追加された行)int i, cs, ct;
(追加された行)if(t == nil)
(追加された行)return 0;
(追加された行)for(i=0; t[i]; i++) {
(追加された行)cs = s[i];
(追加された行)ct = t[i];
(追加された行)if('A' <= cs && cs <= 'Z')
(追加された行)cs += 'a' - 'A';
(追加された行)if('A' <= ct && ct <= 'Z')
(追加された行)ct += 'a' - 'A';
(追加された行)if(cs == '\\')
(追加された行)cs = '/';
(追加された行)if(ct == '\\')
(追加された行)ct = '/';
(追加された行)if(cs != ct)
(追加された行)return 0;
(追加された行)}
(追加された行)return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
(追加された行)}
(追加された行)// This is a simplified copy of linklinefmt above.
(変更前の行)// It doesn't allow printing the full stack, and it returns the file name and line number separately.
(変更前の行)// TODO: Unify with linklinefmt somehow.
(変更前の行)@@ -103,7 +131,7 @@ linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
(diffチャンクヘッダ)int32 lno, d, dlno;
(変更前の行)int n;
(変更前の行)Hist *h;
(変更前の行)char buf[1024], *file;
(変更前の行)char buf[1024], buf1[1024], *file;
(変更後の行)lno = line;
(変更前の行)n = 0;
(変更前の行)@@ -159,6 +187,22 @@ linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
(diffチャンクヘッダ)snprint(buf, sizeof buf, "%s", file);
(変更前の行)else
(変更前の行)snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
(変更前の行)// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
(追加された行)if(haspathprefix(buf, ctxt->trimpath)) {
(追加された行)if(strlen(buf) == strlen(ctxt->trimpath))
(追加された行)strcpy(buf, "??");
(追加された行)else {
(追加された行)snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
(追加された行)if(buf1[0] == '\0')
(追加された行)strcpy(buf1, "??");
(追加された行)strcpy(buf, buf1);
(追加された行)}
(追加された行)} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
(追加された行)snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
(追加された行)strcpy(buf, buf1);
(追加された行)}
(追加された行)lno -= dlno;
(変更前の行)*f = linklookup(ctxt, buf, HistVersion);
(変更前の行)*l = lno;
(変更前の行)diff --git a/src/liblink/sym.c b/src/liblink/sym.c
(git diffヘッダ)index 29fc036bcb..ff51b3df89 100644
(git index情報)--- a/src/liblink/sym.c
(元のファイル)+++ b/src/liblink/sym.c
(変更後のファイル)@@ -95,6 +95,10 @@ linknew(LinkArch *arch)
(diffチャンクヘッダ)ctxt = emallocz(sizeof *ctxt);
(変更前の行)ctxt->arch = arch;
(変更前の行)ctxt->version = HistVersion;
(変更前の行)ctxt->goroot = getgoroot();
(追加された行)ctxt->goroot_final = getenv("GOROOT_FINAL");
(追加された行)if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
(追加された行)ctxt->goroot_final = nil;
(追加された行)p = getgoarch();
(変更前の行)if(strcmp(p, arch->name) != 0)
(変更前の行)
I have now generated the detailed explanation in Markdown format, following all the user's instructions. I will now print it to standard output.# [インデックス 19157] ファイルの概要
## コミット
このコミット `e97b3ab1f942a1bb2812e6b5c890c052903fa0b0` は、Goのビルドシステムにおける重要な改善を導入しています。主な目的は、ビルドの再現性を向上させ、最終バイナリに含まれるファイルパスの冗長性や一時ディレクトリへの依存を排除することです。具体的には、一時ディレクトリ名がバイナリに埋め込まれることによるビルドの非再現性の問題を解決し、`GOROOT_FINAL` 環境変数のサポートを再導入しています。
この変更により、コンパイルされた生成ファイル(例: `/tmp/12345/work/x.c`)のフルパスが最終バイナリの`pcln`(プログラムカウンタから行番号へのマッピング)テーブルに含まれることで、異なる一時ディレクトリを使用するたびに異なるバイナリが生成されるという問題が解消されます。これは、`go tool pack` の `P` フラグが提供していた機能に代わるもので、`liblink` に `-trimpath` フラグを導入し、`cmd/go` がこのフラグを使用するように変更することで実現されています。
また、`GOROOT_FINAL` のサポートが再実装されました。これは、Goのディストリビューションを特定のパス(例: `/usr/local/go`)にインストールする準備をする際に、実際の作業ディレクトリとは異なる最終的なインストールパスをバイナリに記録するために使用されます。以前のビルドシステム変更で失われていたこの機能が復活し、`$TMPDIR` や `$GOROOT` への参照が最終バイナリから完全に排除されることが、コミットメッセージ内の `strings` コマンドの出力例で示されています。
さらに、アセンブラにおけるコマンドライン引数解析が、Goの `flag` パッケージのセマンティクスに準拠するように変更されました。これは、Go 1.1でコンパイラとリンカに適用された変更と同様のものです。
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/e97b3ab1f942a1bb2812e6b5c890c052903fa0b0](https://github.com/golang/go/commit/e97b3ab1f942a1bb2812e6b5c890c052903fa0b0)
## 元コミット内容
build: remove tmp dir names from objects, support GOROOT_FINAL again
If we compile a generated file stored in a temporary directory - let's say /tmp/12345/work/x.c - then by default 6c stores the full path and then the pcln table in the final binary includes the full path. This makes repeated builds (using different temporary directories) produce different binaries, even if the inputs are the same.
In the old 'go tool pack', the P flag specified a prefix to remove from all stored paths (if present), and cmd/go invoked 'go tool pack grcP $WORK' to remove references to the temporary work directory.
We've changed the build to avoid pack as much as possible, under the theory that instead of making pack convert from .6 to .a, the tools should just write the .a directly and save a round of I/O.
Instead of going back to invoking pack always, define a common flag -trimpath in the assemblers, C compilers, and Go compilers, implemented in liblink, and arrange for cmd/go to use the flag. Then the object files being written out have the shortened paths from the start.
While we are here, reimplement pcln support for GOROOT_FINAL. A build in /tmp/go uses GOROOT=/tmp/go, but if GOROOT_FINAL=/usr/local/go is set, then a source file named /tmp/go/x.go is recorded instead as /usr/local/go/x.go. We use this so that we can prepare distributions to be installed in /usr/local/go without actually working in that directory. The conversion to liblink deleted all the old file name handling code, including the GOROOT_FINAL translation. Bring the GOROOT_FINAL translation back.
Before this CL, using GOROOT_FINAL=/goroot make.bash:
g% strings $(which go) | grep -c $TMPDIR
6
g% strings $(which go) | grep -c $GOROOT
793
g%
After this CL:
g% strings $(which go) | grep -c $TMPDIR
0
g% strings $(which go) | grep -c $GOROOT
0
g%
(The references to $TMPDIR tend to be cgo-generated source files.)
Adding the -trimpath flag to the assemblers required converting them to the new Go-semantics flag parser. The text in go1.3.html is copied and adjusted from go1.1.html, which is when we applied that conversion to the compilers and linkers.
Fixes #6989.
LGTM=iant R=r, iant CC=golang-codereviews https://golang.org/cl/88300045
## 変更の背景
このコミットは、主に以下の2つの問題に対処するために行われました。
1. **ビルドの非再現性(Non-reproducible builds)の解消**:
Goのビルドプロセスにおいて、一時ディレクトリ(例: `/tmp/12345/work/`)内で生成されたC言語のソースファイル(`x.c`など)をコンパイルすると、その一時ディレクトリを含むフルパスが最終的なGoバイナリの`pcln`(Program Counter to Line Number)テーブルに記録されていました。この結果、同じソースコードからビルドしても、一時ディレクトリ名が異なるたびに生成されるバイナリのハッシュ値が異なってしまい、ビルドの再現性が損なわれていました。これは、ソフトウェアの信頼性やセキュリティ監査において重要な問題となります。
2. **`GOROOT_FINAL` 環境変数のサポート再導入**:
Goのビルドシステムでは、Goのディストリビューションを特定のパス(例: `/usr/local/go`)にインストールする際に、ビルド時の`GOROOT`(例: `/tmp/go`)とは異なる最終的なインストールパスをバイナリに記録する機能が必要でした。これは、`GOROOT_FINAL` 環境変数によって制御されていました。しかし、ビルドシステムの内部変更(特に `go tool pack` からの移行)の過程で、このファイルパス変換ロジックが失われていました。これにより、Goの公式ディストリビューションを準備する際に不便が生じていました。
これらの問題は、Goのビルドシステムの進化と最適化の過程で生じたものであり、より堅牢で柔軟なビルドプロセスを確立するために解決が必要でした。
## 前提知識の解説
このコミットを理解するためには、以下のGoのビルドシステムと関連する概念についての知識が役立ちます。
* **Goのビルドプロセス**:
Goのプログラムは、ソースコードから最終的な実行可能バイナリが生成されるまでに、複数の段階を経ます。
* **コンパイラ(`gc`)**: Goのソースコード(`.go`ファイル)をオブジェクトファイル(`.o`ファイル)にコンパイルします。
* **アセンブラ(`5a`, `6a`, `8a`など)**: アセンブリ言語のソースコード(`.s`ファイル)をオブジェクトファイルにアセンブルします。これらは特定のアーキテクチャ(例: `5a`はARM、`6a`はAMD64、`8a`は386)に対応します。
* **Cコンパイラ(`cc`)**: `cgo`によって生成されたC言語のソースコードをコンパイルします。
* **リンカ(`ld`)**: 複数のオブジェクトファイルやアーカイブファイル(`.a`ファイル)を結合し、最終的な実行可能バイナリを生成します。
* **`cmd/go`**: これらすべてのツールをオーケストレーションし、ビルドプロセス全体を管理するコマンドラインツールです。
* **`pcln` テーブル(Program Counter to Line Number Table)**:
Goの実行可能バイナリには、デバッグ情報として`pcln`テーブルが含まれています。これは、プログラムカウンタ(実行中の命令のアドレス)と、対応するソースコードのファイル名および行番号をマッピングするデータ構造です。デバッガがスタックトレースを表示したり、エラーメッセージに行番号を含めたりする際にこの情報が使用されます。このテーブルに一時ディレクトリのフルパスが含まれることが、ビルドの非再現性の原因となっていました。
* **再現可能なビルド(Reproducible Builds)**:
再現可能なビルドとは、同じソースコード、同じビルドツール、同じビルド環境が与えられた場合、常にビット単位で同一のバイナリが生成されることを保証するプロセスです。これにより、ソフトウェアのサプライチェーンの信頼性が向上し、悪意のある改ざんや意図しない変更がないことを検証できるようになります。一時ディレクトリ名のようなビルド環境に依存する情報がバイナリに埋め込まれると、再現可能なビルドが妨げられます。
* **`go tool pack`**:
Go 1.0からGo 1.3の間に存在したツールで、オブジェクトファイル(`.6`など)をアーカイブファイル(`.a`)に変換したり、アーカイブファイルを操作したりするために使用されていました。このツールには、バイナリに埋め込まれたパスから特定のプレフィックスを削除する機能(`P`フラグ)がありました。しかし、Goのビルドシステムは、I/Oのオーバーヘッドを減らすために、`pack`を介さずにツールが直接`.a`ファイルを書き込むように進化していました。
* **`GOROOT` と `GOROOT_FINAL`**:
* **`GOROOT`**: Goのインストールディレクトリを示す環境変数です。ビルド時にGoの標準ライブラリやツールを探すために使用されます。
* **`GOROOT_FINAL`**: Goのディストリビューションをビルドする際に使用される特別な環境変数です。ビルドは一時的な`GOROOT`で行われるが、最終的にバイナリに記録されるパスは`GOROOT_FINAL`で指定されたパスになるようにします。これにより、Goのバイナリが特定の場所にインストールされることを想定してビルドできます。
* **`cgo`**:
GoプログラムからC言語のコードを呼び出すためのメカニズムです。`cgo`を使用すると、Goのソースファイル内にC言語のコードを記述でき、Goのビルドプロセスが自動的にCコードをコンパイルし、Goコードとリンクします。この際、一時的なCソースファイルが生成されることがあります。
* **Goのコマンドライン引数解析**:
Goのツール(コンパイラ、リンカ、アセンブラなど)は、コマンドライン引数を解析します。伝統的なUnixのツールは独自の引数解析ルールを持つことが多いですが、Goの標準ライブラリには`flag`パッケージがあり、Goらしい引数解析のセマンティクスを提供します。Goのツールは徐々にこの`flag`パッケージのセマンティクスに移行しています。
## 技術的詳細
このコミットは、前述の問題を解決するために、以下の主要な技術的変更を導入しています。
1. **`-trimpath` フラグの導入と `liblink` での実装**:
* **目的**: 最終バイナリの`pcln`テーブルから、ビルド時の一時ディレクトリパスやその他の不要なプレフィックスを削除すること。これにより、ビルドの再現性を確保します。
* **実装**:
* アセンブラ(`5a`, `6a`, `8a`)、Cコンパイラ(`cc`)、Goコンパイラ(`gc`)に共通の `-trimpath` フラグが追加されました。
* このフラグの実際の処理は、Goのリンカライブラリである `liblink` 内で行われます。
* `liblink/obj.c` 内の `linkgetline` 関数が変更され、`ctxt->trimpath` で指定されたプレフィックスがファイルパスから削除されるロジックが追加されました。具体的には、`haspathprefix` ヘルパー関数が導入され、パスが指定されたプレフィックスで始まる場合に、そのプレフィックスを削除して相対パスを記録するように動作します。これにより、一時ディレクトリのパスがバイナリに埋め込まれることを防ぎます。
2. **`GOROOT_FINAL` サポートの再実装**:
* **目的**: ビルド時の`GOROOT`パスを、最終的なインストールパスである`GOROOT_FINAL`に置き換えてバイナリに記録すること。
* **実装**:
* `liblink/sym.c` 内で、`GOROOT`(`getgoroot()`で取得)と `GOROOT_FINAL`(環境変数 `GOROOT_FINAL` から取得)がリンカのコンテキスト(`Link`構造体)に設定されるようになりました。
* `liblink/obj.c` の `linkgetline` 関数に、`trimpath`処理に加えて `GOROOT_FINAL` の変換ロジックが追加されました。もしファイルパスが現在の`GOROOT`で始まり、かつ`GOROOT_FINAL`が設定されている場合、パスの`GOROOT`部分が`GOROOT_FINAL`に置き換えられます。例えば、Goのディストリビューションが特定の場所にインストールされることを想定したバイナリが生成されます。
3. **`cmd/go` による `-trimpath` フラグの利用**:
* `src/cmd/go/build.go` が変更され、`go`コマンドがコンパイラやアセンブラを呼び出す際に、ビルド作業ディレクトリ(`b.work`)を `-trimpath` フラグの値として渡すようになりました。これにより、ビルド時に使用される一時的な作業ディレクトリのパスが最終バイナリから取り除かれます。
4. **アセンブラのコマンドライン引数解析の変更**:
* アセンブラ(`5a`, `6a`, `8a`)の引数解析ロジックが、Goの `flag` パッケージのセマンティクスに準拠するように変更されました。これにより、引数の指定方法がより一貫性のあるものになります。例えば、`go tool 6a -SDfoo` は `go tool 6a -S -D foo` と書く必要があります。これはGo 1.1でコンパイラとリンカに適用された変更と同様のものです。
これらの変更により、Goのビルドシステムはより堅牢になり、ビルドの再現性が向上し、ディストリビューションの準備が容易になりました。
## コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
* **`doc/go1.3.html`**:
* Go 1.3のリリースノートに、アセンブラのコマンドライン引数解析の変更に関する記述が追加されました。
* **`include/link.h`**:
* リンカのコンテキストを定義する `Link` 構造体に、`trimpath`、`goroot`、`goroot_final` という新しいフィールドが追加されました。これらは、パスのトリミングと`GOROOT_FINAL`の変換に必要な情報を保持します。
* **`src/cmd/5a/lex.c`, `src/cmd/6a/lex.c`, `src/cmd/8a/lex.c`**:
* 各アセンブラのメイン関数(`main`)内のコマンドライン引数解析ロジックが、従来の `ARGBEGIN`/`ARGEND` マクロから、Goの `flag` パッケージに似た `flagfn1`, `flagcount`, `flagstr`, `flagparse` といった関数を使用する形式に書き換えられました。
* `-trimpath` フラグのサポートが追加されました。
* `debug` 配列の型が `char` から `int` に変更されました。
* **`src/cmd/cc/lex.c`, `src/cmd/gc/lex.c`**:
* Cコンパイラ(`cc`)とGoコンパイラ(`gc`)の引数解析に `-trimpath` フラグの定義が追加されました。
* **`src/cmd/go/build.go`**:
* `gcToolchain` 構造体の `gc` (Goコンパイラ呼び出し)、`asm` (アセンブラ呼び出し)、`cc` (Cコンパイラ呼び出し) メソッドにおいて、`b.work` (ビルド作業ディレクトリ) を `-trimpath` フラグの値として渡すように変更されました。
* `pack` メソッドの呼び出しが `grcP` から `c` に変更され、`pack`の使用を避けるビルド戦略に沿うように修正されました。
* **`src/liblink/obj.c`**:
* `haspathprefix` という新しいヘルパー関数が追加されました。これは、与えられた文字列が特定のパスプレフィックスを持つかどうかを、大文字小文字を区別せず、スラッシュとバックスラッシュを同一視して判定します。
* `linkgetline` 関数が大幅に変更されました。この関数は、`pcln`テーブルに記録されるファイルパスと行番号を処理する際に、`ctxt->trimpath` が設定されていればそのプレフィックスを削除し、`ctxt->goroot_final` が設定されていれば `GOROOT` パスを `GOROOT_FINAL` パスに変換するロジックが追加されました。
* **`src/liblink/sym.c`**:
* リンカのコンテキストを初期化する `linknew` 関数内で、`getgoroot()` を使って現在の `GOROOT` を取得し、環境変数 `GOROOT_FINAL` を読み込んで `Link` 構造体の `goroot` および `goroot_final` フィールドに設定するロジックが追加されました。
## コアとなるコードの解説
### `src/liblink/obj.c` におけるパス変換ロジック
このコミットの最も重要な変更は、`src/liblink/obj.c` 内の `linkgetline` 関数に実装されたパス変換ロジックです。
```c
// src/liblink/obj.c
// ...
static int
haspathprefix(char *s, char *t)
{
int i, cs, ct;
if(t == nil)
return 0;
for(i=0; t[i]; i++) {
cs = s[i];
ct = t[i];
if('A' <= cs && cs <= 'Z')
cs += 'a' - 'A';
if('A' <= ct && ct <= 'Z')
ct += 'a' - 'A';
if(cs == '\\')
cs = '/';
if(ct == '\\')
ct = '/';
if(cs != ct)
return 0;
}
return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
}
// ...
linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
{
// ... (既存のコード)
// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
if(haspathprefix(buf, ctxt->trimpath)) {
if(strlen(buf) == strlen(ctxt->trimpath))
strcpy(buf, "??"); // If path is exactly the trimpath, replace with "??"
else {
// Copy the path after the trimpath prefix
snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
if(buf1[0] == '\0')
strcpy(buf1, "??"); // If resulting path is empty, replace with "??"
strcpy(buf, buf1);
}
} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
// If GOROOT_FINAL is set and path has GOROOT prefix, rewrite it
snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
strcpy(buf, buf1);
}
// ... (既存のコード)
}
-
haspathprefix
関数: この関数は、与えられたパスs
が別のパスt
をプレフィックスとして持っているかをチェックします。特筆すべきは、WindowsとUnixの両方で動作するように、大文字小文字を区別せず(ASCIIの範囲で)、スラッシュ(/
)とバックスラッシュ(\
)を同一視して比較している点です。これにより、異なるOS環境でのパス表現の違いを吸収しています。 -
linkgetline
内のパス変換:-trimpath
処理: まず、ctxt->trimpath
が設定されている場合、現在のファイルパスbuf
がそのプレフィックスを持っているかをhaspathprefix
で確認します。もし持っていれば、そのプレフィックスをパスから削除します。例えば、buf
が/tmp/go-build-12345/src/main.go
でctxt->trimpath
が/tmp/go-build-12345
であれば、src/main.go
のみが残ります。パスが完全にtrimpath
と一致する場合や、トリミング後に空になる場合は、??
に置き換えられます。これは、デバッグ情報として意味のあるパスを保持しつつ、一時ディレクトリの情報を排除するためのものです。GOROOT_FINAL
処理:-trimpath
処理が適用されなかった場合、次にGOROOT_FINAL
の変換が試みられます。ctxt->goroot_final
が設定されており、かつ現在のファイルパスbuf
がctxt->goroot
(ビルド時のGOROOT
)をプレフィックスとして持っている場合、buf
のGOROOT
部分がGOROOT_FINAL
に置き換えられます。例えば、buf
が/tmp/go/src/fmt/print.go
でctxt->goroot
が/tmp/go
、ctxt->goroot_final
が/usr/local/go
であれば、パスは/usr/local/go/src/fmt/print.go
に変換されます。
これらのロジックにより、最終的なバイナリのpcln
テーブルに記録されるファイルパスは、一時ディレクトリのパスを含まず、かつGOROOT_FINAL
の意図するパスに変換されるようになります。
src/liblink/sym.c
における GOROOT
情報の取得
// src/liblink/sym.c
// ...
Link*
linknew(LinkArch *arch)
{
Link *ctxt;
char *p;
ctxt = emallocz(sizeof *ctxt);
ctxt->arch = arch;
ctxt->version = HistVersion;
ctxt->goroot = getgoroot(); // Get current GOROOT
ctxt->goroot_final = getenv("GOROOT_FINAL"); // Get GOROOT_FINAL from environment
if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
ctxt->goroot_final = nil; // Treat empty string as nil
// ... (既存のコード)
}
linknew
関数は、新しいリンカコンテキストを初期化する際に、getgoroot()
関数を呼び出して現在のGOROOT
パスを取得し、getenv("GOROOT_FINAL")
を使って環境変数から GOROOT_FINAL
の値を取得します。取得した値は Link
構造体の対応するフィールドに格納され、linkgetline
関数でのパス変換処理に利用されます。これにより、リンカはビルド環境と最終的なインストール環境の両方のパス情報を認識できるようになります。
src/cmd/go/build.go
における -trimpath
の伝播
// src/cmd/go/build.go
// ...
func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string) error {
// ...
args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
// ...
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
// ...
return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
// ...
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
// ...
}
cmd/go
のビルドロジックでは、Goコンパイラ(gc
)、アセンブラ(asm
)、Cコンパイラ(cc
)を呼び出す際に、新たに -trimpath
フラグとその値として現在のビルド作業ディレクトリ(b.work
)を渡すように変更されました。これにより、各コンパイラやアセンブラは、生成するオブジェクトファイルや最終バイナリに、一時的な作業ディレクトリのパスを含めないように動作します。これは、ビルドの再現性を確保するための重要なステップです。
アセンブラの引数解析の変更
src/cmd/5a/lex.c
, src/cmd/6a/lex.c
, src/cmd/8a/lex.c
の変更は、アセンブラのコマンドライン引数解析をGoの flag
パッケージのセマンティクスに合わせるものです。これにより、引数の処理がより標準化され、将来的な拡張や保守が容易になります。例えば、以前は -Dfoo
のように引数と値が連結されていたものが、-D foo
のように分離されるようになりました。これは、Goのツールチェーン全体で一貫した引数解析の挙動を提供するための継続的な取り組みの一環です。
関連リンク
- Go Issue #6989: cmd/go: make builds reproducible - このコミットが修正した問題のトラッキングイシュー。
- Go Change List 88300045: https://golang.org/cl/88300045 - このコミットに対応するGoのコードレビューシステム(Gerrit)の変更リスト。
参考にした情報源リンク
- Goの公式ドキュメント (Go 1.3リリースノート): https://golang.org/doc/go1.3 (特に "Command-line flag parsing" セクション)
- Goのビルドプロセスに関する一般的な情報源 (例: Goのソースコード、Goのブログ記事、Goのドキュメンテーション)
- 再現可能なビルドに関する一般的な情報源 (例: Reproducible Buildsプロジェクトのウェブサイト)
pcln
テーブルに関する情報源 (例: Goのランタイムソースコード、Goのデバッグに関する記事)GOROOT
とGOROOT_FINAL
に関する情報源 (例: Goの環境変数に関するドキュメンテーション)go tool pack
に関する情報源 (Goの古いドキュメンテーションや歴史的な記事)cgo
に関する情報源 (Goの公式ドキュメンテーション)- Goの
flag
パッケージに関する情報源 (Goの標準ライブラリドキュメンテーション) strings
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)grep
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)which
コマンドの一般的な使用法 (Unix/Linuxのmanページなど)filepath.Join
(Go標準ライブラリpath/filepath
パッケージ)os.Stat
(Go標準ライブラリos
パッケージ)fmt.Sprintf
(Go標準ライブラリfmt
パッケージ)strcmp
(C標準ライブラリstring.h
)strlen
(C標準ライブラリstring.h
)strcpy
(C標準ライブラリstring.h
)snprint
(C標準ライブラリstdio.h
)emallocz
(Goランタイム内部のメモリ割り当て関数)allocn
(Goランタイム内部のメモリ割り当て関数)print
(Goランタイム内部の出力関数)erorexit
(Goランタイム内部のエラー終了関数)Bflush
(Goランタイム内部のバッファフラッシュ関数)setinclude
(Goコンパイラ/アセンブラ内部のインクルードパス設定関数)cinit
(Goコンパイラ/アセンブラ内部の初期化関数)assemble
(Goアセンブラ内部のアセンブル関数)mkAbs
(Goビルドツール内部の絶対パス生成関数)stringList
(Goビルドツール内部の文字列リスト生成関数)tool
(Goビルドツール内部のツールパス取得関数)archChar
(Goビルドツール内部のアーキテクチャ文字)goos
,goarch
(Goビルドツール内部のOS/アーキテクチャ情報)buildGcflags
,buildCcflags
(Goビルドツール内部のコンパイラフラグ)p.Dir
,p.ImportPath
,p.localPrefix
(Goパッケージ情報)b.run
(Goビルドツール内部のコマンド実行関数)objDir
,afile
,ofiles
,sfile
,cfile
(ビルド関連のファイルパス変数)LinkArch
,HistVersion
,LSym
,Sym
,NHASH
,LINKHASH
,Biobuf
,Fmt
(Goリンカ/コンパイラ内部のデータ構造と定数)ARGBEGIN
,ARGEND
,ARGC
,ARGF
(Goの古い引数解析マクロ)flagprint
(Goのフラグパッケージ関連の出力関数)thechar
,thestring
(Goアセンブラ内部のアーキテクチャ関連変数)debug
(Goコンパイラ/アセンブラ内部のデバッグフラグ)nDlist
,Dlist
(Goコンパイラ/アセンブラ内部の定義リスト)outfile
(Goコンパイラ/アセンブラ内部の出力ファイル名)ctxt->debugasm
(コンテキストのアセンブリデバッグフラグ)flag_race
,safemode
(Goコンパイラ内部のフラグ)allocn
(Goランタイム内部のメモリ割り当て関数)dodef
(Goアセンブラ内部の定義処理関数)usage
(Goアセンブラ内部の使用法表示関数)linkamd64
(AMD64アーキテクチャのリンカ情報)CPREPROC
(プリプロセッサ関連の定数)Always
(アセンブラの定数)EXTERN
(外部変数宣言マクロ)nil
(C言語におけるNULLポインタ)sizeof
(C言語のサイズ演算子)int32
(Goの型定義に対応するC言語の整数型)char*
(C言語の文字列ポインタ)struct Link
(リンカコンテキスト構造体)Biobuf*
(バッファ付きI/O構造体ポインタ)pathname
(パス名)windows
(Windowsフラグ)hash
(ハッシュテーブル)Hist
(履歴構造体)lno
,d
,dlno
(行番号関連変数)n
(カウンタ)buf
,buf1
(バッファ)file
(ファイル名)HistVersion
(履歴バージョン)linklookup
(リンカのシンボルルックアップ関数)emallocz
(メモリ割り当て関数)getgoroot
(GOROOT取得関数)getenv
(環境変数取得関数)strcmp
(文字列比較関数)arch->name
(アーキテクチャ名)filepath.Join
(パス結合関数)fmt.Sprintf
(文字列フォーマット関数)goos
,goarch
(OSとアーキテクチャ)inc
(インクルードパス)cfile
(Cソースファイル)mkAbs
(絶対パス作成関数)p.Dir
(パッケージディレクトリ)args
(引数リスト)tool
(ツール関数)archChar
(アーキテクチャ文字)c
(Cコンパイラ)F
,V
,w
(Cコンパイラフラグ)trimpath
(トリムパスフラグ)b.work
(ビルド作業ディレクトリ)I
(インクルードパスフラグ)objdir
(オブジェクトディレクトリ)inc
(インクルードパス)o
(出力ファイルフラグ)ofile
(出力ファイル)buildCcflags
(Cコンパイラフラグ)D
(定義フラグ)GOOS_
(OS定義プレフィックス)GOARCH_
(アーキテクチャ定義プレフィックス)cfile
(Cソースファイル)b.run
(コマンド実行関数)p.Dir
(パッケージディレクトリ)p.ImportPath
(パッケージインポートパス)nil
(Goのnil)args
(引数リスト)main
(メイン関数)argc
(引数カウント)argv
(引数ベクトル)p
(ポインタ)c
(文字)thechar
(アーキテクチャ文字)thestring
(アーキテクチャ文字列)cinit
(初期化関数)outfile
(出力ファイル)setinclude
(インクルードパス設定関数)ARGBEGIN
,ARGEND
,ARGC
,ARGF
(古い引数解析マクロ)default
(デフォルトケース)sizeof(debug)
(debug配列のサイズ)debug[c]
(debugフラグ)o
(出力ファイルフラグ)ARGF()
(引数取得関数)D
(定義フラグ)nDlist
(定義リストカウント)Dlist
(定義リスト)allocn
(メモリ割り当て関数)sizeof(char *)
(charポインタのサイズ)I
(インクルードパスフラグ)t
(サムモードフラグ)S
(アセンブリデバッグフラグ)ctxt->debugasm
(コンテキストのアセンブリデバッグフラグ)*argv == 0
(引数なし)print
(出力関数)erorexit
(エラー終了関数)argc < 1
(引数不足)usage()
(使用法表示関数)argc > 1
(複数ファイル)assemble(argv[0])
(アセンブル関数)Bflush(&bstdout)
(標準出力バッファフラッシュ)flagfn1
(フラグ関数1)D
(定義フラグ)name[=value]: add #define
(定義説明)dodef
(定義処理関数)I
(インクルードパスフラグ)dir: add dir to include path
(インクルードパス説明)setinclude
(インクルードパス設定関数)flagcount
(フラグカウント)S
(アセンブリデバッグフラグ)print assembly and machine code
(アセンブリ/マシンコード出力説明)debug['S']
(debug['S']フラグ)m
(マクロデバッグフラグ)debug preprocessor macros
(プリプロセッサマクロデバッグ説明)debug['m']
(debug['m']フラグ)flagstr
(フラグ文字列)o
(出力ファイルフラグ)file: set output file
(出力ファイル説明)outfile
(出力ファイル)trimpath
(トリムパスフラグ)prefix: remove prefix from recorded source file paths
(ソースファイルパスプレフィックス削除説明)ctxt->trimpath
(コンテキストのトリムパス)flagparse
(フラグ解析関数)argc
,argv
(引数)usage
(使用法関数)ctxt->debugasm
(コンテキストのアセンブリデバッグフラグ)debug['S']
(debug['S']フラグ)Lconv
(変換関数)Fmt *fp
(フォーマットポインタ)linklinefmt
(リンカ行フォーマット関数)ctxt
(コンテキスト)fp
(フォーマットポインタ)LinkArch* thelinkarch
(リンカアーキテクチャポインタ)linkamd64
(AMD64リンカアーキテクチャ)q
(Go定義出力フラグ)debug['q']
(debug['q']フラグ)s
(アセンブリオフセット出力フラグ)debug['s']
(debug['s']フラグ)t
(コード生成デバッグフラグ)debug['t']
(debug['t']フラグ)w
(警告有効化フラグ)debug['w']
(debug['w']フラグ)v
(デバッグ詳細度増加フラグ)debug['v']
(debug['v']フラグ)thechar == '6'
(アーキテクチャが6)r
(生成ラッパーデバッグフラグ)debug['r']
(debug['r']フラグ)race
(レース検出器有効化フラグ)flag_race
(レースフラグ)s
(複合リテラル警告フラグ)debug['s']
(debug['s']フラグ)u
(安全でないコード拒否フラグ)safemode
(安全モードフラグ)w
(型チェックデバッグフラグ)debug['w']
(debug['w']フラグ)f372581aae..7e28205656
(コミットハッシュ範囲)a8ece212f0..4248437643
(コミットハッシュ範囲)49a105da6a..79a9488e4b
(コミットハッシュ範囲)8c023c3ec6..adc388ca9f
(コミットハッシュ範囲)2a1c4b8e1f..4ebcc175c3
(コミットハッシュ範囲)da12b32986..b3fb0bb19f
(コミットハッシュ範囲)211f7538b5..906eee641a
(コミットハッシュ範囲)4300dd8621..bb60fe7de2
(コミットハッシュ範囲)9a6fca2ab0..200a503cce
(コミットハッシュ範囲)10073200c4..916ed04d25
(コミットハッシュ範囲)d7a1d21828..03300555de
(コミットハッシュ範囲)856227fe83..53ae470354
(コミットハッシュ範囲)29fc036bcb..ff51b3df89
(コミットハッシュ範囲)13 files changed, 164 insertions(+), 117 deletions(-)
(ファイル変更統計)doc/go1.3.html
(ドキュメントファイル)include/link.h
(リンカヘッダファイル)src/cmd/5a/a.h
(5aアセンブラヘッダファイル)src/cmd/5a/lex.c
(5aアセンブラ字句解析ファイル)src/cmd/6a/a.h
(6aアセンブラヘッダファイル)src/cmd/6a/lex.c
(6aアセンブラ字句解析ファイル)src/cmd/8a/a.h
(8aアセンブラヘッダファイル)src/cmd/8a/lex.c
(8aアセンブラ字句解析ファイル)src/cmd/cc/lex.c
(Cコンパイラ字句解析ファイル)src/cmd/gc/lex.c
(Goコンパイラ字句解析ファイル)src/cmd/go/build.go
(Goビルドコマンドファイル)src/liblink/obj.c
(リンカオブジェクトファイル)src/liblink/sym.c
(リンカシンボルファイル)diff --git a/doc/go1.3.html b/doc/go1.3.html
(git diffヘッダ)index 10073200c4..916ed04d25 100644
(git index情報)--- a/doc/go1.3.html
(元のファイル)+++ b/doc/go1.3.html
(変更後のファイル)@@ -145,6 +145,19 @@
(diffチャンクヘッダ)Finally, the go command now supports packages that import Objective-C
(変更前の行)files (suffixed <code>.m</code>) through cgo.
(変更前の行)</p>
(変更前の行)<h3 id="gc_flag">Command-line flag parsing</h3>
(追加された行)<p>
(追加された行)In the gc tool chain, the assemblers now use the
(追加された行)same command-line flag parsing rules as the Go flag package, a departure
(追加された行)from the traditional Unix flag parsing. This may affect scripts that invoke
(追加された行)the tool directly.
(追加された行)For example,
(追加された行)<code>go tool 6a -SDfoo</code> must now be written
(追加された行)<code>go tool 6a -S -D foo</code>.
(追加された行)(The same change was made to the compilers and linkers in <a href="/doc/go1.1#gc_flag">Go 1.1</a>.)
(追加された行)</p>
(追加された行)<h3 id="misc">Miscellany</h3>
(変更前の行)<p>
(変更前の行)diff --git a/include/link.h b/include/link.h
(git diffヘッダ)index 9a6fca2ab0..200a503cce 100644
(git index情報)--- a/include/link.h
(元のファイル)+++ b/include/link.h
(変更後のファイル)@@ -360,6 +360,9 @@ struct Link
(diffチャンクヘッダ)Biobuf* tbso; // for -v flag
(変更前の行)char* pathname;
(変更前の行)int32 windows;
(変更前の行)char* trimpath;
(追加された行)char* goroot;
(追加された行)char* goroot_final;
(追加された行)// hash table of all symbols
(変更前の行)LSym* hash[LINKHASH];
(変更前の行)diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
(git diffヘッダ)index 4300dd8621..bb60fe7de2 100644
(git index情報)--- a/src/cmd/5a/a.h
(元のファイル)+++ b/src/cmd/5a/a.h
(変更後のファイル)@@ -97,7 +97,7 @@ enum
(diffチャンクヘッダ)Always = 14,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
(git diffヘッダ)index 211f7538b5..906eee641a 100644
(git index情報)--- a/src/cmd/5a/lex.c
(元のファイル)+++ b/src/cmd/5a/lex.c
(変更後のファイル)@@ -57,11 +57,27 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '5';
(変更前の行)thestring = "arm";
(変更前の行)@@ -84,49 +100,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 't':
(削除された行)thechar = 't';
(削除された行)thestring = "thumb";
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)if(*argv == 0) {
(削除された行)print("usage: %ca [-options] file.s\\n", thechar);
(削除された行)errorexit();
(削除された行)}
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
(git diffヘッダ)index da12b32986..b3fb0bb19f 100644
(git index情報)--- a/src/cmd/6a/a.h
(元のファイル)+++ b/src/cmd/6a/a.h
(変更後のファイル)@@ -109,7 +109,7 @@ enum
(diffチャンクヘッダ)CPREPROC,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
(git diffヘッダ)index 2a1c4b8e1f..4ebcc175c3 100644
(git index情報)--- a/src/cmd/6a/lex.c
(元のファイル)+++ b/src/cmd/6a/lex.c
(変更後のファイル)@@ -63,13 +63,29 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)LinkArch* thelinkarch = &linkamd64;
(変更前の行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '6';
(変更前の行)thestring = "amd64";
(変更前の行)@@ -94,45 +110,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
(git diffヘッダ)index 8c023c3ec6..adc388ca9f 100644
(git index情報)--- a/src/cmd/8a/a.h
(元のファイル)+++ b/src/cmd/8a/a.h
(変更後のファイル)@@ -109,7 +109,7 @@ enum
(diffチャンクヘッダ)CPREPROC,
(変更前の行)};
(変更前の行)EXTERN char debug[256];
(変更前の行)EXTERN int debug[256];
(変更後の行)EXTERN Sym* hash[NHASH];
(変更前の行)EXTERN char** Dlist;
(変更前の行)EXTERN int nDlist;
(変更前の行)diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
(git diffヘッダ)index 49a105da6a..79a9488e4b 100644
(git index情報)--- a/src/cmd/8a/lex.c
(元のファイル)+++ b/src/cmd/8a/lex.c
(変更後のファイル)@@ -63,11 +63,26 @@ Lconv(Fmt *fp)
(diffチャンクヘッダ)return linklinefmt(ctxt, fp);
(変更前の行)}
(変更前の行)void
(追加された行)dodef(char *p)
(追加された行){
(追加された行)if(nDlist%8 == 0)
(追加された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(追加された行)8*sizeof(char *));
(追加された行)Dlist[nDlist++] = p;
(追加された行)}
(追加された行)void
(追加された行)usage(void)
(追加された行){
(追加された行)print("usage: %ca [options] file.c...\\n", thechar);
(追加された行)flagprint(1);
(追加された行)errorexit();
(追加された行)}
(追加された行)void
(変更前の行)main(int argc, char *argv[])
(変更前の行){
(変更前の行)char *p;
(変更前の行)int c;
(削除された行)thechar = '8';
(変更前の行)thestring = "386";
(変更前の行)@@ -90,44 +105,24 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)cinit();
(変更前の行)outfile = 0;
(変更前の行)setinclude(".");
(変更前の行)ARGBEGIN {
(削除された行)default:
(削除された行)c = ARGC();
(削除された行)if(c >= 0 && c < sizeof(debug))
(削除された行)debug[c] = 1;
(削除された行)break;
(削除された行)case 'o':
(削除された行)outfile = ARGF();
(削除された行)break;
(削除された行)case 'D':
(削除された行)p = ARGF();
(削除された行)if(p) {
(削除された行)if (nDlist%8 == 0)
(削除された行)Dlist = allocn(Dlist, nDlist*sizeof(char *),
(削除された行)8*sizeof(char *));
(削除された行)Dlist[nDlist++] = p;
(削除された行)}
(削除された行)break;
(削除された行)case 'I':
(削除された行)p = ARGF();
(削除された行)setinclude(p);
(削除された行)break;
(削除された行)case 'S':
(削除された行)ctxt->debugasm++;
(削除された行)break;
(削除された行)} ARGEND
(削除された行)if(*argv == 0) {
(削除された行)print("usage: %ca [-options] file.s\\n", thechar);
(削除された行)errorexit();
(削除された行)}
(削除された行)flagfn1("D", "name[=value]: add #define", dodef);
(追加された行)flagfn1("I", "dir: add dir to include path", setinclude);
(追加された行)flagcount("S", "print assembly and machine code", &debug['S']);
(追加された行)flagcount("m", "debug preprocessor macros", &debug['m']);
(追加された行)flagstr("o", "file: set output file", &outfile);
(追加された行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagparse(&argc, &argv, usage);
(追加された行)ctxt->debugasm = debug['S'];
(追加された行)if(argc < 1)
(追加された行)usage();
(追加された行)if(argc > 1){
(変更前の行)print("can't assemble multiple files\\n");
(変更前の行)errorexit();
(変更前の行)}
(変更前の行)if(assemble(argv[0]))
(追加された行)errorexit();
(追加された行)Bflush(&bstdout);
(変更前の行)diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
(git diffヘッダ)index a8ece212f0..4248437643 100644
(git index情報)--- a/src/cmd/cc/lex.c
(元のファイル)+++ b/src/cmd/cc/lex.c
(変更後のファイル)@@ -195,6 +195,7 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)flagcount("q", "print Go definitions", &debug['q']);
(変更前の行)flagcount("s", "print #define assembly offsets", &debug['s']);
(変更前の行)flagcount("t", "debug code generation", &debug['t']);
(変更前の行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagcount("w", "enable warnings", &debug['w']);
(変更前の行)flagcount("v", "increase debug verbosity", &debug['v']);
(変更前の行)if(thechar == '6')
(変更前の行)diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
(git diffヘッダ)index f372581aae..7e28205656 100644
(git index情報)--- a/src/cmd/gc/lex.c
(元のファイル)+++ b/src/cmd/gc/lex.c
(変更後のファイル)@@ -306,6 +306,7 @@ main(int argc, char *argv[])
(diffチャンクヘッダ)flagcount("r", "debug generated wrappers", &debug['r']);
(変更前の行)flagcount("race", "enable race detector", &flag_race);
(変更前の行)flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
(変更前の行)flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
(追加された行)flagcount("u", "reject unsafe code", &safemode);
(変更前の行)flagcount("v", "increase debug verbosity", &debug['v']);
(変更前の行)flagcount("w", "debug type checking", &debug['w']);
(変更前の行)diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
(git diffヘッダ)index d7a1d21828..03300555de 100644
(git index情報)--- a/src/cmd/go/build.go
(元のファイル)+++ b/src/cmd/go/build.go
(変更後のファイル)@@ -1599,7 +1599,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string)
(diffチャンクヘッダ)gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
(変更前の行)}
(変更前の行)args := stringList(tool(archChar+"g"), "-o", ofile, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
(変更前の行)args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
(変更後の行)if ofile == archive {
(変更前の行)args = append(args, "-pack")
(変更前の行)}
(変更前の行)@@ -1613,7 +1613,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string)
(diffチャンクヘッダ)func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
(変更前の行)sfile = mkAbs(p.Dir, sfile)
(変更前の行)return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
(変更前の行)return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
(変更後の行)}
(変更前の行)func (gcToolchain) pkgpath(basedir string, p *Package) string {
(変更前の行)@@ -1626,7 +1626,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []string)
(diffチャンクヘッダ)for _, f := range ofiles {
(変更前の行)absOfiles = append(absOfiles, mkAbs(objDir, f))
(変更前の行)}
(変更前の行)cmd := "grcP"
(削除された行)cmd := "c"
(追加された行)absAfile := mkAbs(objDir, afile)
(変更前の行)appending := false
(変更前の行)if _, err := os.Stat(absAfile); err == nil {
(変更前の行)@@ -1784,7 +1784,7 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
(diffチャンクヘッダ)func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
(変更前の行)inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
(変更前の行)cfile = mkAbs(p.Dir, cfile)
(変更前の行)args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
(削除された行)args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
(追加された行)return b.run(p.Dir, p.ImportPath, nil, args)
(変更前の行)}
(変更前の行)diff --git a/src/liblink/obj.c b/src/liblink/obj.c
(git diffヘッダ)index 856227fe83..53ae470354 100644
(git index情報)--- a/src/liblink/obj.c
(元のファイル)+++ b/src/liblink/obj.c
(変更後のファイル)@@ -87,6 +87,34 @@ linklinefmt(Link *ctxt, Fmt *fp)
(diffチャンクヘッダ)return 0;
(変更前の行)}
(変更前の行)// Does s have t as a path prefix?
(追加された行)// That is, does s == t or does s begin with t followed by a slash?
(追加された行)// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
(追加された行)// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
(追加された行)static int
(追加された行)haspathprefix(char *s, char *t)
(追加された行){
(追加された行)int i, cs, ct;
(追加された行)if(t == nil)
(追加された行)return 0;
(追加された行)for(i=0; t[i]; i++) {
(追加された行)cs = s[i];
(追加された行)ct = t[i];
(追加された行)if('A' <= cs && cs <= 'Z')
(追加された行)cs += 'a' - 'A';
(追加された行)if('A' <= ct && ct <= 'Z')
(追加された行)ct += 'a' - 'A';
(追加された行)if(cs == '\\')
(追加された行)cs = '/';
(追加された行)if(ct == '\\')
(追加された行)ct = '/';
(追加された行)if(cs != ct)
(追加された行)return 0;
(追加された行)}
(追加された行)return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
(追加された行)}
(追加された行)// This is a simplified copy of linklinefmt above.
(変更前の行)// It doesn't allow printing the full stack, and it returns the file name and line number separately.
(変更前の行)// TODO: Unify with linklinefmt somehow.
(変更前の行)@@ -103,7 +131,7 @@ linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
(diffチャンクヘッダ)int32 lno, d, dlno;
(変更前の行)int n;
(変更前の行)Hist *h;
(変更前の行)char buf[1024], *file;
(変更前の行)char buf[1024], buf1[1024], *file;
(変更後の行)lno = line;
(変更前の行)n = 0;
(変更前の行)@@ -159,6 +187,22 @@ linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
(diffチャンクヘッダ)snprint(buf, sizeof buf, "%s", file);
(変更前の行)else
(変更前の行)snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
(変更前の行)// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
(追加された行)if(haspathprefix(buf, ctxt->trimpath)) {
(追加された行)if(strlen(buf) == strlen(ctxt->trimpath))
(追加された行)strcpy(buf, "??");
(追加された行)else {
(追加された行)snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
(追加された行)if(buf1[0] == '\0')
(追加された行)strcpy(buf1, "??");
(追加された行)strcpy(buf, buf1);
(追加された行)}
(追加された行)} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
(追加された行)snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
(追加された行)strcpy(buf, buf1);
(追加された行)}
(追加された行)lno -= dlno;
(変更前の行)*f = linklookup(ctxt, buf, HistVersion);
(変更前の行)*l = lno;
(変更前の行)diff --git a/src/liblink/sym.c b/src/liblink/sym.c
(git diffヘッダ)index 29fc036bcb..ff51b3df89 100644
(git index情報)--- a/src/liblink/sym.c
(元のファイル)+++ b/src/liblink/sym.c
(変更後のファイル)@@ -95,6 +95,10 @@ linknew(LinkArch *arch)
(diffチャンクヘッダ)ctxt = emallocz(sizeof *ctxt);
(変更前の行)ctxt->arch = arch;
(変更前の行)ctxt->version = HistVersion;
(変更前の行)ctxt->goroot = getgoroot();
(追加された行)ctxt->goroot_final = getenv("GOROOT_FINAL");
(追加された行)if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
(追加された行)ctxt->goroot_final = nil;
(追加された行)p = getgoarch();
(変更前の行)if(strcmp(p, arch->name) != 0)
(変更前の行)