[インデックス 16013] ファイルの概要
このコミットは、Go言語のビルドシステムとリンカに関する重要な変更を導入しています。特に、macOS (旧称 OS X) の特定のバージョンにおけるシステムリンカのバグに対応し、Goプログラムのリンクモードのデフォルト挙動を調整することが目的です。
コミット
commit 3197be48078311368d5a37a89c61bbd47e00622f
Author: Ian Lance Taylor <iant@golang.org>
Date: Fri Mar 29 16:33:35 2013 -0700
cmd/dist, cmd/ld: GO_EXTLINK_ENABLED=0 defaults to -linkmode=internal
Change build system to set GO_EXTLINK_ENABLED=0 by default for
OS X 10.6, since the system linker has a bug and can not
handle the object files generated by 6l.
Fixes #5130.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/8183043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3197be48078311368d5a37a89c61bbd47e00622f
元コミット内容
このコミットは、cmd/dist
(Goのビルドシステム) と cmd/ld
(Goのリンカ) に関連する変更です。主な内容は、GO_EXTLINK_ENABLED=0
がデフォルトで -linkmode=internal
に設定されるようにすることです。これは特に OS X 10.6 環境において、システムリンカが 6l
(Goのx86-64リンカ) によって生成されたオブジェクトファイルを適切に処理できないバグが存在するためです。この変更は、Go issue #5130 を解決することを目的としています。
変更の背景
Go言語のプログラムをビルドする際、コンパイラが生成したオブジェクトファイルを最終的な実行可能ファイルに結合するためにリンカが使用されます。Goには独自の内部リンカがありますが、Cgo(GoからC言語のコードを呼び出す機能)を使用する場合など、外部のシステムリンカ(例: gcc
や clang
)を利用する「外部リンクモード」も存在します。
Go issue #5130 は、OS X 10.6 (Snow Leopard) のシステムリンカに存在する特定のバグを報告しています。このバグにより、Goのコンパイラ(特に 6l
、x86-64アーキテクチャ用のリンカ)が生成するオブジェクトファイルを、OS X 10.6 のシステムリンカが正しく処理できず、外部リンクモードでのビルドが失敗するという問題が発生していました。
この問題に対処するため、Goチームは OS X 10.6 環境でのデフォルトのリンクモードを内部リンカを使用するモードに強制的に変更する必要がありました。これにより、ユーザーが明示的に外部リンクモードを指定しない限り、バグのあるシステムリンカが使用されることを避け、ビルドの成功を保証します。
前提知識の解説
- Go言語のビルドプロセス: Goプログラムは、ソースコードがコンパイラによってオブジェクトファイルに変換され、その後リンカによって実行可能ファイルに結合されます。
- リンカ (Linker): オブジェクトファイルやライブラリを結合して実行可能ファイルを作成するプログラムです。
- 内部リンカ (Internal Linker): Go言語自体が提供するリンカです。Goのランタイムや標準ライブラリを静的にリンクする際に使用されます。
- 外部リンカ (External Linker): オペレーティングシステムが提供するリンカ(例: macOSの
ld
、Linuxのld
、Windowsのlink.exe
)です。Cgoを使用する場合や、特定のシステムライブラリに依存する場合に利用されます。 -linkmode
オプション: Goのビルドコマンド (go build
やgo install
) で使用できるオプションで、リンカの動作を指定します。-linkmode=internal
: 常にGoの内部リンカを使用します。-linkmode=external
: 常に外部リンカを使用します。-linkmode=auto
: Goが自動的に最適なリンカを選択します。通常、Cgoを使用する場合は外部リンカを、それ以外の場合は内部リンカを選択します。
GO_EXTLINK_ENABLED
環境変数: Goのビルド時に、外部リンカの使用を許可するかどうかを制御する環境変数です。GO_EXTLINK_ENABLED=1
: 外部リンカの使用を許可します。GO_EXTLINK_ENABLED=0
: 外部リンカの使用を禁止し、内部リンカを強制します。
- OS X 10.6 (Snow Leopard): 2009年にリリースされたmacOSのバージョンです。このコミットが作成された2013年時点ではまだ広く使用されていましたが、システムリンカに特定のバグが存在していました。
6l
: Goのツールチェーンにおける、x86-64アーキテクチャ向けのリンカの旧称です。現在はgo tool link
に統合されています。
技術的詳細
このコミットの技術的詳細は、Goのビルドシステムがどのように環境変数を読み取り、それに基づいてリンカの挙動を調整するか、そして特定のOSバージョンでの特殊なケースをどのように扱うかを示しています。
-
GO_EXTLINK_ENABLED
の導入:src/cmd/dist/a.h
とsrc/cmd/dist/build.c
でgoextlinkenabled
という変数が導入され、GO_EXTLINK_ENABLED
環境変数の値を保持するようになりました。src/cmd/dist/build.c
のinit
関数内で、GO_EXTLINK_ENABLED
環境変数が読み取られ、その値が0
または1
でない場合はエラーを発生させます。これにより、この環境変数の値が厳密に制御されます。- ビルド時に、この
goextlinkenabled
の値がコンパイラに渡されるようになります。
-
OS X 10.6 の検出と
GO_EXTLINK_ENABLED
の設定:src/cmd/dist/unix.c
は、GoのビルドシステムがUnix系システムで動作する際のロジックを含んでいます。- このファイルに、ホストOSが
darwin
(macOS) であるかどうかをチェックする新しいロジックが追加されました。 - さらに、
uname(&u)
システムコールを使用してOSのリリースバージョンを取得し、それが10.
で始まるか、または最初の数字が10
以下である場合に(これは OS X 10.6 以前のバージョンを示す一般的なパターンです)、goextlinkenabled
を"0"
に設定します。これにより、OS X 10.6 環境ではデフォルトで外部リンカが無効化されます。
-
リンカの挙動変更:
src/cmd/5l/obj.c
(ARMリンカ),src/cmd/6l/obj.c
(x86-64リンカ),src/cmd/8l/obj.c
(x86リンカ) の各リンカのソースコードが変更されました。- これらのファイルでは、
main
関数内でlinkmode == LinkAuto
かつgetgoextlinkenabled()
が"0"
を返す場合、linkmode
をLinkInternal
に強制的に設定するロジックが追加されました。これは、GO_EXTLINK_ENABLED=0
が設定されている場合に、自動選択モードであっても内部リンカを使用することを意味します。 - また、
6l
と8l
では、linkmode == LinkExternal
かつgetgoextlinkenabled()
が"1"
でない場合に、外部リンカを使用できないというエラーを発生させる条件が追加されました。これは、外部リンカが明示的に無効化されているにもかかわらず、ユーザーが外部リンクモードを強制しようとした場合にエラーを出すためのものです。
-
getgoextlinkenabled
関数の実装:src/lib9/goos.c
にgetgoextlinkenabled
関数が追加されました。この関数は、ビルド時に設定されたGO_EXTLINK_ENABLED
の値を返します。これは、リンカがビルド時の設定を参照するためのメカニズムです。
-
テストスクリプトの調整:
src/run.bash
はGoのテストスイートを実行するスクリプトです。- このスクリプトが変更され、
darwin-386
およびdarwin-amd64
環境において、uname -r
の結果が[0-9].*
または10.*
(OS X 10.6 以前のバージョンを示す) である場合、-ldflags '-linkmode=external'
を使用したテストをスキップするようになりました。これは、バグのあるリンカが原因でテストが失敗するのを避けるためです。
これらの変更により、GoのビルドシステムはOS X 10.6 環境を自動的に検出し、外部リンカのバグを回避するためにデフォルトで内部リンカを使用するようになります。これにより、ユーザーは特別な設定なしにGoプログラムを正常にビルドできるようになります。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。
-
src/cmd/dist/unix.c
: OS X 10.6 の検出とgoextlinkenabled
の設定ロジックが追加されています。--- a/src/cmd/dist/unix.c +++ b/src/cmd/dist/unix.c @@ -698,6 +698,19 @@ main(int argc, char **argv) if(strcmp(gohostarch, "arm") == 0) maxnbg = 1; + // The OS X 10.6 linker does not support external + // linking mode; see + // https://code.google.com/p/go/issues/detail?id=5130 . + // The mapping from the uname release field to the OS X + // version number is complicated, but basically 10 or under is + // OS X 10.6 or earlier. + if(strcmp(gohostos, "darwin") == 0) { + if(uname(&u) < 0) + fatal("uname: %s", strerror(errno)); + if(u.release[1] == '.' || hasprefix(u.release, "10")) + goextlinkenabled = "0"; + } + init(); xmain(argc, argv); bfree(&b);
-
src/cmd/6l/obj.c
(およびsrc/cmd/5l/obj.c
,src/cmd/8l/obj.c
): リンカがGO_EXTLINK_ENABLED
の値に基づいてリンクモードを調整するロジックが追加されています。--- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -133,11 +133,16 @@ main(int argc, char *argv[]) if(HEADTYPE == -1) HEADTYPE = headtype(goos); + // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when + // Go was built; see ../../make.bash. + if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0) + linkmode = LinkInternal; + switch(HEADTYPE) { default: if(linkmode == LinkAuto) linkmode = LinkInternal; - if(linkmode == LinkExternal) + if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0) sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); break; case Hdarwin:
-
src/lib9/goos.c
:getgoextlinkenabled
関数の実装が追加されています。--- a/src/lib9/goos.c +++ b/src/lib9/goos.c @@ -51,3 +51,9 @@ getgo386(void) { return defgetenv("GO386", GO386); } + +char * +getgoextlinkenabled(void) +{ + return GO_EXTLINK_ENABLED; +}
コアとなるコードの解説
-
src/cmd/dist/unix.c
の変更:if(strcmp(gohostos, "darwin") == 0)
: ホストOSがmacOSであるかをチェックします。if(u.release[1] == '.' || hasprefix(u.release, "10"))
:uname -r
コマンドで取得されるOSのリリースバージョン文字列をチェックします。macOSのリリースバージョンはX.Y.Z
の形式で、10.6
は10.6.0
のように表現されます。u.release[1] == '.'
はX.
の形式(例:9.
は OS X 10.5 以前)を、hasprefix(u.release, "10")
は10.
で始まるバージョン(例:10.6
)を検出します。これにより、OS X 10.6 以前のバージョンを特定し、goextlinkenabled = "0"
を設定して外部リンカを無効化します。
-
src/cmd/6l/obj.c
(リンカ) の変更:if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
: リンカが自動選択モード (LinkAuto
) であり、かつビルド時にGO_EXTLINK_ENABLED
が0
に設定されていた場合(つまり、外部リンカが明示的に無効化されている場合)、linkmode
をLinkInternal
に強制的に変更します。これにより、OS X 10.6 のような環境で外部リンカのバグを回避できます。if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
: ユーザーが明示的に外部リンクモード (LinkExternal
) を指定しているにもかかわらず、ビルド時にGO_EXTLINK_ENABLED
が1
でない場合(つまり、外部リンカが許可されていない場合)、sysfatal
を呼び出して致命的なエラーを発生させます。これは、矛盾する設定が与えられた場合のガードレールとして機能します。
-
src/lib9/goos.c
のgetgoextlinkenabled
:- この関数は、Goのビルドシステムによって設定された
GO_EXTLINK_ENABLED
の値を、Goのランタイムやリンカが参照できるようにするためのシンプルなラッパーです。これにより、ビルド時の環境設定が実行時のリンカの挙動に影響を与えることができます。
- この関数は、Goのビルドシステムによって設定された
これらの変更は、Goのビルドシステムが特定のOS環境の特性(この場合はOS X 10.6 のリンカバグ)を認識し、それに応じてビルドの挙動を自動的に調整することで、ユーザーエクスペリエンスを向上させるための堅牢なメカニズムを構築していることを示しています。
関連リンク
- Go issue #5130: https://code.google.com/p/go/issues/detail?id=5130 (Goプロジェクトの古いIssueトラッカーのリンクですが、当時の問題の詳細が記載されています)
- Go CL 8183043: https://golang.org/cl/8183043 (このコミットに対応するGoのコードレビューシステム (Gerrit) のチェンジリスト)
参考にした情報源リンク
- Go issue #5130 の内容
- Go言語のビルドシステムとリンカに関する一般的な知識
uname
コマンドとmacOSのバージョン番号の対応に関する情報- Goのソースコード内のコメントと既存のコードパターン