[インデックス 13143] ファイルの概要
このコミットは、Go言語の公式リポジトリにおける cmd/api ツールに関連するものです。cmd/api は、Goの標準ライブラリのAPIサーフェスを検査し、互換性のない変更がないかを確認するために使用されるコマンドラインツールです。具体的には、goapi.go ファイルがこのツールの主要なロジックを含んでいます。このファイルは、異なるビルドコンテキスト(オペレーティングシステム、アーキテクチャ、Cgoの有効/無効など)におけるGoパッケージのAPIを分析し、APIの変更点を追跡する役割を担っています。
コミット
commit f430d0e6096093c9b21b05c48acabe4ab15f87cd
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed May 23 13:45:53 2012 -0700
cmd/api: add flag to specify contexts
I needed this to explore per-GOOS/GOARCH differences in pkg
syscall for a recent CL. Others may find it useful too.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6236046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f430d0e6096093c9b21b05c48acabe4ab15f87cd
元コミット内容
cmd/api: add flag to specify contexts
I needed this to explore per-GOOS/GOARCH differences in pkg
syscall for a recent CL. Others may find it useful too.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6236046
変更の背景
この変更は、cmd/api ツールに新しいコマンドラインフラグ -contexts を追加するものです。コミットメッセージによると、作者のBrad Fitzpatrick氏は、pkg syscall の特定の変更セット(CL: Change List)において、異なる GOOS(オペレーティングシステム)と GOARCH(アーキテクチャ)の組み合わせによるAPIの違いを調査する必要がありました。
cmd/api ツールは、デフォルトで複数のビルドコンテキスト(例: Linux/386, Windows/amd64など)を考慮してAPIを分析します。しかし、特定のOS/アーキテクチャの組み合わせに限定して分析を行いたい場合や、デフォルトで含まれていない特定のコンテキストでAPIを検査したい場合に、既存の機能では対応できませんでした。
この新しいフラグ -contexts を導入することで、ユーザーはカンマ区切りの <goos>-<goarch>[-cgo] 形式で任意のビルドコンテキストを指定できるようになります。これにより、より柔軟かつ詳細なAPI分析が可能となり、特定の環境におけるAPIの挙動や互換性の問題を効率的に特定できるようになります。作者は、この機能が自分だけでなく、他の開発者にとっても有用であると考えています。
前提知識の解説
cmd/api ツール
cmd/api はGo言語のツールチェインの一部であり、Goの標準ライブラリのAPIサーフェスを検査するために使用されます。その主な目的は、Goのリリース間でAPIの互換性が維持されていることを確認することです。このツールは、Goのソースコードを解析し、エクスポートされた型、関数、メソッド、変数などのAPI要素を抽出し、それらを以前のバージョンのAPIと比較します。これにより、意図しないAPIの変更(特に破壊的変更)を検出することができます。
GOOS と GOARCH
GOOS (Go Operating System) と GOARCH (Go Architecture) は、Goのビルドシステムで使用される環境変数です。これらは、GoプログラムがコンパイルされるターゲットのオペレーティングシステムとCPUアーキテクチャを指定します。
GOOS:linux,windows,darwin(macOS),freebsd,android,iosなど。GOARCH:amd64,386,arm,arm64,ppc64,s390xなど。
Goのソースコードには、これらの環境変数に基づいて条件付きでコンパイルされる部分(ビルドタグやファイル名サフィックスなど)が存在します。これにより、特定のOSやアーキテクチャに特化したコードを記述し、クロスプラットフォーム対応を実現しています。
build.Context
Goの go/build パッケージには Context という構造体があります。これは、Goのビルドプロセスにおける環境設定をカプセル化するものです。Context 構造体には、GOOS, GOARCH, CgoEnabled (Cgoが有効かどうか), Compiler (使用するコンパイラ) などのフィールドが含まれています。cmd/api ツールは、この build.Context のインスタンスを使用して、異なるターゲット環境でのAPIをシミュレートし、分析します。
cgo
cgo は、GoプログラムからC言語のコードを呼び出すためのGoの機能です。CgoEnabled フラグは、特定のビルドコンテキストで cgo が有効になっているかどうかを示します。cgo を使用するGoパッケージは、cgo が無効な環境ではコンパイルできないか、異なるAPIを提供する可能性があります。そのため、API分析において cgo の有効/無効を考慮することは重要です。
技術的詳細
このコミットの技術的詳細は、主に src/cmd/api/goapi.go ファイルへの変更に集約されます。
-
新しいフラグ
-contextsの追加:flag.Stringを使用して、forceCtxという新しいグローバル変数が定義されました。これは、コマンドラインから-contextsフラグで渡される文字列(例:"linux-amd64,windows-386-cgo")を保持します。var ( // ... 既存のフラグ定義 ... forceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.") ) -
デフォルトコンテキストの初期化ロジックの変更: 以前は
init()関数内でcontextsスライス内の各build.ContextのCompilerフィールドがbuild.Default.Compilerに設定されていました。このコミットにより、この初期化ロジックはmain()関数内に移動され、-contextsフラグが指定された場合に新しいコンテキストが設定された後に実行されるようになりました。// 変更前: // func init() { // for _, c := range contexts { // c.Compiler = build.Default.Compiler // } // } // 変更後 (main関数内): // if *forceCtx != "" { // setContexts() // } // for _, c := range contexts { // c.Compiler = build.Default.Compiler // } -
parseContext関数の追加: この新しい関数は、<goos>-<goarch>[-cgo]形式の文字列を受け取り、対応する*build.Contextオブジェクトを生成します。入力文字列をハイフンで分割し、GOOSとGOARCHを抽出し、オプションでcgoが指定されていればCgoEnabledをtrueに設定します。不正な形式の文字列が渡された場合はlog.Fatalfでプログラムを終了させます。func parseContext(c string) *build.Context { parts := strings.Split(c, "-") if len(parts) < 2 { log.Fatalf("bad context: %q", c) } bc := &build.Context{ GOOS: parts[0], GOARCH: parts[1], } if len(parts) == 3 { if parts[2] == "cgo" { bc.CgoEnabled = true } else { log.Fatalf("bad context: %q", c) } } return bc } -
setContexts関数の追加: この関数は、-contextsフラグで指定されたカンマ区切りの文字列を解析し、グローバル変数contextsを新しい*build.Contextスライスで上書きします。strings.Splitで文字列を分割し、各部分文字列をparseContextに渡してbuild.Contextオブジェクトを生成し、それをcontextsスライスに追加します。func setContexts() { contexts = []*build.Context{} // デフォルトコンテキストをクリア for _, c := range strings.Split(*forceCtx, ",") { contexts = append(contexts, parseContext(c)) } } -
main関数でのフラグ処理:main関数内でflag.Parse()の後、*forceCtx(つまり-contextsフラグの値) が空文字列でない場合にsetContexts()が呼び出されます。これにより、ユーザーが指定したコンテキストがデフォルトのコンテキストリストを上書きします。その後、contextsスライス内のすべてのbuild.Contextオブジェクトに対してCompilerフィールドが設定されます。func main() { flag.Parse() if *forceCtx != "" { setContexts() } for _, c := range contexts { c.Compiler = build.Default.Compiler } // ... 既存のロジック ... }
これらの変更により、cmd/api ツールは、ユーザーがコマンドラインから明示的に指定したビルドコンテキストに基づいてAPI分析を実行できるようになり、特定のプラットフォームやビルド設定に特化したAPIの差異を効率的に調査することが可能になりました。
コアとなるコードの変更箇所
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 533636cd8a..b10a51c510 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -41,8 +41,11 @@ var (
allowNew = flag.Bool("allow_new", true, "allow API additions")
nextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
verbose = flag.Bool("v", false, "verbose debugging")
+ forceCtx = flag.String("contexts", "", "optional comma-separated list of <goos>-<goarch>[-cgo] to override default contexts.")
)
+// contexts are the default contexts which are scanned, unless
+// overridden by the -contexts flag.
var contexts = []*build.Context{
{GOOS: "linux", GOARCH: "386", CgoEnabled: true},
{GOOS: "linux", GOARCH: "386"},
@@ -56,12 +59,6 @@ var contexts = []*build.Context{
{GOOS: "windows", GOARCH: "386"},
}
-func init() {
- for _, c := range contexts {
- c.Compiler = build.Default.Compiler
- }
-}
-
func contextName(c *build.Context) string {
s := c.GOOS + "-" + c.GOARCH
if c.CgoEnabled {
@@ -70,9 +67,42 @@ func contextName(c *build.Context) string {
return s
}
+func parseContext(c string) *build.Context {
+ parts := strings.Split(c, "-")
+ if len(parts) < 2 {
+ log.Fatalf("bad context: %q", c)
+ }
+ bc := &build.Context{
+ GOOS: parts[0],
+ GOARCH: parts[1],
+ }
+ if len(parts) == 3 {
+ if parts[2] == "cgo" {
+ bc.CgoEnabled = true
+ } else {
+ log.Fatalf("bad context: %q", c)
+ }
+ }
+ return bc
+}
+
+func setContexts() {
+ contexts = []*build.Context{}
+ for _, c := range strings.Split(*forceCtx, ",") {
+ contexts = append(contexts, parseContext(c))
+ }
+}
+
func main() {
flag.Parse()
+ if *forceCtx != "" {
+ setContexts()
+ }
+ for _, c := range contexts {
+ c.Compiler = build.Default.Compiler
+ }
+
var pkgs []string
if flag.NArg() > 0 {
pkgs = flag.Args()
コアとなるコードの解説
このコミットは、src/cmd/api/goapi.go ファイルに以下の主要な変更を加えています。
-
forceCtxフラグの追加:var (ブロック内にforceCtxという新しいstring型のフラグが追加されました。これは-contextsコマンドライン引数に対応し、ユーザーが指定するビルドコンテキストのリストをカンマ区切り文字列として受け取ります。 -
init()関数の削除とCompiler設定の移動: 以前はinit()関数内でcontextsスライス内の各build.ContextのCompilerフィールドをbuild.Default.Compilerに設定していました。このinit()関数は削除され、そのロジックはmain()関数内に移動されました。これにより、ユーザーが-contextsフラグで新しいコンテキストを指定した場合でも、正しくCompilerが設定されるようになります。 -
parseContext(c string) *build.Context関数の追加: この関数は、"goos-goarch"または"goos-goarch-cgo"形式の文字列を解析し、対応する*build.Contextオブジェクトを返します。- 入力文字列をハイフン (
-) で分割します。 - 少なくとも2つの部分(
GOOSとGOARCH)があることを確認します。そうでなければ、不正なコンテキストとしてプログラムを終了します。 build.Contextの新しいインスタンスを作成し、GOOSとGOARCHを設定します。- もし3番目の部分があり、それが
"cgo"であれば、CgoEnabledをtrueに設定します。それ以外の場合は、不正なコンテキストとしてプログラムを終了します。
- 入力文字列をハイフン (
-
setContexts()関数の追加: この関数は、forceCtxフラグ(ユーザーが-contextsで指定した文字列)を読み取り、それをカンマ (,) で分割します。分割された各部分文字列に対してparseContextを呼び出し、生成された*build.Contextオブジェクトをグローバルなcontextsスライスに追加します。これにより、デフォルトで定義されていたcontextsスライスが、ユーザーが指定したコンテキストで完全に上書きされます。 -
main()関数内のロジック変更:flag.Parse()の呼び出し後、main()関数はまず*forceCtxが空文字列でないか(つまり、ユーザーが-contextsフラグを指定したか)をチェックします。- もし指定されていれば、
setContexts()を呼び出して、contextsスライスをユーザー定義のコンテキストで更新します。 - その後、
contextsスライス内のすべてのbuild.Contextオブジェクトに対して、Compilerフィールドをbuild.Default.Compilerに設定します。このステップは、init()関数から移動されたものです。
- もし指定されていれば、
これらの変更により、cmd/api ツールは、デフォルトのビルドコンテキストのセットに加えて、またはそれを完全に置き換えて、ユーザーが指定した特定のビルドコンテキストでAPI分析を実行する柔軟性を獲得しました。
関連リンク
- Go CL 6236046: https://golang.org/cl/6236046
参考にした情報源リンク
- Go Command
api: https://pkg.go.dev/cmd/api - Go
go/buildpackage: https://pkg.go.dev/go/build - Go
flagpackage: https://pkg.go.dev/flag - Go
stringspackage: https://pkg.go.dev/strings - Go
logpackage: https://pkg.go.dev/log - Go Environment Variables (
GOOS,GOARCH): https://go.dev/doc/install/source#environment - Cgo: https://go.dev/blog/c-go-is-not-go