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

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

このコミットは、Go言語のコンパイラ(gccc)のビルドプロセスにおける問題を修正するものです。特に、Plan 9オペレーティングシステム上で32ビットと64ビットのホストコンパイラを切り替えてビルドする際に、誤ったライブラリが使用される可能性があった問題を解決します。

コミット

commit e280035fc1afdf4c1855d74bc4178ff0a8a18332
Author: Anthony Martin <ality@pbrane.org>
Date:   Wed Feb 1 04:14:37 2012 -0800

    gc, cc: avoid using the wrong library when building the compilers

    This can happen on Plan 9 if we we're building
    with the 32-bit and 64-bit host compilers, one
    after the other.

    R=rsc
    CC=golang-dev
    https://golang.org/cl/5599053

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

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

元コミット内容

--- a/.hgignore
+++ b/.hgignore
@@ -3,7 +3,7 @@ syntax:glob
 .git
 .gitignore
 *.[568ao]
-*.ao
+*.a[568o]
 *.so
 *.pyc
 ._*
--- a/src/cmd/5c/Makefile
+++ b/src/cmd/5c/Makefile
@@ -26,7 +26,7 @@ OFILES=\
 	../5l/enam.$O\

 LIB=\
-	../cc/cc.a\
+	../cc/cc.a$O\

 include ../../Make.ctool

--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -28,7 +28,7 @@ OFILES=\
 	reg.$O\

 LIB=\
-	../gc/gc.a\
+	../gc/gc.a$O\

 include ../../Make.ctool

--- a/src/cmd/6c/Makefile
+++ b/src/cmd/6c/Makefile
@@ -28,7 +28,7 @@ OFILES=\
 	../6l/enam.$O\

 LIB=\
-	../cc/cc.a\
+	../cc/cc.a$O\

 include ../../Make.ctool

--- a/src/cmd/6g/Makefile
+++ b/src/cmd/6g/Makefile
@@ -27,7 +27,7 @@ OFILES=\
 	reg.$O\

 LIB=\
-	../gc/gc.a\
+	../gc/gc.a$O\

 include ../../Make.ctool

--- a/src/cmd/8c/Makefile
+++ b/src/cmd/8c/Makefile
@@ -29,7 +29,7 @@ OFILES=\
 	../8l/enam.$O\

 LIB=\
-	../cc/cc.a\
+	../cc/cc.a$O\

 include ../../Make.ctool

--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -28,7 +28,7 @@ OFILES=\
 	reg.$O\

 LIB=\
-	../gc/gc.a\
+	../gc/gc.a$O\

 include ../../Make.ctool

--- a/src/cmd/cc/Makefile
+++ b/src/cmd/cc/Makefile
@@ -5,7 +5,7 @@
 include ../../Make.inc
 O:=$(HOST_O)

-LIB=cc.a
+LIB=cc.a$O

 HFILES=\
 	cc.h\
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -5,7 +5,7 @@
 include ../../Make.inc
 O:=$(HOST_O)

-LIB=gc.a
+LIB=gc.a$O

 HFILES=\
 	go.h\
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -4,6 +4,8 @@

 #include	<bio.h>

+#pragma	lib	"../gc/gc.a$O"\
+\
 #undef OAPPEND

 // avoid <ctype.h>

変更の背景

このコミットは、Go言語のコンパイラ(gcccなど)をPlan 9オペレーティングシステム上でビルドする際に発生する特定の問題に対処するために行われました。問題は、32ビットと64ビットのホストコンパイラを連続して使用してビルドを行うと、ビルドシステムが誤ったバージョンのライブラリファイル(.aファイル)を選択してしまう可能性があったことです。

Plan 9では、異なるアーキテクチャ(例:32ビットのx86、64ビットのamd64、ARMなど)に対応するために、オブジェクトファイルやライブラリファイルにアーキテクチャを示すサフィックス(例:.5.6.8)が付与されることがあります。例えば、foo.aというライブラリは、x86アーキテクチャではfoo.a5、amd64アーキテクチャではfoo.a6となることがあります。

このコミット以前のビルド設定では、ライブラリのパスが../cc/cc.aのように固定されており、アーキテクチャ固有のサフィックスが考慮されていませんでした。このため、例えば最初に64ビットコンパイラでビルドした後、次に32ビットコンパイラでビルドしようとすると、ビルドシステムが以前の64ビット用のライブラリ(cc.a6など)を誤って参照してしまう可能性がありました。これにより、リンケージエラーや不正なバイナリが生成される原因となっていました。

この問題は、特にGoのコンパイラ自体がクロスコンパイル環境で動作し、異なるアーキテクチャのコードを生成する性質上、ビルド環境のアーキテクチャとターゲットアーキテクチャの区別が重要になるGoのビルドシステムにおいて顕著でした。

前提知識の解説

