Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12677] ファイルの概要

コミット

このコミットは、Go言語のビルドプロセスにおいて、意図しないAPI変更を検出するメカニズムを導入するものです。具体的には、api/go1.txtという新しいファイルを導入し、現在のGo APIの定義をこのファイルに固定します。これにより、将来的にAPIに変更が加えられた場合、このgo1.txtファイルも更新する必要が生じます。run.bashスクリプト(ただし、make.bashやWindows環境では適用されない)が、ビルド時にこのgo1.txtファイルと現在のAPI定義を比較し、偶発的なAPI変更を検知するようになります。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f69132d7ad89c6507af6079bd75d2fe50f7f7fe8

元コミット内容

commit f69132d7ad89c6507af6079bd75d2fe50f7f7fe8
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Sat Mar 17 11:20:46 2012 -0700

    build: catch API changes during build

    Adds new file api/go1.txt, locking down the current API.
    Any changes to the API will need to update that file.

    run.bash (but not make.bash, or Windows) will check for
    accidental API changes.

    R=golang-dev, dsymonds, rsc
    CC=golang-dev
    https://golang.org/cl/5820070

変更の背景

Go言語は、その安定性と後方互換性を非常に重視しています。特にGo 1のリリース以降、Go 1の仕様に準拠して書かれたプログラムは、将来のGoのバージョンアップ(例: Go 1.1, Go 1.2など)においても、変更なしでコンパイルおよび実行できることが保証されています。この強力な互換性保証を維持するためには、Goの公開API(Application Programming Interface)が意図せず変更されることを防ぐ仕組みが必要でした。

このコミットは、Go 1のリリースを控えた時期に行われたもので、Go 1のAPI安定性保証を技術的に裏付けるための重要なステップです。開発者がGoの標準ライブラリや言語仕様に影響を与える変更を加える際に、それが既存のAPIを破壊しないことを自動的に検証する手段を提供することで、偶発的なAPI変更を防ぎ、Goエコシステムの健全性を保つことを目的としています。

前提知識の解説

  • Go 1 Compatibility Promise (Go 1 互換性保証): Go言語の最も重要な設計原則の一つに、Go 1以降のバージョンにおける後方互換性の強力な保証があります。これは、Go 1で書かれたコードが、Goの将来のバージョンでも動作し続けることを意味します。この保証は、Go言語が大規模なプロジェクトや長期的なメンテナンスが必要なシステムで採用される上で極めて重要です。この保証を維持するためには、APIの変更を厳密に管理する必要があります。
  • API (Application Programming Interface): ソフトウェアコンポーネントが互いに通信するために使用する一連の定義、プロトコル、ツールです。Go言語においては、標準ライブラリの関数、型、メソッドなどが公開APIを構成します。APIが変更されると、そのAPIを利用している既存のコードが動作しなくなる(破壊的変更)可能性があります。
  • go tool api: Goツールチェーンの一部として提供されるコマンドで、Goのソースコードから公開APIの情報を抽出し、特定の形式で出力する機能を持っています。このツールは、APIの変更を追跡し、互換性を検証するために使用されます。
  • run.bash: Goプロジェクトのルートディレクトリにあるシェルスクリプトで、Goのビルド、テスト、その他の開発タスクを実行するために使用されます。このスクリプトは、開発者がGoのコードベースに変更を加えた際に、様々なチェックを自動的に実行する役割を担っています。

技術的詳細

