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

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

コミット

commit 8039683cef026edb88ae9dc6cd766feccdb40ff4
Author: Anthony Martin <ality@pbrane.org>
Date:   Tue Jan 31 18:15:42 2012 -0800

    gc: use octal escapes in mkopnames
    
    Plan 9's tr(1) doesn't accept the C-style escapes
    for tab and newline characters.  I was going to use
    the \xFF hexadecimal escapes but GNU tr(1) doesn't
    accept those.  It seems octal is the least common
    denominator.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5576079

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

https://github.com/golang/go/commit/8039683cef026edb88ae9dc6cd766feccdb40ff4

元コミット内容

このコミットは、Goコンパイラのガベージコレクタ(gc)関連のツールであるmkopnamesスクリプトにおいて、エスケープシーケンスの記述方法をCスタイル(\t, \n)から8進数表記(\011, \012)に変更するものです。

変更の理由は、Plan 9オペレーティングシステムに存在するtr(1)コマンドがCスタイルのエスケープシーケンスを認識しないためです。また、\xFFのような16進数エスケープもGNU tr(1)ではサポートされていないため、最も互換性の高い8進数表記が選択されました。

変更の背景

この変更の背景には、Go言語の開発環境が様々なオペレーティングシステム(特にUnix系システム)で動作することを保証する必要がありました。Goコンパイラのビルドプロセスの一部として使用されるmkopnamesスクリプトは、trコマンドを利用して文字列変換を行っています。

問題は、異なるtrコマンドの実装(特にPlan 9のtr(1)とGNU tr(1))が、特殊文字(タブや改行)のエスケープシーケンスの解釈において互換性がなかった点にあります。

  • Cスタイルのエスケープ (\t, \n): 多くのUnix系システムやプログラミング言語で一般的に使用されますが、Plan 9のtr(1)ではこれらが特殊文字として認識されませんでした。
  • 16進数エスケープ (\xFF): 特定のtr実装(例えば、一部のBSD系tr)でサポートされることがありますが、GNU tr(1)ではサポートされていませんでした。

このような状況下で、スクリプトの移植性を高め、異なる環境でのビルドエラーを防ぐために、すべての主要なtr実装で共通して解釈されるエスケープシーケンスを見つける必要がありました。その結果、8進数エスケープが「最小公分母(least common denominator)」として選ばれました。

前提知識の解説

trコマンド

tr(translate or delete characters)コマンドは、Unix系オペレーティングシステムで利用されるコマンドラインユーティリティです。標準入力から読み込んだ文字を変換または削除し、結果を標準出力に出力します。

基本的な構文は以下の通りです。

tr [オプション] SET1 [SET2]
  • SET1: 変換元または削除対象の文字セット。
  • SET2: 変換先の文字セット(変換の場合)。

例:

  • echo "hello world" | tr 'a-z' 'A-Z' → "HELLO WORLD" (小文字を大文字に変換)
  • echo "hello world" | tr -d 'o' → "hell wrld" ('o'を削除)

trコマンドは、特殊文字を表現するためにエスケープシーケンスを使用することがあります。

エスケープシーケンス

エスケープシーケンスは、プログラミング言語やコマンドラインツールにおいて、通常の方法では表現できない特殊な文字(改行、タブ、引用符など)を表現するために使用される文字の組み合わせです。通常、バックスラッシュ(\)で始まります。

主なエスケープシーケンスの形式には以下のようなものがあります。

  • Cスタイルのエスケープ:

    • \n: 改行 (Newline)
    • \t: タブ (Tab)
    • \r: キャリッジリターン (Carriage Return)
    • \\: バックスラッシュ自身 これらはC言語に由来し、多くのプログラミング言語やシェルで広く認識されています。
  • 8進数エスケープ:

    • \ooo: 3桁の8進数で文字コードを指定します。例えば、ASCIIの改行文字(LF)は10進数で10、8進数で12なので、\012と表現されます。タブ文字(HT)は10進数で9、8進数で11なので、\011と表現されます。 この形式は、特定の文字コードを直接指定する際に使用され、異なるシステム間での互換性を高めるために利用されることがあります。
  • 16進数エスケープ:

    • \xhh または \xhhhh: 2桁または4桁の16進数で文字コードを指定します。例えば、\x0Aは改行、\x09はタブです。 これも特定の文字コードを直接指定する際に使用されますが、すべてのツールやシステムでサポートされているわけではありません。

