[インデックス 1679] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるgobuild
コマンドの挙動を修正し、生成されるMakefileのコメント行にGOOS
とGOARCH
といった環境変数をより適切に挿入するように変更します。具体的には、シェル形式の変数展開(${VAR}
)とMakefile形式の変数展開($(VAR)
)を区別して出力するよう改善されています。
コミット
commit 97dcc68f1ec4202b467210dcd2607c7630bb9d6e
Author: Russ Cox <rsc@golang.org>
Date: Sun Feb 15 19:20:35 2009 -0800
insert ${GOOS} and ${GOARCH} in
command-line comment.
R=r
DELTA=11 (6 added, 0 deleted, 5 changed)
OCL=25051
CL=25051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/97dcc68f1ec4202b467210dcd2607c7630bb9d6e
元コミット内容
このコミットの元の内容は、gobuild
が生成するMakefileのコメント行に、GOOS
とGOARCH
というGoの環境変数を挿入する際の書式を改善することです。以前は常に$(VAR)
形式で出力されていましたが、この変更により、シェルコマンドとして解釈されるべき箇所では${VAR}
形式で出力されるようになります。
変更の背景
Go言語の初期のビルドシステムでは、gobuild
というツールがGoソースコードからMakefileを生成していました。このMakefileには、gobuild
が実行された際のコマンドライン引数がコメントとして記録されていました。このコメント行は、主にデバッグや履歴追跡のために利用されます。
問題は、このコメント行にGOOS
やGOARCH
といった環境変数が含まれる場合、gobuild
がそれらを常にMakefileの変数展開形式である$(GOOS)
や$(GOARCH)
として出力していた点にありました。しかし、このコメント行はしばしばシェルコマンドとして解釈される文脈で利用されることがあり、その場合、シェルでは$(VAR)
ではなく${VAR}
が一般的な変数展開の書式となります。
この不一致は、コメント行をコピーしてシェルで直接実行しようとした際に問題を引き起こす可能性がありました。例えば、gobuild
の実行コマンドがコメントとして記録されている場合、そのコマンドをそのままシェルに貼り付けて実行すると、$(GOOS)
がシェルによって正しく解釈されず、予期せぬエラーや挙動につながる可能性がありました。
このコミットは、このような潜在的な問題を解決し、生成されるMakefileのコメントがより汎用的に、特にシェル環境での利用において、より正確な変数展開形式を反映するようにするために行われました。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
Go言語のビルドシステム(初期): Go言語の初期のビルドシステムは、現在の
go build
コマンドとは異なり、gobuild
というツールを使用していました。gobuild
は、GoのソースファイルからC言語のコードを生成し、それをコンパイルして実行可能ファイルを生成するプロセスを自動化していました。この過程で、ビルドに必要な情報やコマンドライン引数を記録したMakefileを生成していました。 -
Makefileと変数展開: Makefileは、
make
ユーティリティがプロジェクトのビルドを自動化するために使用するファイルです。Makefileでは、変数を定義し、それらを$(VAR_NAME)
という形式で参照します。make
は、これらの変数をその値に展開してからコマンドを実行します。例:
CC = gcc CFLAGS = -Wall all: $(CC) $(CFLAGS) main.c -o main
この例では、
$(CC)
はgcc
に、$(CFLAGS)
は-Wall
に展開されます。 -
シェルスクリプトと変数展開: Bashなどのシェルスクリプトでは、変数を参照する際に
${VAR_NAME}
または$VAR_NAME
という形式を使用します。${VAR_NAME}
は、変数名が他の文字列と連結される場合など、曖昧さを避けるためによく使われます。例:
#!/bin/bash GOOS="linux" echo "Operating system: ${GOOS}"
この例では、
${GOOS}
はlinux
に展開されます。 -
GOOS
とGOARCH
: これらはGo言語のクロスコンパイルにおいて非常に重要な環境変数です。GOOS
: ターゲットとするオペレーティングシステム(例:linux
,windows
,darwin
)。GOARCH
: ターゲットとするアーキテクチャ(例:amd64
,arm
,386
)。 これらの変数を設定することで、異なるOSやアーキテクチャ向けのバイナリをビルドできます。
-
fmt
パッケージとFmtSharp
フラグ: Go言語の初期のコードベースでは、C言語のprintf
ライクなフォーマット機能を提供する内部的なfmt
パッケージ(またはそれに類するもの)が使用されていました。このコミットで登場するFmtSharp
フラグは、C言語のprintf
における#
フラグ(代替形式)に似た概念で、出力の形式を微調整するために使用される可能性があります。この文脈では、おそらく「シェル形式」の出力が必要な場合に設定されるフラグとして機能しています。
技術的詳細
このコミットは、主にsrc/cmd/gobuild/gobuild.c
ファイルのdollarfmt
関数とwritemakefile
関数に変更を加えています。
gobuild
は、ビルドプロセスの一環としてMakefileを生成します。このMakefileには、gobuild
が実行された際のコマンドラインがコメントとして含まれていました。このコメントは、gobuild
が内部的に持っているGOOS
やGOARCH
といった値を、生成されるMakefileのコメント行に挿入する際に、常に$(GOOS)
や$(GOARCH)
という形式で出力していました。
変更の核心は、dollarfmt
関数にあります。この関数は、文字列中の特定のパターン(この場合はgoos
やgoarch
の値)を、対応する変数形式($(GOOS)
や$(GOARCH)
)に置き換える役割を担っています。
コミット前のコードでは、goos
やgoarch
が見つかると、無条件に$(GOOS)
や$(GOARCH)
に置き換えていました。
// コミット前のコード (抜粋)
if(strncmp(s, goarch, n) == 0){
fmtstrcpy(f, "$(GOARCH)");
continue;
}
// ...
if(strncmp(s, goos, n) == 0){
fmtstrcpy(f, "$(GOOS)");
continue;
}
このコミットでは、dollarfmt
関数内でf->flags & FmtSharp
という条件分岐が追加されました。これは、フォーマットフラグにFmtSharp
が設定されているかどうかをチェックしています。
- もし
FmtSharp
フラグが設定されていれば、変数はシェル形式の${VAR}
として出力されます。 - そうでなければ、従来通りMakefile形式の
$(VAR)
として出力されます。
// コミット後のコード (抜粋)
if(strncmp(s, goarch, n) == 0){
if(f->flags & FmtSharp)
fmtstrcpy(f, "${GOARCH}"); // shell
else
fmtstrcpy(f, "$(GOARCH)"); // make
continue;
}
// ...
if(strncmp(s, goos, n) == 0){
if(f->flags & FmtSharp)
fmtstrcpy(f, "${GOOS}"); // shell
else
fmtstrcpy(f, "$(GOOS)"); // make
continue;
}
この変更に伴い、writemakefile
関数内のBprint
呼び出しも修正されました。以前はBprint(&bout, " %s", oargv[i]);
としていた箇所が、Bprint(&bout, " %#$", oargv[i]);
に変更されています。この%#$
というフォーマット指定子が、dollarfmt
関数内でFmtSharp
フラグを有効にする役割を果たしています。これにより、gobuild
のコマンドライン引数をコメントとして出力する際に、GOOS
やGOARCH
が${VAR}
形式で挿入されるようになります。
src/lib/net/Makefile
の変更は、このgobuild
の変更によって生成されるMakefileのコメント行の例を示しています。以前はgobuild -m ... >Makefile
というコメントでしたが、変更後はgobuild -m ... fd_${GOOS}.go ... net_${GOOS}.go >Makefile
のように、GOOS
が${GOOS}
としてコメント内に表示されるようになります。これは、gobuild
が生成するMakefileのコメントが、よりシェルフレンドリーな形式になったことを示しています。
コアとなるコードの変更箇所
src/cmd/gobuild/gobuild.c
--- a/src/cmd/gobuild/gobuild.c
+++ b/src/cmd/gobuild/gobuild.c
@@ -263,12 +263,18 @@ dollarfmt(Fmt *f)
for(; *s; s+=n){
n = strlen(goarch);
if(strncmp(s, goarch, n) == 0){
- fmtstrcpy(f, "$(GOARCH)");
+ if(f->flags & FmtSharp)
+ fmtstrcpy(f, "${GOARCH}"); // shell
+ else
+ fmtstrcpy(f, "$(GOARCH)"); // make
continue;
}
n = strlen(goos);
if(strncmp(s, goos, n) == 0){
- fmtstrcpy(f, "$(GOOS)");
+ if(f->flags & FmtSharp)
+ fmtstrcpy(f, "${GOOS}"); // shell
+ else
+ fmtstrcpy(f, "$(GOOS)"); // make
continue;
}
n = chartorune(&r, s);
@@ -327,7 +333,7 @@ writemakefile(void)
Bprint(&bout, "\\\n# ");
o = Boffset(&bout);
}
- Bprint(&bout, " %s", oargv[i]);
+ Bprint(&bout, " %#$", oargv[i]);
}
Bprint(&bout, " >Makefile\\n");
Bprint(&bout, preamble, thechar);
src/lib/net/Makefile
--- a/src/lib/net/Makefile
+++ b/src/lib/net/Makefile
@@ -3,8 +3,8 @@
# license that can be found in the LICENSE file.
# DO NOT EDIT. Automatically generated by gobuild.
-# gobuild -m dnsclient.go dnsconfig.go dnsmsg.go fd.go fd_darwin.go\
-# ip.go net.go net_darwin.go parse.go port.go >Makefile
+# gobuild -m dnsclient.go dnsconfig.go dnsmsg.go fd.go fd_${GOOS}.go\
+# ip.go net.go net_${GOOS}.go parse.go port.go >Makefile
O=6
GC=$(O)g
CC=$(O)c -w
コアとなるコードの解説
src/cmd/gobuild/gobuild.c
の変更
-
dollarfmt
関数の変更: この関数は、gobuild
が文字列をフォーマットする際に、GOOS
やGOARCH
といった特定のキーワードを対応する変数形式に変換する役割を担っています。- 変更前は、
goarch
やgoos
という文字列が見つかると、無条件に$(GOARCH)
や$(GOOS)
というMakefile形式の変数展開文字列に置き換えていました。 - 変更後は、
if(f->flags & FmtSharp)
という条件が追加されました。これは、フォーマット指定子に#
フラグ(代替形式)が指定されているかどうかをチェックしています。- もし
#
フラグが設定されていれば、fmtstrcpy(f, "${GOARCH}");
またはfmtstrcpy(f, "${GOOS}");
が実行され、シェル形式の変数展開(${VAR}
)が出力されます。コメントには「// shell」と書かれており、これがシェルで解釈されることを意図していることがわかります。 #
フラグが設定されていなければ、従来通りfmtstrcpy(f, "$(GOARCH)");
またはfmtstrcpy(f, "$(GOOS)");
が実行され、Makefile形式の変数展開($(VAR)
)が出力されます。コメントには「// make」と書かれており、これがMakefileで解釈されることを意図していることがわかります。 この変更により、gobuild
は出力のコンテキストに応じて適切な変数展開形式を選択できるようになりました。
- もし
- 変更前は、
-
writemakefile
関数の変更: この関数は、最終的なMakefileの内容を書き出す役割を担っています。- 変更前は、コマンドライン引数を
Bprint(&bout, " %s", oargv[i]);
という形式で出力していました。ここで%s
は単純な文字列として引数を挿入します。 - 変更後は、
Bprint(&bout, " %#$", oargv[i]);
に変更されました。ここで注目すべきは%#$
という新しいフォーマット指定子です。%
はフォーマット指定子の開始を示します。#
は、前述のdollarfmt
関数でチェックされるFmtSharp
フラグを有効にする役割を果たします。これにより、dollarfmt
がシェル形式の変数展開を選択するようになります。$
は、おそらくdollarfmt
関数を呼び出すためのカスタムフォーマット指定子です。 この変更により、gobuild
が生成するMakefileのコメント行に、GOOS
やGOARCH
といった環境変数が含まれる場合、それらがシェルで正しく解釈される${VAR}
形式で出力されるようになりました。
- 変更前は、コマンドライン引数を
src/lib/net/Makefile
の変更
このファイルは、gobuild
によって自動生成されるMakefileの一例です。このコミットにおける変更は、gobuild
の挙動変更によって、このMakefileのコメント行がどのように変化するかを示しています。
- 変更前は、コメント行に
fd_darwin.go
やnet_darwin.go
のように、特定のOS名がハードコードされていました。これは、gobuild
が実行された環境のGOOS
が直接埋め込まれていたことを示唆しています。 - 変更後は、コメント行が
fd_${GOOS}.go
やnet_${GOOS}.go
のように、${GOOS}
というシェル形式の変数展開を含むようになりました。これは、gobuild
が生成するコメントが、実行時の環境変数ではなく、より汎用的な変数形式でコマンドラインを表現するようになったことを示しています。これにより、このコメント行をコピーして別の環境で実行する際に、その環境のGOOS
が自動的に適用されるようになり、利便性が向上します。
関連リンク
- Go言語の初期のビルドシステムに関する情報(歴史的な文脈)
- Makefileの変数展開に関するドキュメント
- シェルスクリプトの変数展開に関するドキュメント
参考にした情報源リンク
- Go言語の公式ドキュメント (特に初期のビルドシステムに関するアーカイブ情報があれば)
- GNU Make マニュアル
- Bash マニュアル
- Go言語のソースコードリポジトリ (過去のコミット履歴)
- Go言語のIssueトラッカー (関連する議論があれば)