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

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

このコミットは、Goコンパイラのフロントエンドであるcmd/gcにおけるWindowsビルドの問題を修正するものです。具体的には、lex.cファイル内で定義されているcatcher関数が、Windows環境で未定義の参照エラー(undefined reference to noted)を引き起こしていた問題を解決します。

コミット

commit e0dee49688c1c767e2f81a4dab824ba0be36dcbb
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Thu Feb 13 20:15:19 2014 +0400

    cmd/gc: fix windows build
    c:\src\go\pkg\obj\windows_amd64\libgc.a(lex.o): In function `catcher':
    c:/src/go/src/cmd/gc/lex.c:181: undefined reference to `noted'
    
    LGTM=0intro
    R=0intro
    CC=golang-codereviews
    https://golang.org/cl/63270043

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

https://github.com/golang/go/commit/e0dee49688c1c767e2f81a4dab824ba0be36dcbb

元コミット内容

cmd/gc: fix windows build
c:\src\go\pkg\obj\windows_amd64\libgc.a(lex.o): In function `catcher':
c:/src/go/src/cmd/gc/lex.c:181: undefined reference to `noted'

LGTM=0intro
R=0intro
CC=golang-codereviews
https://golang.org/cl/63270043

変更の背景

このコミットは、Goコンパイラのcmd/gc(Goコンパイラのフロントエンド部分)をWindows環境でビルドする際に発生していたエラーを修正するために行われました。エラーメッセージ「undefined reference to noted」が示すように、lex.cファイル内のcatcher関数が、notedというシンボル(関数または変数)を参照しているにもかかわらず、そのシンボルがリンク時に見つからないという問題が発生していました。

この問題は、notedシンボルが特定のオペレーティングシステム(この場合はPlan 9)に特有のものであり、Windows環境では提供されていないために発生していました。Goコンパイラは、その歴史的経緯からPlan 9のツールチェインの影響を強く受けており、一部のコードがPlan 9固有のAPIを使用していることがあります。しかし、Windowsのような異なるOSでビルドする際には、これらのOS固有の依存関係が問題となることがあります。

開発者Dmitriy Vyukov氏によって報告されたこのビルドエラーは、Goコンパイラのクロスプラットフォーム対応における重要な課題の一つでした。

前提知識の解説

  • cmd/gc: Go言語のコンパイラのフロントエンド部分を指します。Goのソースコードを解析し、中間表現に変換する役割を担います。gcは「Go compiler」の略です。
  • lex.c: 字句解析(lexical analysis)を行うC言語のソースファイルです。字句解析は、ソースコードをトークン(単語のようなもの)の並びに分解するプロセスであり、コンパイラの最初の段階です。
  • Plan 9: ベル研究所で開発された分散オペレーティングシステムです。Go言語の開発者の一部はPlan 9の開発にも携わっており、Goの設計思想やツールチェインにはPlan 9の影響が色濃く残っています。特に、Goの初期のコンパイラやツールはPlan 9のツールチェインをベースにしていました。
  • noted関数: Plan 9オペレーティングシステムにおけるシステムコールの一つです。Plan 9では、プロセスがシグナルを受信した際に、そのシグナルを「通知(note)」として処理するメカニズムがあります。noted関数は、この通知メカニズムに関連する関数であり、通常はシグナルハンドラ内で使用され、通知を処理したことをシステムに伝える役割を果たします。Windowsにはこれに直接対応するAPIは存在しません。
  • 条件付きコンパイル (#ifdef, #endif): C/C++言語におけるプリプロセッサディレクティブです。#ifdef マクロ名から#endifまでのコードブロックは、指定されたマクロ名が定義されている場合にのみコンパイルされます。これにより、異なるプラットフォームや環境に応じて、特定のコードをコンパイルに含めたり除外したりすることができます。このコミットでは、PLAN9というマクロが定義されている場合にのみcatcher関数をコンパイルするように制御しています。

技術的詳細

この問題の根本原因は、src/cmd/gc/lex.c内のcatcher関数が、Plan 9固有のnoted関数を呼び出していたことにあります。Goコンパイラは、様々なオペレーティングシステムでビルドおよび実行できるように設計されていますが、一部の低レベルなコードやレガシーな部分では、特定のOSに依存するAPIが使用されていることがあります。

Windows環境でcmd/gcをビルドする際、リンカはnoted関数の定義を見つけることができませんでした。これは、Windowsの標準ライブラリやGoのランタイムライブラリにはnoted関数が含まれていないためです。結果として、リンカは未解決のシンボルエラーを報告し、ビルドが失敗していました。

このコミットによる修正は、非常にシンプルかつ効果的なものです。catcher関数全体を#ifdef PLAN9#endifで囲むことにより、PLAN9マクロが定義されている環境(つまりPlan 9環境)でのみcatcher関数がコンパイルされるように変更しました。

  • #ifdef PLAN9: この行は、プリプロセッサに対して、PLAN9というマクロが定義されているかどうかをチェックするように指示します。
  • void catcher(void *v, char *s) から noted(NDFLT); } まで: このコードブロックは、catcher関数の定義です。
  • #endif: この行は、#ifdefディレクティブで開始された条件付きコンパイルブロックの終わりを示します。

Windows環境ではPLAN9マクロは定義されていないため、catcher関数はコンパイル対象から除外されます。これにより、noted関数への未定義参照エラーが解消され、Windowsでのビルドが成功するようになります。

この修正は、catcher関数がWindows環境では不要であるか、あるいはその機能がWindowsでは異なる方法で処理されることを示唆しています。コンパイラの字句解析器において、catcher関数がどのような役割を担っていたのかは、このコミットメッセージだけでは明確ではありませんが、おそらく特定のシグナルや例外処理に関連するもので、Plan 9の環境でのみ必要とされる特殊なケースハンドリングだったと考えられます。

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

変更はsrc/cmd/gc/lex.cファイルにのみ行われました。

--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -164,6 +164,7 @@ fault(int s)
 	fatal("fault");
 }
 
+#ifdef	PLAN9
 void
 catcher(void *v, char *s)
 {
@@ -180,6 +181,7 @@ catcher(void *v, char *s)
 	}
 	noted(NDFLT);
 }
+#endif
 
 void
 doversion(void)

コアとなるコードの解説

この変更は、catcher関数の定義全体を#ifdef PLAN9#endifプリプロセッサディレクティブで囲むことで構成されています。

  • + #ifdef PLAN9: catcher関数の定義の直前に挿入された行です。これにより、この後のコードブロックがPLAN9マクロが定義されている場合にのみコンパイルされるようになります。
  • + #endif: catcher関数の定義の直後に挿入された行です。これにより、#ifdef PLAN9で開始された条件付きコンパイルブロックが閉じられます。

この修正により、WindowsのようなPlan 9以外の環境でGoコンパイラをビルドする際には、catcher関数とその中で呼び出されているnoted関数がコンパイル対象から除外されます。結果として、Windows環境での「undefined reference to noted」というリンクエラーが解消され、ビルドが正常に完了するようになります。

これは、クロスプラットフォーム開発において一般的な手法であり、特定のOSに依存するコードを分離し、必要な環境でのみコンパイルすることで、移植性を高めることができます。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード(src/cmd/gc/lex.cの関連部分)
  • Plan 9のシステムコールに関する一般的な情報
  • C言語のプリプロセッサディレクティブ(#ifdef, #endif)に関する一般的な情報
  • Go言語のコンパイラ構造に関する一般的な情報
  • Go言語のIssueトラッカーやメーリングリストでの関連議論(もしあれば)