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

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

このコミットは、Go言語のビルドプロセスにおいて、macOS (Darwin) 上でGCCコンパイラを使用する際に、-mmacosx-version-min=10.6 フラグを渡すように変更を加えるものです。これにより、macOSの古いバージョンとの互換性を確保し、特定の環境で発生していた「Illegal Instruction」エラーを修正します。

コミット

  • コミットハッシュ: a5fe79ef787ab6b9048368648736ca66f3622f5b
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2013年4月16日 火曜日 13:30:52 -0700

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

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

元コミット内容

cmd/dist, make.bash: pass -mmacosx-version-min=10.6 to gcc on Darwin
Fixes #5261.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/8798044

変更の背景

この変更は、GoプログラムがmacOS上で「Illegal Instruction」エラーを発生させる問題(Issue #5261)を解決するために行われました。このエラーは、特に古いバージョンのmacOS(例: OS X 10.6 Snow Leopard)でGoのバイナリを実行しようとした際に顕著でした。

「Illegal Instruction」エラーは、プログラムがCPUが理解できない、または現在のCPUの命令セットではサポートされていない命令を実行しようとしたときに発生します。これは通常、新しいバージョンのコンパイラが、ターゲットとするOSの最小バージョンを考慮せずに、より新しいCPU命令(例えば、SSE4.2やAVXなどの拡張命令セット)を使用するバイナリを生成してしまう場合に起こります。

Goのビルドシステムは、クロスコンパイルやブートストラップの過程でGCC(またはClang)を使用します。この際、macOS環境では、コンパイラがデフォルトでターゲットとするmacOSのバージョンが、実際に実行される環境よりも新しい命令セットを要求する可能性がありました。その結果、古いmacOS環境で実行すると、サポートされていない命令に遭遇し、「Illegal Instruction」エラーでクラッシュするという問題が発生していました。

前提知識の解説

  • gcc on Darwin (macOS): macOSでは、Apple ClangがデフォルトのC/C++/Objective-Cコンパイラとして提供されていますが、GCCも利用可能です。Goのビルドプロセスでは、Cgoやランタイムの一部をコンパイルするためにCコンパイラ(通常はGCC互換のコンパイラ)を使用します。
  • -mmacosx-version-min フラグ: これはGCCやClangなどのコンパイラに渡されるオプションで、生成されるバイナリが動作するmacOSの最小バージョンを指定します。このフラグを使用することで、コンパイラは指定された最小バージョンで利用可能な命令セットのみを使用するように制限され、それより新しい命令セットに依存するコードの生成を避けます。例えば、-mmacosx-version-min=10.6 は、生成されるバイナリがmacOS 10.6 (Snow Leopard) 以降で動作することを保証します。これにより、古いmacOS環境での互換性が向上します。
  • Goのビルドプロセス (cmd/dist, make.bash):
    • make.bash: GoのソースコードからGoツールチェイン全体をビルドするための主要なシェルスクリプトです。Goのブートストラッププロセス(Go自身をGoでビルドする)の最初のステップとして、C言語で書かれたcmd/distツールをコンパイルするために使用されます。
    • cmd/dist: Goのディストリビューションを構築するためのコマンドラインツールです。Goの標準ライブラリやツールをコンパイルする際に、内部的にCコンパイラ(GCCなど)を呼び出します。
  • Illegal Instruction エラー: CPUが認識できない、または現在のCPUのモードや権限では実行できない命令に遭遇したときに発生する実行時エラーです。ソフトウェアが、実行環境のCPUがサポートしていない命令セット(例: 特定のSIMD命令)を使用しようとした場合に頻繁に見られます。
  • dlsym: Unix系システムにおける動的リンキングライブラリ(dlfcn.h)の一部で、実行時に共有ライブラリからシンボル(関数や変数)のアドレスを取得するために使用される関数です。Issue #5261の報告では、dlsymが期待されるシンボルを見つけられないという記述があり、これはコンパイルされたバイナリが特定の環境で動的にロードされるライブラリとの互換性問題を示唆している可能性があります。

技術的詳細

このコミットは、GoのビルドシステムがmacOS上でCコンパイラ(GCCまたはClang)を呼び出す際に、明示的に -mmacosx-version-min=10.6 フラグを追加することで、この問題を解決します。

具体的には、以下の2つのファイルが変更されています。

  1. src/cmd/dist/build.c: cmd/distはGoのビルドプロセスの中核をなすツールであり、Goの標準ライブラリやツール群をコンパイルする際にCコンパイラを呼び出します。このファイルにフラグを追加することで、distがGoのコンポーネントをビルドする際に使用するCコンパイラが、macOS 10.6以降との互換性を持つバイナリを生成するようになります。これにより、GoのランタイムやCgoでリンクされる部分が、古いmacOS環境でも正しく動作するようになります。

  2. src/make.bash: make.bashはGoのブートストラップビルドの最初の段階で、cmd/dist自体をコンパイルするために使用されます。このスクリプトにも同じフラグを追加することで、cmd/distツール自体がmacOS 10.6以降との互換性を持ってコンパイルされるようになります。これは、distツールが正しく動作するための基盤を確保する上で重要です。

この変更により、Goのバイナリは、macOS 10.6で利用可能な命令セットのみを使用するようにコンパイルされるため、それより古いmacOSバージョンで実行された場合に発生する「Illegal Instruction」エラーが回避されます。これは、Goがより広範なmacOS環境で安定して動作するための重要な互換性修正です。

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

src/cmd/dist/build.c

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -622,6 +622,10 @@ install(char *dir)
 			// clang is too smart about unused command-line arguments
 			vadd(&gccargs, "-Qunused-arguments");
 		}
