[インデックス 18650] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるSolarisビルドの問題を修正するものです。具体的には、Solaris環境ではsyscall.Mmap
およびsyscall.Munmap
が定義されていないため、これらのシステムコールを使用するテストコードをSolarisビルドから除外するように変更されています。
コミット
commit f9b384f554143901ddf771214bfacf8041862f0c
Author: Dave Cheney <dave@cheney.net>
Date: Wed Feb 26 07:56:41 2014 +1100
syscall: fix solaris build
Solaris does not define syscall.{Mmap,Munmap}. Move the Mmap test to a new file and exclude solaris as discussed.
LGTM=aram
R=aram, mikioh.mikioh, iant
CC=golang-codereviews
https://golang.org/cl/68720043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f9b384f554143901ddf771214bfacf8041862f0c
元コミット内容
このコミットの元の内容は、syscall
パッケージのSolarisビルドに関する修正です。Solarisがsyscall.Mmap
とsyscall.Munmap
を定義していないため、Mmap
テストを新しいファイルに移動し、Solarisをそのテストのビルドから除外しています。
変更の背景
Go言語の標準ライブラリ、特にsyscall
パッケージは、オペレーティングシステム(OS)のシステムコールをGoプログラムから直接呼び出すためのインターフェースを提供します。システムコールはOSカーネルが提供する低レベルの機能であり、メモリ管理、ファイルI/O、プロセス制御など多岐にわたります。しかし、システムコールの具体的な実装や利用可能なシステムコールの種類は、OSによって大きく異なります。
このコミットの背景には、Goのsyscall
パッケージがSolarisオペレーティングシステム上でビルドされる際に発生した問題があります。syscall.Mmap
とsyscall.Munmap
は、メモリマップドファイル(memory-mapped file)や匿名メモリ領域を扱うためのシステムコールであり、Unix系OSでは一般的に利用されます。しかし、Solarisの特定のバージョンや構成では、Goのsyscall
パッケージが期待する形でこれらの関数が提供されていないか、あるいは異なるシグネチャやセマンティクスを持っている可能性がありました。
結果として、syscall_unix_test.go
ファイルに含まれていたTestMmap
関数がSolaris環境でビルドエラーを引き起こしていました。Goのビルドシステムは、特定のOSやアーキテクチャに特化したコードをコンパイルするために「ビルドタグ(build tags)」を使用します。この問題は、TestMmap
がSolarisを含むUnix系OS全般を対象とするビルドタグでコンパイルされていたために顕在化しました。
この修正は、Goのクロスプラットフォーム対応を維持しつつ、特定のOSの差異に起因するビルド問題を解決するための典型的なアプローチを示しています。
前提知識の解説
1. Go言語のsyscall
パッケージ
syscall
パッケージは、GoプログラムからOSのシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、Goのランタイムや標準ライブラリは、OS固有の機能にアクセスし、高性能なI/O、ネットワーク通信、プロセス管理などを実現しています。このパッケージはOSに強く依存するため、各OS(Linux, macOS, Windows, FreeBSD, Solarisなど)ごとに異なる実装を持っています。
2. mmap
とmunmap
システムコール
mmap
(memory map)は、ファイルやデバイスのメモリ領域をプロセスのアドレス空間にマッピングするためのシステムコールです。これにより、ファイルの内容を通常のメモリとしてアクセスできるようになり、ファイルI/Oの効率化や、プロセス間通信(IPC)の手段として利用されます。
munmap
は、mmap
によってマッピングされたメモリ領域をアンマッピング(解放)するためのシステムコールです。
これらのシステムコールは、Unix系OSにおいてメモリ管理の重要な要素であり、特に大規模なデータ処理や、共有メモリを必要とするアプリケーションで頻繁に利用されます。
3. Go言語のビルドタグ(Build Tags)
Go言語には、特定のファイルが特定の環境でのみコンパイルされるように制御するための「ビルドタグ」という仕組みがあります。これは、ソースファイルの先頭に// +build tag_name
のようなコメント行を記述することで実現されます。例えば、// +build linux
と書かれたファイルはLinux環境でのみコンパイルされ、// +build darwin dragonfly freebsd linux netbsd openbsd
と書かれたファイルはこれらのOSでのみコンパイルされます。
ビルドタグは、クロスプラットフォーム開発においてOS固有のコードを分離し、各プラットフォームに最適化されたバイナリを生成するために不可欠な機能です。
4. Solarisオペレーティングシステム
Solarisは、Sun Microsystems(現在はOracleが所有)によって開発されたUnix系のオペレーティングシステムです。高性能なサーバー環境やエンタープライズシステムで広く利用されてきました。他のUnix系OS(Linux, FreeBSDなど)と多くの共通点を持つ一方で、システムコールの実装やライブラリの提供方法には独自の差異が存在します。この差異が、Goのsyscall
パッケージのような低レベルなコードで問題を引き起こすことがあります。
技術的詳細
このコミットの技術的詳細は、GoのビルドシステムとOS固有のシステムコール実装の差異をどのように吸収するかという点に集約されます。
-
問題の特定:
syscall_unix_test.go
内のTestMmap
関数がSolaris環境でビルドエラーを引き起こしていました。これは、SolarisがGoのsyscall
パッケージが期待するMmap
およびMunmap
システムコールを定義していないためです。 -
既存のビルドタグ:
syscall_unix_test.go
は、以下のビルドタグを持っていました。// +build freebsd dragonfly darwin linux netbsd openbsd solaris
このタグは、このファイルがFreeBSD, Dragonfly BSD, Darwin (macOS), Linux, NetBSD, OpenBSD, そしてSolarisの各OSでコンパイルされるべきであることを示しています。
TestMmap
がSolarisで問題を起こすにもかかわらず、このタグによってSolarisでもコンパイル対象となっていたことが問題の根源です。 -
解決策:
- テストの分離:
TestMmap
関数をsyscall_unix_test.go
から切り離し、mmap_unix_test.go
という新しいファイルに移動しました。 - 新しいビルドタグの適用: 新しいファイル
mmap_unix_test.go
には、Solarisを除外したビルドタグを適用しました。
これにより、// +build darwin dragonfly freebsd linux netbsd openbsd
TestMmap
はSolaris環境ではコンパイルされなくなり、ビルドエラーが解消されます。 - 既存ファイルのビルドタグの維持:
syscall_unix_test.go
のビルドタグは変更されず、引き続きSolarisを含むすべての指定されたUnix系OSでコンパイルされます。これは、TestMmap
以外のテスト関数はSolarisでも問題なく動作するためです。
- テストの分離:
このアプローチにより、Goのテストスイートは、mmap
/munmap
をサポートするプラットフォームでは引き続きこれらのシステムコールのテストを実行しつつ、サポートしない(または異なる実装を持つ)Solarisではビルドエラーを回避できるようになります。これは、Goのクロスプラットフォーム開発における一般的なパターンであり、OS固有のAPIの差異を適切に管理するための効果的な方法です。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
-
src/pkg/syscall/mmap_unix_test.go
(新規作成)TestMmap
関数がこのファイルに移動されました。- ファイルの先頭に以下のビルドタグが追加されました。
これにより、このテストファイルはSolarisではコンパイルされなくなります。// +build darwin dragonfly freebsd linux netbsd openbsd
-
src/pkg/syscall/syscall_unix_test.go
(変更)- 既存の
TestMmap
関数がこのファイルから削除されました。 - ファイルのビルドタグは変更されていません。
- 既存の
コアとなるコードの解説
src/pkg/syscall/mmap_unix_test.go
(新規作成)
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd
package syscall_test
import (
"syscall"
"testing"
)
func TestMmap(t *testing.T) {
// syscall.Mmapを呼び出して匿名メモリ領域をマップする
// -1: ファイルディスクリプタ (匿名マップのため無視される)
// 0: オフセット (匿名マップのため無視される)
// syscall.Getpagesize(): マップするサイズ (OSのページサイズ)
// syscall.PROT_NONE: メモリ保護 (アクセス不可)
// syscall.MAP_ANON|syscall.MAP_PRIVATE: 匿名かつプライベートなマップ
b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatalf("Mmap: %v", err) // エラーが発生したらテスト失敗
}
// マップしたメモリ領域を解放する
if err := syscall.Munmap(b); err != nil {
t.Fatalf("Munmap: %v", err) // エラーが発生したらテスト失敗
}
}
この新しいファイルは、syscall.Mmap
とsyscall.Munmap
の基本的な機能が期待通りに動作するかを検証するテストを含んでいます。重要なのは、ファイルの先頭にある+build
タグです。このタグにより、このテストファイルはdarwin
, dragonfly
, freebsd
, linux
, netbsd
, openbsd
の各OSでのみコンパイルされ、Solarisではコンパイル対象から外されます。これにより、SolarisでMmap
やMunmap
が定義されていないことによるビルドエラーが回避されます。
src/pkg/syscall/syscall_unix_test.go
(変更)
--- a/src/pkg/syscall/syscall_unix_test.go
+++ b/src/pkg/syscall/syscall_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build freebsd dragonfly darwin linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package syscall_test
@@ -77,16 +77,6 @@ func TestFcntlFlock(t *testing.T) {
}\n }\n \n-func TestMmap(t *testing.T) {\n-\tb, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)\n-\tif err != nil {\n-\t\tt.Fatalf(\"Mmap: %v\", err)\n-\t}\n-\tif err := syscall.Munmap(b); err != nil {\n-\t\tt.Fatalf(\"Munmap: %v\", err)\n-\t}\n-}\n-\n // TestPassFD tests passing a file descriptor over a Unix socket.\n //
このファイルからはTestMmap
関数が削除されました。これにより、このファイルはSolarisを含むすべての指定されたUnix系OSで引き続きコンパイルされますが、Mmap
関連のテストは含まれなくなります。この変更は、テストコードの責任を分割し、OS固有の差異をビルドタグによって適切に管理するというGoの設計思想に沿ったものです。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall mmap(2)
man page (Linux): https://man7.org/linux/man-pages/man2/mmap.2.html- Go言語のビルドタグに関する公式ドキュメント: https://go.dev/cmd/go/#hdr-Build_constraints
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (このコミットのCL: https://golang.org/cl/68720043)
参考にした情報源リンク
- Go言語の公式ドキュメント
- Unix系OSのシステムコールに関する一般的な知識
- Goのソースコードリポジトリ
- Gerrit上のコードレビューコメント (コミットメッセージに記載のCLリンクからアクセス可能)
man mmap
などのシステムコールに関するmanページ