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

[インデックス 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シンボルの多重定義または未定義の問題を解決している点にあります。

  1. 既存のRunemaxの隠蔽: #define Runemax Plan9Runemax この行は、libc.hをインクルードする直前に挿入されています。これにより、プリプロセッサは、この行以降に現れるすべてのRunemaxという文字列をPlan9Runemaxという文字列に置き換えます。もしPlan 9の64ビット版libcが既にRunemaxを定義していたとしても、その定義はPlan9Runemaxとして扱われるため、Go言語のコードが独自のRunemaxを定義する際に名前の衝突を避けることができます。

  2. libc.hのインクルード: #include "/sys/include/libc.h" この行で、Plan 9のシステム標準のlibc.hヘッダーファイルがインクルードされます。このヘッダーファイルには、システムが提供するRunemax(もし存在すれば、それはPlan9Runemaxとして扱われる)やその他の重要な定義が含まれています。

  3. 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言語のビルドプロセスの一貫性を保っています。

関連リンク

参考にした情報源リンク