[インデックス 19265] ファイルの概要
このコミットは、Go言語のビルドシステムの一部である src/cmd/dist/build.c
ファイルに対する変更です。cmd/dist
はGoのソースコードからGoツールチェイン自体をビルドするために使用されるプログラムであり、Goのリリースプロセスにおいて重要な役割を担っています。具体的には、Goのバージョン情報に基づいて特定のビルド時の制約を適用するロジックが含まれています。
コミット
このコミットは、Goのメイン開発ブランチ(当時のMercurialにおけるdefault
ブランチ)において、go*
というプレフィックスを持つタグ、特にgo1.3beta1
のようなベータ版を示すタグが使用された際に、ビルドが中断されないようにするための変更です。これにより、コミュニティのメンバーがソースからベータ版をビルドする際に、よりスムーズな体験を提供できるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5cb67d7ba4fab6961d3693545697c051daa6a3b0
元コミット内容
commit 5cb67d7ba4fab6961d3693545697c051daa6a3b0
Author: Andrew Gerrand <adg@golang.org>
Date: Thu May 1 12:13:32 2014 -0400
cmd/dist: permit go* tag in main branch when it includes "beta"
This change allows us to give an hg tag such as "go1.3beta1" to
revisions in the main branch without breaking the build.
This is helpful for community members who want to build the beta
from source.
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/90190044
変更の背景
Goのリリースプロセスでは、安定版リリース(例: go1.2
, go1.3
)と、その前のベータ版(例: go1.3beta1
)やリリース候補版(例: go1.3rc1
)が存在します。cmd/dist
は、ビルドされるGoのバージョンがリリース版であるかどうかを判断し、それに基づいて特定のディレクトリ(unreleased
配列で定義されているもの)が存在しないことを確認するロジックを持っていました。これは、リリース版には開発中の機能や一時的なファイルが含まれていないことを保証するためです。
しかし、このロジックは、go1.3beta1
のようにgo
で始まるがまだ正式なリリースではないバージョンタグがメインブランチに適用された場合に問題を引き起こしていました。従来の条件では、go
で始まるバージョンはすべて「リリース版」と見なされ、開発中のディレクトリが存在するとビルドが失敗していました。これは、ベータ版をソースからビルドしようとするコミュニティメンバーにとって不便であり、ビルドが意図せず中断される原因となっていました。
この変更の目的は、go
で始まるバージョンタグであっても、それが「ベータ版」であることを示す文字列(beta
)を含んでいる場合には、リリース版としての厳格なチェックを緩和し、ビルドが成功するようにすることでした。これにより、開発ブランチでベータ版タグが使用されても、ビルドプロセスがスムーズに進行するようになります。
前提知識の解説
cmd/dist
cmd/dist
は、Go言語のソースコードからGoツールチェイン(コンパイラ、リンカ、標準ライブラリなど)をビルドするための内部ツールです。Goのブートストラッププロセスにおいて中心的な役割を担っており、Goのバージョン管理やクロスコンパイルの設定など、ビルドに関する様々なロジックを処理します。Goのソースツリーのルートディレクトリで./all.bash
(Unix系)やall.bat
(Windows)を実行すると、内部的にcmd/dist
が呼び出され、Goのビルドが開始されます。
Goのバージョン管理とリリースプロセス
Go言語はセマンティックバージョニングに似たバージョン管理スキームを採用しています。
go1.x
: 正式な安定版リリースを示します。例:go1.2
,go1.3
。go1.xbetaY
:go1.x
のベータ版リリースを示します。Y
はベータ版の番号です。例:go1.3beta1
。go1.xrcY
:go1.x
のリリース候補版を示します。Y
はリリース候補版の番号です。例:go1.3rc1
。release.rX
: 内部的なリリースブランチや特定のリリースポイントを示すために使用されることがあります。
cmd/dist
は、goversion
という変数を通じて現在のビルドのバージョン文字列を取得し、その文字列に基づいて異なるビルドロジックを適用します。
hasprefix
とcontains
関数
src/cmd/dist/build.c
はC言語で書かれており、文字列操作のために以下の関数を使用しています。
hasprefix(string, prefix)
:string
がprefix
で始まるかどうかを判定する関数です。例えば、hasprefix("go1.3beta1", "go")
は真を返します。contains(string, substring)
:string
がsubstring
を含むかどうかを判定する関数です。例えば、contains("go1.3beta1", "beta")
は真を返します。
これらの関数は、Goのバージョン文字列を解析し、特定の条件を満たすかどうかをチェックするために利用されます。
技術的詳細
変更が行われたのは、setup()
関数内のリリースビルドに関するチェック部分です。このチェックは、goversion
(現在のGoのバージョン文字列)が特定の条件を満たす場合に、unreleased
配列にリストされているディレクトリ(例: src/pkg/exp
など、開発中の実験的なパッケージや一時的なファイルが含まれる可能性のあるディレクトリ)が存在しないことを確認するものです。これらのディレクトリは、正式なリリースビルドには含まれるべきではないとされています。
変更前の条件は以下の通りでした。
if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) {
// ... unreleased ディレクトリのチェック ...
}
この条件は、「goversion
がrelease.
で始まる場合」または「goversion
がgo
で始まる場合」に、unreleased
ディレクトリの存在チェックを実行するというものでした。
問題は、go1.3beta1
のようなベータ版のバージョン文字列もgo
で始まるため、この条件に合致してしまい、まだ開発中のディレクトリが存在するメインブランチでのビルドが失敗してしまう点にありました。
変更後の条件は以下の通りです。
if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
// ... unreleased ディレクトリのチェック ...
}
この新しい条件は、論理的に以下のように解釈できます。
goversion
がrelease.
で始まる場合(これは従来のリリースブランチのタグをカバーします)。- または、
goversion
がgo
で始まり、かつgoversion
がbeta
という文字列を含まない場合。
この変更により、go1.3beta1
のようなバージョン文字列の場合、hasprefix(goversion, "go")
は真となりますが、contains(goversion, "beta")
も真となるため、!contains(goversion, "beta")
は偽となります。結果として、hasprefix(goversion, "go") && !contains(goversion, "beta")
の全体が偽となり、unreleased
ディレクトリのチェックがスキップされます。
これにより、ベータ版のタグが付けられたメインブランチのリビジョンでも、unreleased
ディレクトリが存在していてもビルドが成功するようになり、コミュニティメンバーがソースからベータ版をビルドする際の利便性が向上しました。
コアとなるコードの変更箇所
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -444,7 +444,7 @@ setup(void)
}\n
\n
// For release, make sure excluded things are excluded.\n
- if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) {\n
+ if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {\n
\tfor(i=0; i<nelem(unreleased); i++)\n
\t\tif(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))\n
\t\t\tfatal("%s should not exist in release build", bstr(&b));\n
コアとなるコードの解説
変更された行は、setup()
関数内のif
文の条件式です。
-
変更前:
if(hasprefix(goversion, "release.") || hasprefix(goversion, "go")) {
この条件は、
goversion
が"release."
で始まるか、または"go"
で始まる場合に真となります。これは、正式なリリース版(release.rX
やgo1.x
)だけでなく、go1.xbetaY
のようなベータ版も"go"
で始まるため、リリース版と同様の厳格なチェックが適用されていました。 -
変更後:
if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
この新しい条件は、以下のいずれかの条件が真の場合に全体が真となります。
goversion
が"release."
で始まる場合。goversion
が"go"
で始まり、かつgoversion
が"beta"
という文字列を含まない場合。
この
&& !contains(goversion, "beta")
という追加の条件が重要です。これにより、go1.3beta1
のように"go"
で始まり、かつ"beta"
を含むバージョン文字列は、このif
文の条件を満たさなくなります。結果として、ベータ版のビルド時には、unreleased
ディレクトリの存在チェックがスキップされ、ビルドが中断されることなく進行するようになります。
この変更は、Goのビルドシステムが、開発ブランチにおけるベータ版のタグ付けと、それに対応するビルドの振る舞いをより柔軟に扱えるようにするための、実用的な改善と言えます。
関連リンク
- Go CL 90190044: https://golang.org/cl/90190044
参考にした情報源リンク
- Go言語の公式ドキュメント (Goのバージョン管理、ビルドプロセスに関する一般的な情報)
- Go言語のソースコード (
src/cmd/dist/build.c
および関連ファイル) - Mercurial (当時のGoプロジェクトが使用していたバージョン管理システムに関する一般的な知識)
- C言語の文字列操作に関する一般的な知識