Plan 9とGNU tr

  • Plan 9: ベル研究所で開発された分散オペレーティングシステムです。その設計思想はUnixとは異なる部分が多く、付属するユーティリティ(tr(1)など)もUnixのそれとは異なる挙動を示すことがあります。特に、エスケープシーケンスの解釈は、より厳密であったり、特定の形式のみをサポートしたりする傾向があります。
  • GNU tr: GNUプロジェクトによって開発されたtrコマンドの実装です。Linuxディストリビューションなどで広く使用されており、多くの拡張機能や柔軟なエスケープシーケンスの解釈をサポートしています。しかし、このコミットの時点では、16進数エスケープをサポートしていなかったようです。

技術的詳細

このコミットの技術的な核心は、異なるtrコマンドの実装間でのエスケープシーケンスの互換性の問題に対処することです。

mkopnamesスクリプトは、Goコンパイラの内部で使用されるオペレーションコード(opcode)の名前を生成するために使用されます。このスクリプトは、go.hファイルから特定の行を抽出し、cpp(Cプリプロセッサ)で処理した後、sedtrコマンドを組み合わせて整形しています。

元のスクリプトでは、trコマンドでスペースを改行に、タブとカンマを削除するためにCスタイルのエスケープ\n\tを使用していました。

tr ' ' '\n' |
tr -d ' \t,' |

しかし、Plan 9のtr(1)\n\tを特殊なエスケープシーケンスとして解釈せず、リテラルのバックスラッシュと文字(例: \n)として扱ってしまいます。これにより、スクリプトが意図した通りに動作せず、ビルドエラーが発生する可能性がありました。

コミットの作者は、まず16進数エスケープ(例: \x0A\x09)の使用を検討しましたが、これはGNU tr(1)でサポートされていないことが判明しました。GNU trは広く使用されているため、これもまた互換性の問題を引き起こします。

そこで、最終的に選択されたのが8進数エスケープです。

  • 改行文字(LF)のASCIIコードは10進数で10、8進数で12です。したがって、\n\012に変換されます。
  • タブ文字(HT)のASCIIコードは10進数で9、8進数で11です。したがって、\t\011に変換されます。

8進数エスケープは、C言語の標準で定義されており、多くのUnix系ツールやシェルで広くサポートされています。これにより、Plan 9のtr(1)とGNU tr(1)の両方で正しく解釈されることが保証され、mkopnamesスクリプトのクロスプラットフォーム互換性が向上しました。

この変更は、Go言語のビルドシステムが多様な環境で堅牢に動作するための、細部にわたる配慮を示しています。

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

--- a/src/cmd/gc/mkopnames
+++ b/src/cmd/gc/mkopnames
@@ -14,8 +14,8 @@ echo '{'
 sed -n '/OXXX/,/OEND/p' go.h |
 	cpp |
 	sed 's!//.*!!; /^#/d'  |
-	tr ' ' '\n' |
-	tr -d ' \t,' |
+	tr ' ' '\012' |
+	tr -d ' \011,' |
 	grep . |
 	sort |
 	grep -v '^OEND$' |

コアとなるコードの解説

変更されたのは、src/cmd/gc/mkopnamesスクリプト内の2つのtrコマンドの行です。

  1. tr ' ' '\n'tr ' ' '\012':

    • この行は、入力ストリーム内のすべてのスペース文字(' ')を改行文字に変換します。
    • 元の'\n'はCスタイルの改行エスケープでしたが、Plan 9のtr(1)では正しく解釈されませんでした。
    • 変更後の'\012'は、ASCIIコードで改行(LF)を表す8進数エスケープです。これにより、Plan 9を含むより多くのtr実装で正しく改行として認識されるようになります。
  2. tr -d ' \t,'tr -d ' \011,':

    • この行は、入力ストリームからスペース(' ')、タブ('\t')、カンマ(',')の各文字を削除します。
    • 元の'\t'はCスタイルのタブエスケープでしたが、これもPlan 9のtr(1)では正しく解釈されませんでした。
    • 変更後の'\011'は、ASCIIコードでタブ(HT)を表す8進数エスケープです。これにより、Plan 9を含むより多くのtr実装で正しくタブとして認識され、削除されるようになります。

これらの変更により、mkopnamesスクリプトは、Plan 9を含む様々な環境でGoコンパイラをビルドする際に、期待通りに動作するようになりました。

関連リンク

参考にした情報源リンク

  • Web search results for "Plan 9 tr(1) escape sequences" (Stack Overflow, 9p.io)
  • trコマンドの一般的なドキュメントとエスケープシーケンスに関する情報