[インデックス 12064] ファイルの概要
このコミットは、Go言語のcmd/fix
ツールにruntime
パッケージ内の関数名の変更(リネーム)ルールを追加するものです。具体的には、runtime.Cgocalls
をruntime.NumCgoCall
に、runtime.Goroutines
をruntime.NumGoroutine
にそれぞれ変更するルールが追加されました。これにより、Go 1のリリースに向けたAPIの安定化と、古いAPIを使用しているコードの自動更新を支援します。
コミット
commit 3c831f6395dcda1742c6737e367cd804ea87fd82
Author: Russ Cox <rsc@golang.org>
Date: Sun Feb 19 16:10:45 2012 -0500
cmd/fix: add runtime renamings
R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/5685043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3c831f6395dcda1742c6737e367cd804ea87fd82
元コミット内容
commit 3c831f6395dcda1742c6737e367cd804ea87fd82
Author: Russ Cox <rsc@golang.org>
Date: Sun Feb 19 16:10:45 2012 -0500
cmd/fix: add runtime renamings
R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/5685043
---
src/cmd/fix/go1rename.go | 12 ++++++++++++\n src/cmd/fix/go1rename_test.go | 6 ++++++\n 2 files changed, 18 insertions(+)\n
diff --git a/src/cmd/fix/go1rename.go b/src/cmd/fix/go1rename.go
index 5d12f18701..2995880c30 100644
--- a/src/cmd/fix/go1rename.go
+++ b/src/cmd/fix/go1rename.go
@@ -56,4 +56,16 @@ var go1renameReplace = []rename{\n \tOld: \"os.Exec\",\n \tNew: \"syscall.Exec\",\n },\n+\t{\n+\t\tOldImport: \"runtime\",\n+\t\tNewImport: \"\",\n+\t\tOld: \"runtime.Cgocalls\",\n+\t\tNew: \"runtime.NumCgoCall\",\n+\t},\n+\t{\n+\t\tOldImport: \"runtime\",\n+\t\tNewImport: \"\",\n+\t\tOld: \"runtime.Goroutines\",\n+\t\tNew: \"runtime.NumGoroutine\",\n+\t},\n }\ndiff --git a/src/cmd/fix/go1rename_test.go b/src/cmd/fix/go1rename_test.go
index 0a7dcf46cf..02eaea6a54 100644
--- a/src/cmd/fix/go1rename_test.go
+++ b/src/cmd/fix/go1rename_test.go
@@ -18,6 +18,7 @@ import (\n \"crypto/des\"\n \"net/url\"\n \"os\"\n+\t\"runtime\"\n )\n \n var (\n@@ -29,6 +30,8 @@ var (\n _ = url.ParseWithReference\n _ = url.ParseRequest\n _ = os.Exec\n+\t_ = runtime.Cgocalls\n+\t_ = runtime.Goroutines\n )\n `,\n \t\tOut: `package main\n@@ -37,6 +40,7 @@ import (\n \"crypto/aes\"\n \"crypto/cipher\"\n \"net/url\"\n+\t\"runtime\"\n \"syscall\"\n )\n \n@@ -49,6 +53,8 @@ var (\n _ = url.Parse\n _ = url.ParseRequestURI\n _ = syscall.Exec\n+\t_ = runtime.NumCgoCall\n+\t_ = runtime.NumGoroutine\n )\n `,\n \t},\n```
## 変更の背景
この変更は、Go言語がバージョン1.0の安定版リリースに向けて進められていた時期に行われました。Go 1の目標の一つは、将来のバージョンアップにおいても既存のコードが動作し続けるように、APIの安定性を確保することでした。しかし、開発段階ではAPIの名称や構造が変更されることがあり、特に`runtime`パッケージのような低レベルな機能を提供する部分では、より明確で一貫性のある命名規則が求められました。
`runtime.Cgocalls`と`runtime.Goroutines`という関数名は、それぞれCgo呼び出しの数とゴルーチンの数を返すことを意図していましたが、Goの標準ライブラリ全体で「数を数える」関数には`Num`プレフィックスを付けるという命名規則が確立されつつありました。例えば、`runtime.NumCPU`や`runtime.NumGoroutine`(このコミットで変更される前の`Goroutines`の新しい名前)などです。
このような背景から、既存のコードベースが新しいAPIに容易に移行できるよう、`cmd/fix`ツールにこれらのリネームルールを追加する必要がありました。`cmd/fix`は、Goのバージョンアップに伴う破壊的変更を自動的に修正するためのツールであり、開発者が手動で大量のコードを修正する手間を省くことを目的としています。このコミットは、Go 1の互換性保証の一環として、`runtime`パッケージのAPIをよりGoらしい命名規則に合わせるための重要なステップでした。
## 前提知識の解説
### Go 1 互換性保証
Go言語は、バージョン1.0のリリース時に「Go 1 Compatibility Promise」という重要な方針を打ち出しました。これは、Go 1でリリースされたAPIは、Go 1.xのすべてのリリースにおいて互換性が維持されることを保証するものです。つまり、Go 1で書かれたプログラムは、Go 1.1、Go 1.2といった将来のバージョンでも、特別な修正なしにコンパイル・実行できることを意味します。この保証は、Go言語が実用的なプログラミング言語として広く採用される上で非常に重要な要素となりました。
### `cmd/fix` ツール
`cmd/fix`は、Go言語の標準ツールチェーンに含まれるコマンドラインツールです。その主な目的は、Go言語のバージョンアップに伴うAPIの変更や構文の変更によって、既存のGoプログラムがコンパイルできなくなったり、意図しない動作をしたりするのを自動的に修正することです。
Go 1の互換性保証は、Go 1リリース後のAPIの安定性を約束するものですが、Go 1リリース前の開発段階では、より良いAPI設計や言語機能の改善のために、既存のAPIが変更されることがありました。`cmd/fix`は、このような過渡期において、開発者が古いGoバージョンで書かれたコードを新しいGoバージョンで動作するように、半自動的に更新する手段を提供しました。
`cmd/fix`は、Goのソースコードを解析し、定義されたリネームルールや変換ルールに基づいて、コードを書き換えます。例えば、関数名の変更、パッケージパスの変更、構文の変更などに対応できます。開発者は`go tool fix`コマンドを実行するだけで、多くの互換性問題を解決できました。
### `runtime` パッケージ
`runtime`パッケージは、Goプログラムのランタイムシステムと直接対話するための低レベルな機能を提供するGoの標準ライブラリです。これには、ガベージコレクション、ゴルーチン管理、スケジューリング、Cgo(GoとC言語の相互運用)関連の統計情報など、Goプログラムの実行環境に関する情報や制御機能が含まれます。
このパッケージの関数は、通常、Goプログラムの内部動作を監視したり、特定のランタイム動作を微調整したりするために使用されます。そのため、他の高レベルなパッケージと比較して、APIの変更がより慎重に行われる傾向があります。
### `runtime.Cgocalls` と `runtime.Goroutines` (旧API)
* **`runtime.Cgocalls`**: この関数は、GoプログラムがCgoを介してC言語の関数を呼び出した回数を返していました。Cgoは、GoプログラムからCライブラリを利用するためのメカニズムであり、外部のCコードとの連携が必要な場合に用いられます。
* **`runtime.Goroutines`**: この関数は、現在実行中のゴルーチンの数を返していました。ゴルーチンはGo言語の軽量な並行処理単位であり、Goプログラムの並行性を実現する上で中心的な役割を果たします。
これらの関数は、Go 1リリース前の開発段階で存在していましたが、GoのAPI命名規則の統一化の一環として、より明確な名前へと変更されることになりました。
### `runtime.NumCgoCall` と `runtime.NumGoroutine` (新API)
* **`runtime.NumCgoCall`**: `runtime.Cgocalls`の新しい名前です。`Num`プレフィックスは「数」を意味し、この関数がCgo呼び出しの総数を返すことをより明確に示しています。
* **`runtime.NumGoroutine`**: `runtime.Goroutines`の新しい名前です。同様に`Num`プレフィックスが追加され、現在存在するゴルーチンの総数を返すことを明確にしています。
これらの新しい名前は、Goの標準ライブラリ全体で採用されている命名規則(例: `runtime.NumCPU`)と一貫性があり、APIの可読性と予測可能性を向上させます。
## 技術的詳細
このコミットは、`cmd/fix`ツールの内部で利用されるリネームルールを定義する`src/cmd/fix/go1rename.go`ファイルと、そのリネームルールが正しく機能するかを検証するためのテストケースを定義する`src/cmd/fix/go1rename_test.go`ファイルに変更を加えています。
### `go1rename.go` の変更
`go1rename.go`ファイルには、Go 1リリースに向けて変更されたAPIの旧名と新名をマッピングする`go1renameReplace`という`[]rename`型のスライスが定義されています。このスライスに新しい`rename`構造体が2つ追加されました。
追加された`rename`構造体は以下の通りです。
1. **`runtime.Cgocalls` から `runtime.NumCgoCall` への変更ルール**:
```go
{
OldImport: "runtime",
NewImport: "", // 同じパッケージ内でのリネームのためNewImportは空
Old: "runtime.Cgocalls",
New: "runtime.NumCgoCall",
},
```
このエントリは、`runtime`パッケージ内で`Cgocalls`という識別子が見つかった場合、それを`NumCgoCall`に置き換えることを`cmd/fix`に指示します。`OldImport`が指定されているため、`runtime`パッケージからのインポートがある場合にのみこのルールが適用されます。
2. **`runtime.Goroutines` から `runtime.NumGoroutine` への変更ルール**:
```go
{
OldImport: "runtime",
NewImport: "", // 同じパッケージ内でのリネームのためNewImportは空
Old: "runtime.Goroutines",
New: "runtime.NumGoroutine",
},
```
同様に、このエントリは`runtime`パッケージ内で`Goroutines`という識別子が見つかった場合、それを`NumGoroutine`に置き換えることを`cmd/fix`に指示します。
これらのルールが`go1renameReplace`に追加されることで、`cmd/fix`はGo 1リリース前のコードベースをスキャンし、これらの古い関数名を使用している箇所を自動的に新しい関数名に書き換えることができるようになります。
### `go1rename_test.go` の変更
`go1rename_test.go`ファイルには、`cmd/fix`のリネーム機能が期待通りに動作するかを検証するためのテストケースが含まれています。このコミットでは、新しいリネームルールに対応するために、既存のテストデータに`runtime`パッケージ関連の記述が追加されました。
具体的には、テスト入力となるGoコードスニペット(`In`フィールド)に、古い`runtime.Cgocalls`と`runtime.Goroutines`の使用例が追加されています。そして、期待される出力となるGoコードスニペット(`Out`フィールド)には、それらが新しい`runtime.NumCgoCall`と`runtime.NumGoroutine`に正しく変換された形が記述されています。
```go
// In: テスト入力となるGoコード
import (
// ...
"runtime" // runtimeパッケージのインポートが追加
)
var (
// ...
_ = runtime.Cgocalls // 古い関数名の使用例
_ = runtime.Goroutines // 古い関数名の使用例
)
// Out: 期待されるGoコード出力
import (
// ...
"runtime" // runtimeパッケージのインポートが維持される
"syscall" // 既存のos.Execからsyscall.Execへの変更に関連
)
var (
// ...
_ = runtime.NumCgoCall // 新しい関数名に変換
_ = runtime.NumGoroutine // 新しい関数名に変換
)
このテストケースの追加により、cmd/fix
がruntime
パッケージのリネームを正確に処理できることが保証されます。テストは、cmd/fix
が単に文字列置換を行うのではなく、Goの構文ツリーを解析して意味的に正しいリネームを行うことを確認します。例えば、runtime
パッケージをインポートしている場合にのみリネームが適用されることなどが検証されます。
コアとなるコードの変更箇所
diff --git a/src/cmd/fix/go1rename.go b/src/cmd/fix/go1rename.go
index 5d12f18701..2995880c30 100644
--- a/src/cmd/fix/go1rename.go
+++ b/src/cmd/fix/go1rename.go
@@ -56,4 +56,16 @@ var go1renameReplace = []rename{\n \tOld: \"os.Exec\",\n \tNew: \"syscall.Exec\",\n },\n+\t{\n+\t\tOldImport: \"runtime\",\n+\t\tNewImport: \"\",\n+\t\tOld: \"runtime.Cgocalls\",\n+\t\tNew: \"runtime.NumCgoCall\",\n+\t},\n+\t{\n+\t\tOldImport: \"runtime\",\n+\t\tNewImport: \"\",\n+\t\tOld: \"runtime.Goroutines\",\n+\t\tNew: \"runtime.NumGoroutine\",\n+\t},\n }\
diff --git a/src/cmd/fix/go1rename_test.go b/src/cmd/fix/go1rename_test.go
index 0a7dcf46cf..02eaea6a54 100644
--- a/src/cmd/fix/go1rename_test.go
+++ b/src/cmd/fix/go1rename_test.go
@@ -18,6 +18,7 @@ import (\n \"crypto/des\"\n \"net/url\"\n \"os\"\n+\t\"runtime\"\n )\n \n var (\n@@ -29,6 +30,8 @@ var (\n _ = url.ParseWithReference\n _ = url.ParseRequest\n _ = os.Exec\n+\t_ = runtime.Cgocalls\n+\t_ = runtime.Goroutines\n )\n `,\n \t\tOut: `package main\n@@ -37,6 +40,7 @@ import (\n \"crypto/aes\"\n \"crypto/cipher\"\n \"net/url\"\n+\t\"runtime\"\n \"syscall\"\n )\n \n@@ -49,6 +53,8 @@ var (\n _ = url.Parse\n _ = url.ParseRequestURI\n _ = syscall.Exec\n+\t_ = runtime.NumCgoCall\n+\t_ = runtime.NumGoroutine\n )\n `,\n \t},\
コアとなるコードの解説
src/cmd/fix/go1rename.go
このファイルは、cmd/fix
ツールがGo 1互換性のために実行するリネームルールを定義しています。追加されたコードは、go1renameReplace
という[]rename
型のグローバル変数に2つの新しいrename
構造体を追加しています。
rename
構造体: この構造体は、リネームの元となる情報と変換後の情報を保持します。OldImport
: 変更対象の識別子が含まれる古いパッケージのパス。runtime
パッケージはGoの組み込みパッケージであり、パスは"runtime"です。NewImport
: 変更後の識別子が含まれる新しいパッケージのパス。今回は同じruntime
パッケージ内でのリネームなので空文字列""
です。Old
: 古い識別子の完全修飾名(例:runtime.Cgocalls
)。New
: 新しい識別子の完全修飾名(例:runtime.NumCgoCall
)。
この追加により、cmd/fix
はGoソースコードを解析する際に、これらの定義されたルールに基づいて古い関数名を新しい関数名に自動的に置き換えることができるようになります。これは、Go 1への移行をスムーズにするための重要な自動化機能です。
src/cmd/fix/go1rename_test.go
このファイルは、go1rename.go
で定義されたリネームルールが正しく適用されることを検証するためのテストコードです。go1rename_test.go
内のrenameTests
という変数に、新しいテストケースが追加されています。
各テストケースは、In
フィールドにリネーム前のGoコードスニペットを、Out
フィールドにリネーム後の期待されるGoコードスニペットを文字列として保持しています。
このコミットでは、既存のテストケースにruntime
パッケージのCgocalls
とGoroutines
の使用例がIn
に追加され、それらがNumCgoCall
とNumGoroutine
に正しく変換されることがOut
で示されています。
テストフレームワークは、In
のコードをcmd/fix
に渡し、その出力がOut
のコードと一致するかどうかを検証します。これにより、cmd/fix
がruntime
パッケージの関数名変更を正確に処理し、開発者が安心してツールを使用できることが保証されます。
関連リンク
- Go 1 Compatibility Promise: Go言語の互換性保証に関する公式ドキュメント。
cmd/fix
のドキュメント: Goの公式ドキュメントにおけるfix
コマンドの説明。runtime
パッケージのドキュメント: Goの公式ドキュメントにおけるruntime
パッケージの説明。- Go 1 Release Notes (Go 1.0): Go 1.0のリリースノートには、APIの変更点や
cmd/fix
の役割について言及がある可能性があります。
参考にした情報源リンク
- Go言語の公式ドキュメント (go.dev)
- GitHubのGoリポジトリのコミット履歴
- Go言語の
cmd/fix
ツールのソースコード - Go言語の
runtime
パッケージのソースコード - Go 1 Compatibility Promiseに関する情報源