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

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

このコミットは、Go言語の標準ライブラリであるosパッケージにおける、WindowsおよびPlan9ビルドの修正に関するものです。具体的には、テストでオーバーライドされるlstat変数の定義位置が変更されています。

コミット

commit 8378804640942aa165b8d591b4287d4f4148e484
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Thu Aug 8 11:13:00 2013 -0700

    os: fix windows and plan9 builds
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/12519046

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

https://github.com/golang/go/commit/8378804640942aa165b8d591b4287d4f4148e484

元コミット内容

os: fix windows and plan9 builds

このコミットは、osパッケージがWindowsおよびPlan9環境で正しくビルドされるようにするための修正です。

変更の背景

Go言語はクロスプラットフォーム対応を重視しており、osパッケージはその中核をなすものです。ファイルシステム操作など、OSに依存する機能は、各プラットフォーム向けに異なる実装を持つことがあります。Goでは、ビルドタグ(build tags)を使用して、特定のOSやアーキテクチャ向けのコードを条件付きでコンパイルする仕組みがあります。

このコミット以前は、lstatという変数がsrc/pkg/os/file_unix.go内で定義されていました。lstatは、Lstat関数(シンボリックリンクを辿らずにファイルの情報を取得する関数)をテスト目的でオーバーライドするために使用される変数です。しかし、file_unix.goというファイル名が示すように、このファイルはUnix系のシステム(Linux, macOSなど)向けにビルドされるコードを含んでいます。

WindowsやPlan9のような非Unix系システムでは、file_unix.goはコンパイルされません。そのため、これらの環境でosパッケージをビルドしようとすると、lstat変数が未定義であるというコンパイルエラーが発生していました。これは、lstat変数がテスト目的で必要とされるにもかかわらず、その定義が特定のプラットフォームに限定されていたためです。

この問題を解決するため、lstat変数の定義を、すべてのプラットフォームで共通してコンパイルされるsrc/pkg/os/file.goに移動する必要がありました。これにより、WindowsやPlan9を含むすべての環境でlstatが利用可能となり、ビルドエラーが解消されます。

前提知識の解説

Go言語のosパッケージ

osパッケージは、Goプログラムがオペレーティングシステムと対話するための基本的な機能を提供します。これには、ファイルシステム操作(ファイルの読み書き、ディレクトリの作成など)、プロセス管理、環境変数へのアクセスなどが含まれます。OSに依存する機能が多いため、内部的には各OS向けの特定の実装(例: file_unix.go, file_windows.go)を持っています。

Lstat関数

os.Lstat(name string) (fi FileInfo, err error)関数は、指定されたパスnameのファイルまたはディレクトリに関する情報を返します。Stat関数と似ていますが、Lstatはパスがシンボリックリンクである場合、そのシンボリックリンク自体の情報を返し、リンク先のファイルの情報は辿りません。これは、シンボリックリンクのプロパティ(例えば、リンク先のパス)を検査する際に重要です。

ビルドタグ (Build Tags)

Go言語では、ソースコードファイルに特別なコメント行を追加することで、そのファイルが特定のビルド条件(OS、アーキテクチャ、Goのバージョンなど)が満たされた場合にのみコンパイルされるように指定できます。これをビルドタグと呼びます。例えば、// +build unixという行がファイルの先頭にある場合、そのファイルはUnix系のシステムでのみコンパイルされます。

テストにおける変数のオーバーライド

Goのテストでは、特定の関数や変数の振る舞いを一時的に変更して、テスト対象のコードが期待通りに動作するかを確認することがよくあります。このコミットで言及されているlstat変数は、まさにこの目的のために使用されています。Lstat関数の実際の呼び出しを、テスト中にモックやスタブに置き換えることで、ファイルシステムへの実際のアクセスなしにテストを実行できるようになります。これは、テストの速度向上や、特定のファイルシステムの状態をシミュレートする際に非常に有用です。

技術的詳細

このコミットの技術的な核心は、Goのビルドシステムと、テストにおける依存性の注入(Dependency Injection)のパターンを理解することにあります。

