[インデックス 15984] ファイルの概要
このコミットは、Go言語のリンカであるcmd/ld
がホストリンカを使用する際に、-r
オプションを-rpath
として適切に渡すように修正するものです。これにより、共有ライブラリの検索パスが正しく設定され、実行時の動的リンクの問題が解決されます。
コミット
commit 8877a2dfee4cd37825f0df2fa7bb53573d04ae5b
Author: Ian Lance Taylor <iant@golang.org>
Date: Thu Mar 28 09:37:32 2013 -0700
cmd/ld: when using host linker pass -r option as -rpath
R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/8070043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b
元コミット内容
cmd/ld: when using host linker pass -r option as -rpath
R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/8070043
変更の背景
Go言語のビルドシステムは、Go自身のリンカ(cmd/ld
)を使用することもあれば、システムにインストールされているホストリンカ(例: gcc
が内部的に使用するld
)を使用することもあります。特にCGO(C言語との相互運用)を使用する場合や、特定のプラットフォームではホストリンカが利用されます。
このコミット以前は、Goのビルドプロセスにおいて、共有ライブラリの検索パスを指定するための-r
オプションが、ホストリンカに正しく伝達されていませんでした。その結果、ビルドされた実行ファイルが、実行時に必要な共有ライブラリを見つけられず、エラーとなる可能性がありました。
具体的には、Goのリンカが内部的に管理しているrpath
(Run-time search path)情報が、ホストリンカに渡される際に、ホストリンカが期待する形式(-Wl,-rpath,
)に変換されていなかったことが問題でした。この修正は、この変換を適切に行うことで、動的リンクされたGoプログラムが、実行時に必要な共有ライブラリを正しくロードできるようにすることを目的としています。
前提知識の解説
リンカ (Linker)
リンカは、コンパイラによって生成されたオブジェクトファイル(機械語コードとデータを含むファイル)を結合し、実行可能なプログラムや共有ライブラリを作成するツールです。このプロセスには、未解決のシンボル(関数や変数の参照)を解決し、それらを適切なメモリ位置にマッピングする作業が含まれます。
動的リンク (Dynamic Linking) と静的リンク (Static Linking)
- 静的リンク: プログラムが必要とするすべてのライブラリコードが、コンパイル時に実行ファイルに直接組み込まれます。これにより、実行ファイルは自己完結型となり、他のライブラリファイルに依存しません。しかし、実行ファイルのサイズが大きくなり、ライブラリの更新があった場合にプログラム全体を再コンパイルする必要があります。
- 動的リンク: プログラムが必要とするライブラリコードは、実行ファイルには組み込まれず、実行時にOSによってロードされます。これにより、実行ファイルのサイズが小さくなり、複数のプログラムで同じライブラリを共有できるためメモリ効率が向上します。また、ライブラリの更新があっても、プログラムを再コンパイルせずに新しいライブラリを利用できます。しかし、実行時にライブラリが見つからないとプログラムが起動できないという問題が発生する可能性があります。
RPATH (Run-time search path)
RPATHは、動的リンクされた実行ファイルが、実行時に共有ライブラリを検索するパスを指定するためのメカニズムです。通常、OSは共有ライブラリを検索するために、標準的なシステムディレクトリ(例: /lib
, /usr/lib
)や環境変数(例: LD_LIBRARY_PATH
on Linux, DYLD_LIBRARY_PATH
on macOS)を使用します。しかし、RPATHを使用すると、実行ファイル自体に特定の検索パスを埋め込むことができます。これにより、環境変数に依存せずに、アプリケーション固有のライブラリパスを指定することが可能になります。これは、特にアプリケーションが特定のディレクトリ構造に依存している場合や、システム全体に影響を与えずにライブラリの場所を制御したい場合に有用です。
cmd/ld
cmd/ld
は、Go言語の標準リンカです。Goプログラムのビルドにおいて、Goのコンパイラが生成したオブジェクトファイルをリンクし、実行ファイルを生成する役割を担います。Goのリンカは、Go独自のランタイムやガベージコレクタ、スケジューラなど、Go言語の特性を考慮したリンク処理を行います。
ホストリンカ
ホストリンカとは、GoのビルドシステムがGo自身のリンカではなく、実行環境(ホストOS)に元々インストールされているリンカ(例: GNU ld
)を使用する場合のリンカを指します。CGOを使用するGoプログラムは、C言語のコードをコンパイルしてリンクする必要があるため、通常はホストリンカが使用されます。
-Wl,option
-Wl,option
は、gcc
やclang
などのコンパイラドライバが、内部的に呼び出すリンカにオプションを渡すための一般的な構文です。-Wl,
の後に続く文字列が、リンカに直接渡されます。例えば、-Wl,-rpath,/path/to/lib
は、リンカに-rpath,/path/to/lib
というオプションを渡すことを意味します。
技術的詳細
このコミットの技術的な核心は、Goのリンカ(cmd/ld
)がホストリンカを呼び出す際に、rpath
の情報を正しく-Wl,-rpath,
形式で渡すようにした点です。
Goのビルドプロセスでは、rpath
という内部変数が、共有ライブラリの検索パスを保持しています。このrpath
は、Goのビルド設定や、CGOのコンパイルオプションなどから設定されることがあります。
src/cmd/ld/lib.c
ファイルは、cmd/ld
のリンカ処理の一部を担っており、特にhostlink
関数は、Goのリンカが外部のホストリンカを呼び出す際の引数を構築する役割を持っています。
変更前は、hostlink
関数内でrpath
変数が設定されていても、それがホストリンカに渡されるargv
(引数リスト)に追加されていませんでした。そのため、ホストリンカはGoのビルドプロセスが意図したrpath
情報を認識できず、結果として実行時に共有ライブラリが見つからないという問題が発生していました。
このコミットでは、hostlink
関数内に以下のコードが追加されました。
if(rpath)
argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
このコードは、rpath
変数が空でない(つまり、共有ライブラリの検索パスが指定されている)場合に、smprint
関数を使用して-Wl,-rpath,%s
という形式の文字列を生成し、それをホストリンカに渡す引数リストargv
に追加します。%s
の部分には、実際のrpath
の値が埋め込まれます。
これにより、ホストリンカは-Wl,-rpath,/path/to/your/libs
のような形式のオプションを受け取り、そのrpath
情報を最終的な実行ファイルに埋め込むことができるようになります。結果として、ビルドされたGoプログラムは、実行時に指定されたパスで共有ライブラリを正しく検索し、ロードできるようになります。
コアとなるコードの変更箇所
変更はsrc/cmd/ld/lib.c
ファイルに集中しています。
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -636,6 +636,9 @@ hostlink(void)\
argv[argc++] = "-o";
argv[argc++] = outfile;
+ if(rpath)
+ argv[argc++] = smprint("-Wl,-rpath,%s", rpath);\
+\
// Force global symbols to be exported for dlopen, etc.
// NOTE: May not work on OS X or Windows. We'll see.
argv[argc++] = "-rdynamic";
具体的には、hostlink
関数の内部で、出力ファイル名(-o
オプション)が設定された直後に、rpath
に関する処理が追加されています。
コアとなるコードの解説
追加された3行のコードは以下の通りです。
if(rpath)
argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
if(rpath)
: これは、rpath
というグローバル変数またはローカル変数が、共有ライブラリの検索パス情報を持っているかどうかをチェックしています。rpath
がNULLや空文字列でない場合に、条件が真となります。つまり、rpath
が設定されている場合にのみ、以下の処理が実行されます。smprint("-Wl,-rpath,%s", rpath)
:smprint
は、Goのリンカ内部で使用される文字列フォーマット関数で、printf
のようにフォーマットされた文字列を生成します。ここでは、-Wl,-rpath,
というプレフィックスに続けて、rpath
変数の内容を埋め込んだ文字列を生成しています。-Wl,
: これは、コンパイラドライバ(例:gcc
)がリンカにオプションを渡すための標準的なプレフィックスです。-rpath,%s
: これは、リンカ(例: GNUld
)が共有ライブラリの検索パスを指定するために認識するオプションです。%s
の部分には、rpath
変数の値(実際のパス)が挿入されます。
argv[argc++] = ...
: 生成された文字列は、argv
配列に追加されます。argv
は、ホストリンカを呼び出す際のコマンドライン引数を格納する配列です。argc++
は、引数の数をインクリメントし、次の引数を格納する位置を指すようにしています。
この変更により、Goのビルドシステムがrpath
を設定した場合、その情報がホストリンカに-Wl,-rpath,
という適切な形式で渡されるようになり、動的リンクされたGoプログラムが実行時に共有ライブラリを正しく見つけられるようになります。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Goのリンカに関する議論(Go issue trackerなど): 関連するissueやCL(Change List)を検索すると、より詳細な背景情報が見つかる可能性があります。
参考にした情報源リンク
- GNU
ld
manページ (rpathオプションについて): https://man7.org/linux/man-pages/man1/ld.1.html gcc
の-Wl
オプションに関するドキュメント: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html- GoのCL(Change List): https://golang.org/cl/8070043 (コミットメッセージに記載されているCLへのリンク)
- 動的リンクとRPATHに関する一般的な情報(Linuxのmanページや開発者向けドキュメントなど)I have generated the Markdown content as requested. I will now print it to standard output.
# [インデックス 15984] ファイルの概要
このコミットは、Go言語のリンカである`cmd/ld`がホストリンカを使用する際に、`-r`オプションを`-rpath`として適切に渡すように修正するものです。これにより、共有ライブラリの検索パスが正しく設定され、実行時の動的リンクの問題が解決されます。
## コミット
commit 8877a2dfee4cd37825f0df2fa7bb53573d04ae5b Author: Ian Lance Taylor iant@golang.org Date: Thu Mar 28 09:37:32 2013 -0700
cmd/ld: when using host linker pass -r option as -rpath
R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/8070043
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b](https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b)
## 元コミット内容
cmd/ld: when using host linker pass -r option as -rpath
R=golang-dev, daniel.morsing CC=golang-dev https://golang.org/cl/8070043
## 変更の背景
Go言語のビルドシステムは、Go自身のリンカ(`cmd/ld`)を使用することもあれば、システムにインストールされているホストリンカ(例: `gcc`が内部的に使用する`ld`)を使用することもあります。特にCGO(C言語との相互運用)を使用する場合や、特定のプラットフォームではホストリンカが利用されます。
このコミット以前は、Goのビルドプロセスにおいて、共有ライブラリの検索パスを指定するための`-r`オプションが、ホストリンカに正しく伝達されていませんでした。その結果、ビルドされた実行ファイルが、実行時に必要な共有ライブラリを見つけられず、エラーとなる可能性がありました。
具体的には、Goのリンカが内部的に管理している`rpath`(Run-time search path)情報が、ホストリンカに渡される際に、ホストリンカが期待する形式(`-Wl,-rpath,`)に変換されていなかったことが問題でした。この修正は、この変換を適切に行うことで、動的リンクされたGoプログラムが、実行時に必要な共有ライブラリを正しくロードできるようにすることを目的としています。
## 前提知識の解説
### リンカ (Linker)
リンカは、コンパイラによって生成されたオブジェクトファイル(機械語コードとデータを含むファイル)を結合し、実行可能なプログラムや共有ライブラリを作成するツールです。このプロセスには、未解決のシンボル(関数や変数の参照)を解決し、それらを適切なメモリ位置にマッピングする作業が含まれます。
### 動的リンク (Dynamic Linking) と静的リンク (Static Linking)
* **静的リンク**: プログラムが必要とするすべてのライブラリコードが、コンパイル時に実行ファイルに直接組み込まれます。これにより、実行ファイルは自己完結型となり、他のライブラリファイルに依存しません。しかし、実行ファイルのサイズが大きくなり、ライブラリの更新があった場合にプログラム全体を再コンパイルする必要があります。
* **動的リンク**: プログラムが必要とするライブラリコードは、実行ファイルには組み込まれず、実行時にOSによってロードされます。これにより、実行ファイルのサイズが小さくなり、複数のプログラムで同じライブラリを共有できるためメモリ効率が向上します。また、ライブラリの更新があっても、プログラムを再コンパイルせずに新しいライブラリを利用できます。しかし、実行時にライブラリが見つからないとプログラムが起動できないという問題が発生する可能性があります。
### RPATH (Run-time search path)
RPATHは、動的リンクされた実行ファイルが、実行時に共有ライブラリを検索するパスを指定するためのメカニズムです。通常、OSは共有ライブラリを検索するために、標準的なシステムディレクトリ(例: `/lib`, `/usr/lib`)や環境変数(例: `LD_LIBRARY_PATH` on Linux, `DYLD_LIBRARY_PATH` on macOS)を使用します。しかし、RPATHを使用すると、実行ファイル自体に特定の検索パスを埋め込むことができます。これにより、環境変数に依存せずに、アプリケーション固有のライブラリパスを指定することが可能になります。これは、特にアプリケーションが特定のディレクトリ構造に依存している場合や、システム全体に影響を与えずにライブラリの場所を制御したい場合に有用です。
### `cmd/ld`
`cmd/ld`は、Go言語の標準リンカです。Goプログラムのビルドにおいて、Goのコンパイラが生成したオブジェクトファイルをリンクし、実行ファイルを生成する役割を担います。Goのリンカは、Go独自のランタイムやガベージコレクタ、スケジューラなど、Go言語の特性を考慮したリンク処理を行います。
### ホストリンカ
ホストリンカとは、GoのビルドシステムがGo自身のリンカではなく、実行環境(ホストOS)に元々インストールされているリンカ(例: GNU `ld`)を使用する場合のリンカを指します。CGOを使用するGoプログラムは、C言語のコードをコンパイルしてリンクする必要があるため、通常はホストリンカが使用されます。
### `-Wl,option`
`-Wl,option`は、`gcc`や`clang`などのコンパイラドライバが、内部的に呼び出すリンカにオプションを渡すための一般的な構文です。`-Wl,`の後に続く文字列が、リンカに直接渡されます。例えば、`-Wl,-rpath,/path/to/lib`は、リンカに`-rpath,/path/to/lib`というオプションを渡すことを意味します。
## 技術的詳細
このコミットの技術的な核心は、Goのリンカ(`cmd/ld`)がホストリンカを呼び出す際に、`rpath`の情報を正しく`-Wl,-rpath,`形式で渡すようにした点です。
Goのビルドプロセスでは、`rpath`という内部変数が、共有ライブラリの検索パスを保持しています。この`rpath`は、Goのビルド設定や、CGOのコンパイルオプションなどから設定されることがあります。
`src/cmd/ld/lib.c`ファイルは、`cmd/ld`のリンカ処理の一部を担っており、特に`hostlink`関数は、Goのリンカが外部のホストリンカを呼び出す際の引数を構築する役割を持っています。
変更前は、`hostlink`関数内で`rpath`変数が設定されていても、それがホストリンカに渡される`argv`(引数リスト)に追加されていませんでした。そのため、ホストリンカはGoのビルドプロセスが意図した`rpath`情報を認識できず、結果として実行時に共有ライブラリが見つからないという問題が発生していました。
このコミットでは、`hostlink`関数内に以下のコードが追加されました。
```c
if(rpath)
argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
このコードは、rpath
変数が空でない(つまり、共有ライブラリの検索パスが指定されている)場合に、smprint
関数を使用して-Wl,-rpath,%s
という形式の文字列を生成し、それをホストリンカに渡す引数リストargv
に追加します。%s
の部分には、実際のrpath
の値が埋め込まれます。
これにより、ホストリンカは-Wl,-rpath,/path/to/your/libs
のような形式のオプションを受け取り、そのrpath
情報を最終的な実行ファイルに埋め込むことができるようになります。結果として、ビルドされたGoプログラムは、実行時に指定されたパスで共有ライブラリを正しく検索し、ロードできるようになります。
コアとなるコードの変更箇所
変更はsrc/cmd/ld/lib.c
ファイルに集中しています。
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -636,6 +636,9 @@ hostlink(void)\
argv[argc++] = "-o";
argv[argc++] = outfile;
+ if(rpath)
+ argv[argc++] = smprint("-Wl,-rpath,%s", rpath);\
+\
// Force global symbols to be exported for dlopen, etc.
// NOTE: May not work on OS X or Windows. We'll see.
argv[argc++] = "-rdynamic";
具体的には、hostlink
関数の内部で、出力ファイル名(-o
オプション)が設定された直後に、rpath
に関する処理が追加されています。
コアとなるコードの解説
追加された3行のコードは以下の通りです。
if(rpath)
argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
if(rpath)
: これは、rpath
というグローバル変数またはローカル変数が、共有ライブラリの検索パス情報を持っているかどうかをチェックしています。rpath
がNULLや空文字列でない場合に、条件が真となります。つまり、rpath
が設定されている場合にのみ、以下の処理が実行されます。smprint("-Wl,-rpath,%s", rpath)
:smprint
は、Goのリンカ内部で使用される文字列フォーマット関数で、printf
のようにフォーマットされた文字列を生成します。ここでは、-Wl,-rpath,
というプレフィックスに続けて、rpath
変数の内容を埋め込んだ文字列を生成しています。-Wl,
: これは、コンパイラドライバ(例:gcc
)がリンカにオプションを渡すための標準的なプレフィックスです。-rpath,%s
: これは、リンカ(例: GNUld
)が共有ライブラリの検索パスを指定するために認識するオプションです。%s
の部分には、rpath
変数の値(実際のパス)が挿入されます。
argv[argc++] = ...
: 生成された文字列は、argv
配列に追加されます。argv
は、ホストリンカを呼び出す際のコマンドライン引数を格納する配列です。argc++
は、引数の数をインクリメントし、次の引数を格納する位置を指すようにしています。
この変更により、Goのビルドシステムがrpath
を設定した場合、その情報がホストリンカに-Wl,-rpath,
という適切な形式で渡されるようになり、動的リンクされたGoプログラムが実行時に共有ライブラリを正しく見つけられるようになります。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Goのリンカに関する議論(Go issue trackerなど): 関連するissueやCL(Change List)を検索すると、より詳細な背景情報が見つかる可能性があります。
参考にした情報源リンク
- GNU
ld
manページ (rpathオプションについて): https://man7.org/linux/man-pages/man1/ld.1.html gcc
の-Wl
オプションに関するドキュメント: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html- GoのCL(Change List): https://golang.org/cl/8070043 (コミットメッセージに記載されているCLへのリンク)
- 動的リンクとRPATHに関する一般的な情報(Linuxのmanページや開発者向けドキュメントなど)