[インデックス 11539] ファイルの概要
このコミットは、Go言語のコンパイラ(gc
とcc
)のビルドプロセスにおける問題を修正するものです。特に、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言語のコンパイラ(gc
、cc
など)を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のビルドシステムにおいて顕著でした。
前提知識の解説
このコミットを理解するためには、以下の概念について理解しておく必要があります。
-
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
: リンカ
-
Go言語のビルドシステム: Go言語の初期のビルドシステムは、Unix/Plan 9の
make
ユーティリティとシェルスクリプトをベースにしていました。Goのソースコードは、Goコンパイラ(gc
)とCコンパイラ(cc
)によってコンパイルされ、リンカ(5l
,6l
,8l
など)によって実行可能ファイルが生成されます。 Goのビルドプロセスでは、ホストのアーキテクチャとターゲットのアーキテクチャを区別し、それぞれに対応するツールやライブラリを使用する必要があります。 -
Makefileと変数
$O
:Makefile
は、プログラムのビルドプロセスを自動化するためのスクリプトです。Goのビルドシステムでは、Makefile
が各コンポーネント(コンパイラ、リンカなど)のビルド手順を定義しています。$O
は、Goのビルドシステムにおける特別な変数で、現在のビルドターゲットのアーキテクチャを示すオブジェクトファイルサフィックスを表します。例えば、x86 (32-bit) ターゲットの場合、$O
は.5
となり、amd64 (64-bit) ターゲットの場合、$O
は.6
となります。この変数は、アーキテクチャ固有のオブジェクトファイルやライブラリを正しく参照するために使用されます。 -
ライブラリファイル(
.a
):.a
ファイルは、Unix系システムで一般的に使用される静的ライブラリのアーカイブファイルです。複数のオブジェクトファイル(.o
ファイル)を一つにまとめたもので、リンカがプログラムをビルドする際に参照します。Plan 9の慣習に従い、Goのビルドシステムでは、これらの静的ライブラリもアーキテクチャ固有のサフィックスを持つことがあります(例:cc.a5
,gc.a6
)。 -
#pragma lib
: C言語やC++のコンパイラによっては、#pragma
ディレクティブを用いてコンパイル時の特殊な指示を与えることができます。#pragma lib
は、特定のライブラリをリンクするようにコンパイラに指示するために使用されることがあります。Goの初期のコンパイラでは、C言語のヘッダファイルを通じて、ビルド時に必要なライブラリを明示的に指定するためにこのディレクティブが利用されていました。
技術的詳細
このコミットの技術的な核心は、Goのビルドシステムが、異なるアーキテクチャのライブラリファイルを正しく識別し、使用できるようにすることです。具体的には、以下の2つの主要な変更によって実現されています。
-
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.a
はcc.a5
として参照され、amd64 (64-bit) ターゲットではcc.a6
として参照されます。これにより、異なるアーキテクチャのライブラリが混同される問題が解消されます。 -
.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
)をより包括的に無視するための変更です。この変更は、ビルドプロセスで生成されるこれらのアーキテクチャ固有のライブラリがバージョン管理システムに誤って追加されるのを防ぐためのものです。
-
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.a5
やgc.a6
)を参照するように保証します。これは、コンパイラ自身のビルドの整合性を保つ上で重要です。
これらの変更は、GoのビルドシステムがPlan 9のような多様なアーキテクチャをサポートする環境において、より堅牢で正確なライブラリの選択を行うための基盤を強化しました。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、主にGoコンパイラおよびCコンパイラのMakefile
ファイル群と、gc
コンパイラのヘッダファイルgo.h
です。
-
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
を追加する変更です。 -
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
が使用され、正しいアーキテクチャのライブラリが選択されるようにします。 -
.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.a
はgc
コンパイラの内部的な依存関係の一部であり、このライブラリもまたアーキテクチャ固有のバージョンを持つ可能性があります。$O
を使用することで、gc
コンパイラが自身のビルド時に、自身のターゲットアーキテクチャに合致するgc.a
を確実に参照できるようになります。これは、コンパイラが正しく機能するための自己参照的な整合性を保つ上で重要です。 -
.hgignore
の変更: この変更は、ビルドプロセスによって生成されるアーキテクチャ固有のライブラリファイル(例:*.a5
,*.a6
,*.a8
)がバージョン管理システムによって追跡されないようにするためのものです。これにより、リポジトリがクリーンに保たれ、ビルド成果物がソースコードリポジトリに混入するのを防ぎます。これは、ビルドシステムのベストプラクティスに従った変更です。
これらの変更は、Goの初期のビルドシステムが、特にPlan 9のような特定の環境下で直面していた、アーキテクチャ間のライブラリの競合という具体的な問題を解決するために設計されました。これにより、Goのコンパイラがより堅牢に、そして正確にビルドされることが保証されます。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- このコミットのChange List (CL): https://golang.org/cl/5599053 (GoのコードレビューシステムGerritへのリンク)
参考にした情報源リンク
- Plan 9 From Bell Labs: https://9p.io/plan9/
- Go言語のビルドシステムに関する初期のドキュメントや議論(当時のメーリングリストなど)
- Goのソースコード内の
Make.inc
やMake.ctool
などのビルド関連ファイル - Mercurialの
.hgignore
に関するドキュメント - C言語の
#pragma
ディレクティブに関する一般的な情報