このコミットを理解するためには、以下の概念について理解しておく必要があります。

  1. Plan 9 From Bell Labs: ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、"Everything is a file"という哲学を徹底しています。Go言語の開発者の一部はPlan 9の開発にも携わっており、Goの初期のビルドシステムやツールチェインにはPlan 9の設計思想や慣習が色濃く反映されています。特に、Goのコンパイラやリンカの命名規則(例:5c, 6g, 8lなど)はPlan 9のツールチェインに由来します。

    • 5: x86 (32-bit)
    • 6: amd64 (64-bit)
    • 8: arm (32-bit)
    • c: Cコンパイラ
    • g: Goコンパイラ
    • l: リンカ
  2. Go言語のビルドシステム: Go言語の初期のビルドシステムは、Unix/Plan 9のmakeユーティリティとシェルスクリプトをベースにしていました。Goのソースコードは、Goコンパイラ(gc)とCコンパイラ(cc)によってコンパイルされ、リンカ(5l, 6l, 8lなど)によって実行可能ファイルが生成されます。 Goのビルドプロセスでは、ホストのアーキテクチャとターゲットのアーキテクチャを区別し、それぞれに対応するツールやライブラリを使用する必要があります。

  3. Makefileと変数$O: Makefileは、プログラムのビルドプロセスを自動化するためのスクリプトです。Goのビルドシステムでは、Makefileが各コンポーネント(コンパイラ、リンカなど)のビルド手順を定義しています。 $Oは、Goのビルドシステムにおける特別な変数で、現在のビルドターゲットのアーキテクチャを示すオブジェクトファイルサフィックスを表します。例えば、x86 (32-bit) ターゲットの場合、$O.5となり、amd64 (64-bit) ターゲットの場合、$O.6となります。この変数は、アーキテクチャ固有のオブジェクトファイルやライブラリを正しく参照するために使用されます。

  4. ライブラリファイル(.a: .aファイルは、Unix系システムで一般的に使用される静的ライブラリのアーカイブファイルです。複数のオブジェクトファイル(.oファイル)を一つにまとめたもので、リンカがプログラムをビルドする際に参照します。Plan 9の慣習に従い、Goのビルドシステムでは、これらの静的ライブラリもアーキテクチャ固有のサフィックスを持つことがあります(例:cc.a5, gc.a6)。

  5. #pragma lib: C言語やC++のコンパイラによっては、#pragmaディレクティブを用いてコンパイル時の特殊な指示を与えることができます。#pragma libは、特定のライブラリをリンクするようにコンパイラに指示するために使用されることがあります。Goの初期のコンパイラでは、C言語のヘッダファイルを通じて、ビルド時に必要なライブラリを明示的に指定するためにこのディレクティブが利用されていました。

技術的詳細

このコミットの技術的な核心は、Goのビルドシステムが、異なるアーキテクチャのライブラリファイルを正しく識別し、使用できるようにすることです。具体的には、以下の2つの主要な変更によって実現されています。

  1. Makefileにおけるライブラリパスの修正: Goのコンパイラ(5c, 5g, 6c, 6g, 8c, 8g, cc, gc)のMakefileにおいて、LIB変数の定義が変更されました。 変更前: LIB=../cc/cc.a または LIB=cc.a 変更後: LIB=../cc/cc.a$O または LIB=cc.a$O この変更により、ライブラリファイル名に$O変数が追加されました。これにより、ビルド時に現在のターゲットアーキテクチャに対応する正しいサフィックス(例:.5, .6, .8)がライブラリファイル名に付与されるようになります。例えば、x86 (32-bit) ターゲットでビルドする場合、cc.acc.a5として参照され、amd64 (64-bit) ターゲットではcc.a6として参照されます。これにより、異なるアーキテクチャのライブラリが混同される問題が解消されます。

  2. .hgignoreの更新: .hgignoreファイルは、Mercurialバージョン管理システムが無視するファイルパターンを定義します。このコミットでは、*.aoというパターンが*.a[568o]に変更されました。

    • *.ao: 任意のファイル名に.aoという拡張子が付くファイルを無視します。これは、Plan 9のオブジェクトファイル(.o)に似た形式のアーカイブファイルを示唆している可能性があります。
    • *.a[568o]: 任意のファイル名に.aが続き、その後に5, 6, 8のいずれかの数字、またはoが付くファイルを無視します。これは、Plan 9のアーキテクチャ固有の静的ライブラリ(例:lib.a5, lib.a6, lib.a8)や、一般的なオブジェクトファイル(.o)をより包括的に無視するための変更です。この変更は、ビルドプロセスで生成されるこれらのアーキテクチャ固有のライブラリがバージョン管理システムに誤って追加されるのを防ぐためのものです。
  3. src/cmd/gc/go.hへの#pragma libの追加: src/cmd/gc/go.hファイルに以下の行が追加されました。 #pragma lib "../gc/gc.a$O" この#pragma libディレクティブは、gcコンパイラがビルドされる際に、../gc/gc.aというライブラリをリンクするように指示します。ここでも$O変数が使用されており、コンパイラが自身のビルド時に正しいアーキテクチャのgc.aライブラリ(例:gc.a5gc.a6)を参照するように保証します。これは、コンパイラ自身のビルドの整合性を保つ上で重要です。

これらの変更は、GoのビルドシステムがPlan 9のような多様なアーキテクチャをサポートする環境において、より堅牢で正確なライブラリの選択を行うための基盤を強化しました。

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

このコミットにおけるコアとなるコードの変更箇所は、主にGoコンパイラおよびCコンパイラのMakefileファイル群と、gcコンパイラのヘッダファイルgo.hです。

  1. src/cmd/{5c,5g,6c,6g,8c,8g,cc,gc}/Makefile: これらのファイルでは、LIB変数の定義が変更されています。

    -LIB=../cc/cc.a
    +LIB=../cc/cc.a$O
    

    または

    -LIB=cc.a
    +LIB=cc.a$O
    

    これは、各コンパイラが依存するライブラリのパスに、現在のビルドターゲットのアーキテクチャを示すサフィックス$Oを追加する変更です。

  2. src/cmd/gc/go.h: このヘッダファイルには、新しい#pragma libディレクティブが追加されています。

    --- a/src/cmd/gc/go.h
    +++ b/src/cmd/gc/go.h
    @@ -4,6 +4,8 @@
    
     #include	<bio.h>
    
    +#pragma	lib	"../gc/gc.a$O"
    +\
     #undef OAPPEND
    
     // avoid <ctype.h>
    

    この行は、gcコンパイラがビルドされる際に、gc.aライブラリをリンクするように明示的に指示するものです。ここでも$Oが使用され、正しいアーキテクチャのライブラリが選択されるようにします。

  3. .hgignore: バージョン管理システムが無視するファイルパターンが更新されました。

    --- a/.hgignore
    +++ b/.hgignore
    @@ -3,7 +3,7 @@ syntax:glob
     .git
     .gitignore
     *.[568ao]
    -*.ao
    +*.a[568o]
     *.so
     *.pyc
     ._*
    

    これは、ビルドによって生成されるアーキテクチャ固有のライブラリファイルが誤ってリポジトリにコミットされるのを防ぐための変更です。

コアとなるコードの解説

これらの変更は、Goのビルドシステムが、特にPlan 9のようなマルチアーキテクチャ環境において、ライブラリの依存関係をより正確に解決できるようにするためのものです。

  • Makefileの変更: LIB変数に$Oを追加することは、ビルドシステムが実行されるアーキテクチャ(ホストアーキテクチャ)に基づいて、適切なライブラリファイル(例: cc.a5 for x86, cc.a6 for amd64)を動的に選択することを可能にします。これにより、32ビットと64ビットのコンパイラを切り替えてビルドする際に、以前のビルドで生成された異なるアーキテクチャのライブラリが誤って再利用されることを防ぎます。これは、ビルドの再現性と正確性を保証するために不可欠です。

  • go.hへの#pragma libの追加: gcコンパイラ自身のビルドプロセスにおいて、この#pragma libディレクティブは、gc.aライブラリが正しくリンクされることを保証します。gc.agcコンパイラの内部的な依存関係の一部であり、このライブラリもまたアーキテクチャ固有のバージョンを持つ可能性があります。$Oを使用することで、gcコンパイラが自身のビルド時に、自身のターゲットアーキテクチャに合致するgc.aを確実に参照できるようになります。これは、コンパイラが正しく機能するための自己参照的な整合性を保つ上で重要です。

  • .hgignoreの変更: この変更は、ビルドプロセスによって生成されるアーキテクチャ固有のライブラリファイル(例: *.a5, *.a6, *.a8)がバージョン管理システムによって追跡されないようにするためのものです。これにより、リポジトリがクリーンに保たれ、ビルド成果物がソースコードリポジトリに混入するのを防ぎます。これは、ビルドシステムのベストプラクティスに従った変更です。

これらの変更は、Goの初期のビルドシステムが、特にPlan 9のような特定の環境下で直面していた、アーキテクチャ間のライブラリの競合という具体的な問題を解決するために設計されました。これにより、Goのコンパイラがより堅牢に、そして正確にビルドされることが保証されます。

関連リンク

参考にした情報源リンク

  • Plan 9 From Bell Labs: https://9p.io/plan9/
  • Go言語のビルドシステムに関する初期のドキュメントや議論(当時のメーリングリストなど)
  • Goのソースコード内のMake.incMake.ctoolなどのビルド関連ファイル
  • Mercurialの.hgignoreに関するドキュメント
  • C言語の#pragmaディレクティブに関する一般的な情報