[インデックス 15025] ファイルの概要
このコミットは、Go言語のランタイムがPlan 9オペレーティングシステム上で動作する際の互換性問題を解決するために、include/plan9/libc.h
ファイルに対して行われた変更を記述しています。具体的には、Runemax
というシンボルの定義に関する問題に対処しています。
コミット
commit 660c4cde9ce10ff158fc76bf8f75c9d0e880d346
Author: Akshat Kumar <seed@mail.nanosouffle.net>
Date: Wed Jan 30 07:56:08 2013 -0800
include: Plan 9: hide any previous definition of Runemax
Runemax is already defined in libc on 64-bit version of
Plan 9, but is not defined on other versions.
To accommodate, we make sure to rename any previous
instance of Runemax and re-define it subsequently.
R=rsc, ality, rminnich
CC=golang-dev
https://golang.org/cl/7232059
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/660c4cde9ce10ff158fc76bf8f75c9d0e880d346
元コミット内容
このコミットの目的は、「Plan 9において、既存のRunemax
の定義を隠蔽する」ことです。
その理由は、Plan 9の64ビット版libcにはRunemax
が既に定義されている一方で、他のバージョンでは定義されていないためです。この差異に対応するため、既存のRunemax
のインスタンスをリネームし、その後で再定義するという手法が取られています。
変更の背景
Go言語は、クロスプラットフォーム対応を重視しており、様々なオペレーティングシステム上で動作するように設計されています。その中には、ベル研究所で開発された分散オペレーティングシステムであるPlan 9も含まれます。
このコミットが行われた当時、Go言語のPlan 9向けビルドにおいて、Runemax
というシンボルの定義に関する互換性の問題が存在していました。具体的には、Plan 9の64ビット版libc(C標準ライブラリ)にはRunemax
が既に定義されているにもかかわらず、他のPlan 9のバージョン(例えば32ビット版)ではこのシンボルが定義されていませんでした。
このような環境間の差異は、Go言語のコンパイル時に問題を引き起こす可能性があります。もしGo言語のコードがRunemax
を使用しようとした場合、64ビット版では二重定義エラーが発生し、32ビット版では未定義シンボルエラーが発生する可能性があります。このコミットは、この問題を解決し、Go言語がPlan 9の異なるバージョン間で一貫してビルドおよび実行できるようにすることを目的としています。
前提知識の解説
Plan 9 from Bell Labs
Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、ネットワーク透過性、ファイルシステム中心の設計、UTF-8の採用など、多くの革新的な概念を導入しました。Go言語の開発者の一部はPlan 9の開発にも携わっており、Go言語の設計思想にもPlan 9の影響が見られます。
libc (C標準ライブラリ)
libc
は、C言語の標準ライブラリであり、オペレーティングシステムの基本的な機能(メモリ管理、ファイルI/O、文字列操作など)を提供する関数の集合です。各オペレーティングシステムには、そのシステムに特化したlibc
の実装が存在します。Go言語のランタイムは、低レベルのシステムコールやC言語の関数を呼び出すために、これらのlibc
関数を利用することがあります。
Runemax
Runemax
は、Plan 9のシステムプログラミングにおいて、UTF-8エンコーディングにおけるルーン(Unicodeコードポイント)の最大バイト長を示す定数として使用されることがあります。UTF-8では、1つのルーンが1バイトから4バイトで表現されるため、Runemax
は通常4に設定されます。この定数は、文字エンコーディングの処理やバッファサイズの計算などで利用されます。
Cプリプロセッサディレクティブ (#define
, #undef
, #include
)
#define
: マクロを定義するために使用されます。シンボルを特定の値やコードスニペットに置き換えることができます。このコミットでは、Runemax
を一時的にPlan9Runemax
という別の名前にマッピングするために使用されています。#undef
: 以前に定義されたマクロの定義を解除するために使用されます。これにより、そのマクロ名が再び通常の識別子として扱われるようになります。このコミットでは、Runemax
のマッピングを解除し、元のRunemax
が再定義されることを可能にしています。#include
: 別のファイルのコンテンツを現在のファイルに挿入するために使用されます。通常、ヘッダーファイル(.h
ファイル)をインクルードして、関数宣言やマクロ定義などを利用可能にします。
技術的詳細
このコミットの核心は、Cプリプロセッサの機能を巧みに利用して、Runemax
シンボルの多重定義または未定義の問題を解決している点にあります。
-
既存の
Runemax
の隠蔽:#define Runemax Plan9Runemax
この行は、libc.h
をインクルードする直前に挿入されています。これにより、プリプロセッサは、この行以降に現れるすべてのRunemax
という文字列をPlan9Runemax
という文字列に置き換えます。もしPlan 9の64ビット版libcが既にRunemax
を定義していたとしても、その定義はPlan9Runemax
として扱われるため、Go言語のコードが独自のRunemax
を定義する際に名前の衝突を避けることができます。 -
libc.h
のインクルード:#include "/sys/include/libc.h"
この行で、Plan 9のシステム標準のlibc.h
ヘッダーファイルがインクルードされます。このヘッダーファイルには、システムが提供するRunemax
(もし存在すれば、それはPlan9Runemax
として扱われる)やその他の重要な定義が含まれています。 -
Runemax
の定義解除:#undef Runemax
libc.h
のインクルードが完了した後、この行が実行されます。これにより、先ほど設定したRunemax
からPlan9Runemax
へのマッピングが解除されます。この時点で、Go言語のコードは、自身の目的のためにRunemax
を適切に定義できるようになります。
この手法は、ヘッダーファイルのインクルード順序やマクロ定義のスコープを制御することで、異なる環境間でのシンボル名の衝突を回避し、Go言語のコードが期待通りに動作するようにするための一般的なC/C++プログラミングのイディオムです。
コアとなるコードの変更箇所
変更はinclude/plan9/libc.h
ファイルに対して行われています。
--- a/include/plan9/libc.h
+++ b/include/plan9/libc.h
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#define Runemax Plan9Runemax
#include "/sys/include/libc.h"
+#undef Runemax
#include "/sys/include/ctype.h"
enum
コアとなるコードの解説
-
#define Runemax Plan9Runemax
: この行は、libc.h
をインクルードする直前に追加されました。これにより、libc.h
内で定義されている可能性のあるRunemax
が、Plan9Runemax
という一時的な名前にリネームされます。これは、Go言語のコードが独自のRunemax
を定義する際に、システムが提供するRunemax
との名前の衝突を避けるための措置です。 -
#include "/sys/include/libc.h"
: この行は元々存在しており、Plan 9の標準Cライブラリのヘッダーファイルをインクルードしています。上記の#define
の影響により、このインクルードによって取り込まれるRunemax
の定義は、プリプロセッサによってPlan9Runemax
として扱われます。 -
#undef Runemax
: この行は、libc.h
のインクルード後に新しく追加されました。これは、Runemax
からPlan9Runemax
へのマッピングを解除します。これにより、この行以降のコードでは、Runemax
というシンボルが通常の識別子として扱われ、Go言語のコードが自身の目的のためにRunemax
を定義できるようになります。
この一連の操作により、Plan 9の異なるバージョン(64ビット版とそれ以外)でRunemax
の定義の有無が異なるという問題を、プリプロセッサレベルで吸収し、Go言語のビルドプロセスの一貫性を保っています。
関連リンク
- Go言語の公式ウェブサイト: https://golang.org/
- Plan 9 from Bell Labs: https://plan9.bell-labs.com/
- このコミットのGo CL (Code Review) ページ: https://golang.org/cl/7232059
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- C言語のプリプロセッサに関するドキュメント (例: GCC Preprocessor Directives): https://gcc.gnu.org/onlinedocs/cpp/
- Plan 9のドキュメントや関連情報 (Web検索結果に基づく)