[インデックス 18437] ファイルの概要
このコミットは、Go言語のコマンドラインツール(cmd/go
)のテストスクリプトである src/cmd/go/test.bash
に関連する変更です。具体的には、cgo
を使用した共有ライブラリの検索パスに関するテストにおいて、macOS (Darwin) システムでの問題を回避するための修正が含まれています。
コミット
commit ff5f9bbf6a5d5281a2bf5326ce43df65deef4ac1
Author: Dave Cheney <dave@cheney.net>
Date: Mon Feb 10 13:35:39 2014 +1100
cmd/go: skip $ORIGIN test on darwin systems
Fixes #7293.
Update #7261
The bsd ld(1) does not understand $ORIGIN and has restrictions on using -rpath when using clang(1), the default compiler on darwin.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/58480045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ff5f9bbf6a5d5281a2bf5326ce43df65deef4ac1
元コミット内容
cmd/go: skip $ORIGIN test on darwin systems
Fixes #7293.
Update #7261
The bsd ld(1) does not understand $ORIGIN and has restrictions on using -rpath when using clang(1), the default compiler on darwin.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/58480045
変更の背景
このコミットは、Goの cmd/go
コマンドのテストスイートがmacOS (Darwin) システム上で失敗する問題を解決するために導入されました。問題の根源は、cgo
を使用してC言語のコードをGoプログラムにリンクする際に、共有ライブラリの検索パスを指定するために使用される $ORIGIN
というリンカの特殊な変数が、macOSのデフォルトリンカである bsd ld(1)
によって正しく解釈されないことにありました。
さらに、macOSでは clang(1)
がデフォルトのコンパイラとして使用されており、この clang(1)
と bsd ld(1)
の組み合わせにおいて、-rpath
リンカオプションの使用に特定の制限が存在します。これらの要因が複合的に作用し、$ORIGIN
を利用した rpath
の設定を含むテストがmacOS環境で期待通りに動作せず、テストの失敗を引き起こしていました。
この問題は、GoのIssue #7293として報告されており、このコミットはその修正を目的としています。また、Issue #7261に関連する更新も含まれています。
前提知識の解説
このコミットの変更内容を理解するためには、以下の技術的な概念を把握しておく必要があります。
1. $ORIGIN
$ORIGIN
は、ELF (Executable and Linkable Format) 形式の実行ファイルや共有ライブラリにおいて、動的リンカが実行時に解釈する特殊なトークンです。これは、現在ロードされている実行ファイルまたは共有ライブラリが配置されているディレクトリのパスを表します。
例えば、/usr/local/bin/myprog
という実行ファイルが /usr/local/lib/mylib.so
という共有ライブラリに依存しており、myprog
の rpath
に $ORIGIN/../lib
が指定されている場合、リンカは myprog
のディレクトリ(/usr/local/bin
)を基準として ../lib
、つまり /usr/local/lib
を共有ライブラリの検索パスとして使用します。
この機能は、アプリケーションとその依存ライブラリを相対パスで配置し、インストールパスに依存しないポータブルなバイナリを作成する際に非常に有用です。しかし、$ORIGIN
は主にLinuxなどのELFベースのシステムでサポートされており、macOS (Darwin) のようなMach-Oベースのシステムでは直接的な同等の機能がありません。macOSでは @loader_path
や @executable_path
といった独自の相対パス指定メカニズムが提供されています。
2. ld(1)
(リンカ)
ld
は "linker" の略で、コンパイラによって生成されたオブジェクトファイル(.o
ファイル)やライブラリファイル(.a
や .so
/.dylib
ファイル)を結合し、最終的な実行ファイルや共有ライブラリを生成するプログラムです。
リンカは、未解決のシンボル(関数や変数の参照)を解決し、適切なメモリアドレスに配置する役割を担います。
macOSでは、BSD系の ld
が使用されており、その挙動はLinuxなどで一般的に使用されるGNU ld
とは異なる場合があります。この違いが、本コミットで扱われる問題の根源の一つです。
3. -rpath
リンカオプション
-rpath
(Run-time search path) は、リンカに対して、生成される実行ファイルや共有ライブラリが実行時に依存する共有ライブラリを検索するための追加パスを指定するオプションです。
通常、共有ライブラリはシステム標準のパス(例: /lib
, /usr/lib
)や環境変数 LD_LIBRARY_PATH
(Linux) / DYLD_LIBRARY_PATH
(macOS) を参照して検索されますが、-rpath
を使用することで、バイナリ自体に検索パスを埋め込むことができます。これにより、環境変数に依存せずに特定のパスからライブラリをロードさせることが可能になります。
セキュリティ上の理由や、特定の環境でのみ有効なパスを指定するために使用されることがあります。
4. clang(1)
clang
は、LLVMプロジェクトの一部として開発されているC、C++、Objective-C、Objective-C++ のコンパイラフロントエンドです。Apple製品の開発環境であるXcodeに同梱されており、macOSのデフォルトコンパイラとして広く使用されています。
clang
は、GCC (GNU Compiler Collection) と高い互換性を持ちながら、より高速なコンパイル、優れたエラー診断、モジュール性などの利点を提供します。
5. cgo
cgo
は、Go言語のプログラムからC言語のコードを呼び出したり、逆にC言語のコードからGo言語の関数を呼び出したりするためのGoツールチェーンの一部です。
Goのソースファイル内に import "C"
という行を記述し、その直前のコメントブロックにC言語のコードを記述することで、GoとCの相互運用が可能になります。
cgo
は、Cコンパイラやリンカに渡すオプションを指定するための特別なディレクティブ // #cgo
をサポートしています。例えば、// #cgo LDFLAGS: -L/path/to/lib -lmylib
のように記述することで、リンカにライブラリのパスやライブラリ名を渡すことができます。
技術的詳細
このコミットの技術的な核心は、macOS (Darwin) 環境における動的リンカの挙動と cgo
の連携に関するものです。
Goの cmd/go
コマンドのテストスイートには、cgo
を利用して外部Cライブラリをリンクし、そのライブラリの検索パスに $ORIGIN
を含む -rpath
を指定するテストケースが含まれていました。このテストケースは、Goプログラムが自身の実行ファイルからの相対パスで共有ライブラリをロードできることを検証することを目的としていました。
しかし、macOSでは以下の問題が発生します。
-
bsd ld(1)
の$ORIGIN
非サポート: macOSのデフォルトリンカであるbsd ld(1)
は、ELF形式のシステムで一般的に使用される$ORIGIN
という特殊なトークンを理解しません。macOSの実行ファイル形式はMach-Oであり、ELFとは異なる動的リンカのメカニズムを持っています。そのため、-rpath,$ORIGIN
のような指定はbsd ld(1)
によって正しく解釈されず、リンカエラーや実行時のライブラリロード失敗につながります。 -
clang(1)
と-rpath
の制限: macOSのデフォルトコンパイラであるclang(1)
を使用して-rpath
オプションをbsd ld(1)
に渡す場合、特定の制限や挙動の違いがあります。特に、$ORIGIN
のような動的なパス指定は、macOSのセキュリティモデルやリンカの設計思想と合致しないため、問題を引き起こしやすいです。macOSでは、@loader_path
や@executable_path
といった独自の相対パス指定メカニズムが提供されていますが、これらは$ORIGIN
とは異なる概念であり、Goのテストケースでは$ORIGIN
が直接使用されていました。
これらの理由により、src/cmd/go/test.bash
内の cgo
テストがmacOS上で失敗していました。このコミットは、この特定のテストケースがmacOS環境では実行されないようにすることで、テストスイート全体の安定性を確保しています。これは、macOSのリンカの特性に起因する根本的な問題を回避するための実用的なアプローチです。
コアとなるコードの変更箇所
変更は src/cmd/go/test.bash
ファイルの1箇所のみです。
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -608,7 +608,7 @@ export GOPATH=$d
mkdir -p $d/src/origin
echo '
package origin
-// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
// void f(void) {}
import "C"
コアとなるコードの解説
変更された行は、src/cmd/go/test.bash
スクリプト内で生成されるGoパッケージ origin
のソースコードの一部です。このGoパッケージは、cgo
を使用してC言語の関数 f
をインポートしています。
元のコード:
// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
この行は、cgo
ディレクティブを使用して、Cコンパイラ/リンカに LDFLAGS
(リンカフラグ) を渡しています。具体的には、-Wl,-rpath -Wl,$ORIGIN
というフラグを渡しています。
-Wl,
は、続くオプションをリンカに渡すことを意味します。-rpath
は、実行時の共有ライブラリ検索パスを指定するリンカオプションです。$ORIGIN
は、前述の通り、実行ファイル自身のディレクトリを指す特殊な変数です。
このディレクティブは、生成されるバイナリが $ORIGIN
を基準とした相対パスで共有ライブラリを検索するようにリンカに指示していました。
変更後のコード:
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
この変更では、#cgo
ディレクティブに !darwin
というビルドタグが追加されています。
!darwin
は、Goのビルドタグの一種で、「Darwin (macOS) 以外のシステムでのみこの行を有効にする」という意味を持ちます。
したがって、この変更により、// #cgo LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
というリンカフラグは、macOS以外のシステム(Linuxなど)でのみ適用されるようになります。macOS上では、この行は無視され、$ORIGIN
を含む rpath
の設定は行われなくなります。これにより、macOSのリンカが $ORIGIN
を理解しないことによるテストの失敗が回避されます。
この修正は、Goのクロスプラットフォーム対応において、特定のOSのリンカの挙動の違いを吸収するための典型的なアプローチを示しています。
関連リンク
- Go Issue #7293: https://github.com/golang/go/issues/7293
- Go Issue #7261: https://github.com/golang/go/issues/7261
- Gerrit Change-Id:
I2121212121212121212121212121212121212121
(コミットメッセージのhttps://golang.org/cl/58480045
から推測されるGerritのChange-Idは、通常I
で始まるハッシュ値ですが、ここでは具体的な値が提供されていないため、一般的なプレースホルダーを使用します。実際のリンクはhttps://go-review.googlesource.com/c/go/+/58480045
のような形式になります。)
参考にした情報源リンク
- ELF
rpath
and$ORIGIN
: https://linux.die.net/man/8/ld.so (ld.so man page, for$ORIGIN
context) ld(1)
man page (macOS): https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/MachOReference/Articles/MachO_Reference.html (Mach-O Reference, for macOS linker context)clang
documentation: https://clang.llvm.org/- Go
cgo
documentation: https://pkg.go.dev/cmd/cgo - Go Build Tags: https://go.dev/cmd/go/#hdr-Build_tags