このコミットの核心は、Goの公開APIをテキストファイル(api/go1.txt)として「凍結」し、その後のビルドプロセスでこの凍結されたAPI定義と現在のAPI定義を比較することで、APIの変更を自動的に検出する仕組みを導入した点にあります。

  1. api/go1.txtの導入: このファイルは、Go 1リリース時点でのGo標準ライブラリのすべての公開API要素(パッケージ、定数、変数、関数、メソッド、型、構造体フィールドなど)を、特定のフォーマットで列挙したものです。各行はpkg <パッケージ名>, <要素の種類> <要素名> ...のような形式で記述されており、GoのAPIの「スナップショット」として機能します。このファイルは、GoのAPIチェッカー(go tool api)が生成する出力と一致するように設計されています。
  2. src/cmd/api/goapi.goの変更: このGoプログラムは、Goのソースコードを解析し、その公開APIを抽出して標準出力に出力する役割を担っています。このコミットでは、goapi.goapi/go1.txtの形式に沿った出力を生成するように調整されました。これにより、go tool apiコマンドがgo1.txtの内容を生成・検証できるようになります。
  3. src/run.bashの変更: run.bashスクリプトに、go tool apiコマンドを利用したAPI変更のチェックが組み込まれました。具体的には、ビルドプロセス中に現在のGoソースコードからAPI情報を抽出し、それをapi/go1.txtの内容と比較します。もし両者に差異があれば、それはAPIが変更されたことを意味し、ビルドプロセスがエラーを発生させて停止します。これにより、開発者は意図しないAPIの破壊的変更をコミットする前に気づくことができます。

この仕組みは、GoのAPI互換性保証を強制するための重要なガードレールとして機能します。APIに変更を加える必要がある場合、開発者はまずその変更がGoの互換性ポリシーに違反しないことを確認し、その後、api/go1.txtファイルを意図的に更新する必要があります。この手動での更新プロセスは、API変更が慎重に検討され、承認されたものであることを保証します。

コアとなるコードの変更箇所

このコミットで変更された主要なファイルは以下の3つです。

  1. api/go1.txt:

    • 新規追加されたファイル。
    • Go 1の公開APIの定義が網羅的に記述されています。ファイルの内容は非常に長く、Go標準ライブラリのほぼ全ての公開要素が列挙されています。
  2. src/cmd/api/goapi.go:

    • goapi.goは、GoのソースコードからAPI情報を抽出するプログラムです。
    • 変更点としては、API情報の出力形式がapi/go1.txtの形式に合うように調整されました。具体的には、出力されるAPI要素の順序や表現が統一され、go1.txtとの比較が容易になるように改善されています。
  3. src/run.bash:

    • Goプロジェクトのビルドとテストを実行するメインスクリプトです。
    • このスクリプトに、go tool apiコマンドを使用してAPIの変更をチェックするロジックが追加されました。
    • 追加されたロジックは、go tool apiの出力とapi/go1.txtの内容を比較し、差異があればエラーとして報告します。

コアとなるコードの解説

api/go1.txtは、GoのAPIの「期待される状態」を定義する参照ファイルです。このファイルは、Goの標準ライブラリに含まれるすべての公開された型、関数、メソッド、定数、変数などを、特定の正規化された形式で記述しています。例えば、pkg archive/tar, func NewReader(io.Reader) *Reader のような行は、archive/tarパッケージにNewReaderという関数が存在し、そのシグネチャがfunc NewReader(io.Reader) *Readerであることを示しています。

src/cmd/api/goapi.goは、Goのコンパイラが使用する内部ツールであり、Goのソースコードを静的に解析して、その公開APIをこのgo1.txtと同じ形式で出力する機能を提供します。このツールは、Goのビルドシステムによって呼び出され、現在のソースコードのAPI定義を動的に生成します。

src/run.bashにおける変更は、このgoapi.goツールとgo1.txtファイルを連携させる部分です。スクリプトは以下の手順を実行します(簡略化):

  1. go tool apiコマンドを実行し、現在のGoソースコードからAPI定義を抽出します。この出力は一時ファイルに保存されます。
  2. 一時ファイルに保存された現在のAPI定義と、リポジトリにコミットされているapi/go1.txtの内容を比較します。
  3. もし両者に差分があれば、それはAPIが変更されたことを意味します。この場合、run.bashはエラーを返し、ビルドプロセスを停止させます。

この自動チェックにより、開発者はAPIの変更が意図的であり、かつgo1.txtに適切に反映されていることを確認するよう強制されます。これにより、GoのAPI互換性保証が開発ワークフローに組み込まれ、偶発的な破壊的変更が防がれます。

関連リンク

  • Go 1 and the Future of Go Programs: https://go.dev/doc/go1compat
  • Go API Checker (go tool api): GoのソースコードからAPIを抽出するツールの詳細については、Goの公式ドキュメントやソースコードを参照してください。

参考にした情報源リンク