Goのビルドプロセスでは、ビルドタグに基づいて適切なソースファイルが選択され、コンパイルされます。src/pkg/os/file_unix.goは、そのファイル名と内容から、Unix系のシステムでのみコンパイルされることを意図しています。したがって、このファイル内で定義された変数や関数は、WindowsやPlan9のような非Unix系システムでは利用できません。

lstat変数は、Lstat関数の実装をテスト時に置き換えるためのメカニズムとして機能していました。これは、Goにおける依存性の注入の一種と見なすことができます。通常、Lstat関数はosパッケージの公開APIとして提供されますが、内部的にはlstatという変数を通じてその実装が参照されていました。テストコードは、このlstat変数を別の関数(例えば、モックのLstat実装)に一時的に設定することで、Lstatの振る舞いを制御できます。

しかし、lstatの定義がfile_unix.go内にあったため、WindowsやPlan9環境ではlstatがコンパイル時に存在せず、osパッケージのテストや、lstatに依存する他のコードがコンパイルエラーとなっていました。

このコミットは、lstat変数の定義をsrc/pkg/os/file.goに移動することで、この問題を解決しました。file.goは、osパッケージの汎用的なコードを含むファイルであり、すべてのプラットフォームでコンパイルされます。これにより、lstat変数はどのOS環境でも常に利用可能となり、クロスプラットフォームでのビルドが成功するようになりました。

この変更は、Goの標準ライブラリが、異なるOS環境での互換性とテスト容易性をどのように維持しているかを示す良い例です。特定のプラットフォームに依存する実装はビルドタグで分離しつつ、テストや共通のロジックで必要とされる共有可能な要素は、プラットフォーム非依存のファイルに配置するという設計原則が適用されています。

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

このコミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/os/file.go
  2. src/pkg/os/file_unix.go

src/pkg/os/file.go への追加

--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -238,3 +238,6 @@ func Open(name string) (file *File, err error) {
 func Create(name string) (file *File, err error) {
 	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 }
+
+// lstat is overridden in tests.
+var lstat = Lstat

src/pkg/os/file_unix.go からの削除

--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -149,9 +149,6 @@ func Lstat(name string) (fi FileInfo, err error) {
 	return fileInfoFromStat(&stat, name), nil
 }
 
-// lstat is overridden in tests.
-var lstat = Lstat
-
 func (f *File) readdir(n int) (fi []FileInfo, err error) {
 	dirName := f.name
 	if dirName == "" {

コアとなるコードの解説

このコミットの核心は、var lstat = Lstatという行の移動です。

  • 移動前 (src/pkg/os/file_unix.go): lstat変数はfile_unix.go内に定義されていました。このファイルはUnix系のシステムでのみコンパイルされるため、WindowsやPlan9などの非Unix系システムではlstatが定義されず、コンパイルエラーの原因となっていました。コメント// lstat is overridden in tests.が示すように、この変数はテスト時にLstat関数の振る舞いを変更するために使用されていました。

  • 移動後 (src/pkg/os/file.go): lstat変数はfile.goに移動されました。file.goosパッケージの汎用的な部分であり、すべてのGoがサポートするプラットフォームでコンパイルされます。これにより、lstat変数はどのOS環境でも常に利用可能となり、WindowsやPlan9を含むすべてのビルドが成功するようになりました。

この変更は、Goのクロスプラットフォーム開発における重要なプラクティスを示しています。すなわち、特定のOSに依存するコードはビルドタグで分離されたファイルに配置し、一方で、テストや共通のロジックで必要とされる共有可能な要素(この場合はテスト用のオーバーライド変数)は、プラットフォーム非依存のファイルに配置するという原則です。これにより、コードの再利用性を高め、異なる環境でのビルドの堅牢性を確保しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコードリポジトリ
  • Go言語のビルドタグに関する一般的な解説記事
  • Go言語におけるテストとモックに関する一般的な解説記事
  • Go言語のosパッケージの内部実装に関する情報