+		if(streq(gohostos, "darwin")) {
+			// golang.org/issue/5261
+			vadd(&gccargs, "-mmacosx-version-min=10.6");
+		}
 	}

 	islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");

src/make.bash

--- a/src/make.bash
+++ b/src/make.bash
@@ -111,6 +111,10 @@ case "$GOHOSTARCH" in
 386) mflag=-m32;;
 amd64) mflag=-m64;;
 esac
+if [ "$(uname)" == "Darwin" ]; then
+	# golang.org/issue/5261
+	mflag="$mflag -mmacosx-version-min=10.6"
+fi
 ${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c

 eval $(./cmd/dist/dist env -p)

コアとなるコードの解説

src/cmd/dist/build.c の変更

install 関数内で、gohostos が "darwin" (macOS) である場合に、gccargs (GCCに渡す引数のリスト) に "-mmacosx-version-min=10.6" を追加しています。 これは、Goのビルドプロセス中にcmd/distがCコンパイラを呼び出す際に、生成されるバイナリがmacOS 10.6以降で動作するように、コンパイラに明示的に指示するためのものです。これにより、GoのランタイムやCgoで利用されるCコードが、古いmacOS環境でも互換性のある命令セットでコンパイルされることが保証されます。

src/make.bash の変更

make.bash スクリプト内で、uname コマンドの出力が "Darwin" (macOS) であることを確認し、mflag 変数に "-mmacosx-version-min=10.6" を追加しています。 mflag は、make.bashcmd/dist/dist ツール自体をコンパイルするために gcc を呼び出す際に使用されるフラグです。この変更により、Goのブートストラッププロセスで最初にコンパイルされるdistツール自体が、macOS 10.6以降との互換性を持ってビルドされるようになります。これは、Goのビルドシステム全体の安定性と互換性を確保するために重要です。

両方の変更箇所で、コメントとして // golang.org/issue/5261 または # golang.org/issue/5261 が追加されており、この変更が特定のGitHub Issueに対応するものであることを示しています。

関連リンク

参考にした情報源リンク