[インデックス 19257] ファイルの概要
このコミットは、Go言語のテストスクリプト run.bash における改善を目的としています。具体的には、Cgoを用いた静的リンクのテストが、一部のシステムで libc.a (C標準ライブラリの静的バージョン) が利用できないために失敗する問題を解決します。また、run.bash スクリプトの実行時に GOROOT 環境変数を明示的にエクスポートすることで、ユーザーが事前に GOROOT を設定していなくてもスクリプトが正しく動作するように、利便性を向上させています。
コミット
commit 6f3f2d0ab825ee1ab77d62766828b6c191f92622
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Tue Apr 29 14:43:10 2014 -0400
run.bash: skip -static cgo test if -static linking isn't possible.
Some system doesn't have libc.a available.
While we're at here, also export GOROOT in run.bash, so that
one doesn't need to set GOROOT to run run.bash.
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/99870043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6f3f2d0ab825ee1ab77d62766828b6c191f92622
元コミット内容
run.bash: skip -static cgo test if -static linking isn't possible.
Some system doesn't have libc.a available.
While we're at here, also export GOROOT in run.bash, so that
one doesn't need to set GOROOT to run run.bash.
変更の背景
この変更には主に二つの背景があります。
-
Cgo静的リンクテストの信頼性向上: Go言語はC言語のコードを呼び出すための
cgoという機能を提供しています。cgoを使用するプログラムは、通常、動的リンク(実行時に共有ライブラリをロードする方式)されますが、特定のユースケースでは静的リンク(必要なライブラリをすべて実行ファイルに含める方式)が望まれます。Goのテストスイートには、この静的リンクが正しく機能するかを検証するテストが含まれています。しかし、一部のLinuxディストリビューションやシステムでは、C標準ライブラリの静的バージョンであるlibc.aがデフォルトでインストールされていない場合があります。このような環境で静的リンクのテストを実行すると、libc.aが見つからないためにテストが失敗し、本来は問題ないはずのビルドがエラーとなるという誤検知が発生していました。このコミットは、静的リンクが不可能な環境では該当テストをスキップすることで、テストの信頼性を高めることを目的としています。 -
run.bashスクリプトの利便性向上:run.bashはGoのビルドシステムやテストスイートを実行するための重要なシェルスクリプトです。以前は、このスクリプトを実行する前にユーザーが手動でGOROOT環境変数を設定する必要がありました。GOROOTはGoのインストールディレクトリを指す変数であり、Goツールチェーンの動作に不可欠です。このコミットでは、run.bash内部でGOROOTを明示的にエクスポートすることで、ユーザーが事前に設定する手間を省き、スクリプトの使いやすさを向上させています。
前提知識の解説
このコミットを理解するためには、以下の技術的な概念を把握しておく必要があります。
- Cgo: Go言語の機能の一つで、C言語のコードをGoプログラムから呼び出すことを可能にします。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。
- 静的リンク (Static Linking): プログラムのコンパイル時に、必要なすべてのライブラリコードを実行ファイル自体に組み込むリンク方式です。これにより、実行ファイルは自己完結型となり、外部の共有ライブラリに依存しなくなります。利点としては、デプロイが容易になること(依存関係の管理が不要)、起動が速いこと、実行環境に特定のライブラリが存在しなくても動作することなどが挙げられます。欠点としては、実行ファイルのサイズが大きくなることや、ライブラリのセキュリティアップデートがあった場合に、そのライブラリを使用するすべての実行ファイルを再コンパイルする必要があることなどがあります。
- 動的リンク (Dynamic Linking): プログラムの実行時に、必要な共有ライブラリ(例:
.soファイル on Linux,.dllファイル on Windows)をロードするリンク方式です。利点としては、実行ファイルのサイズが小さくなること、複数のプログラムで同じ共有ライブラリを共有できるためメモリ効率が良いこと、ライブラリのアップデートが容易であることなどが挙げられます。欠点としては、実行環境に適切なバージョンの共有ライブラリが存在しないとプログラムが起動しない(「DLL地獄」などと呼ばれる問題)ことなどがあります。 libc.a: C標準ライブラリ (glibcなど) の静的リンク用アーカイブファイルです。静的リンクを行う際には、このファイルがリンカによって参照され、必要なC標準ライブラリの関数が実行ファイルに組み込まれます。一部のシステムでは、ディスクスペースの節約やセキュリティ上の理由から、libc.aがデフォルトでインストールされていない場合があります。go test: Go言語のテストを実行するためのコマンドです。-ldflags:go buildやgo testコマンドに渡すことができるフラグで、リンカに渡す追加のオプションを指定します。-linkmode=external:go buildやgo testでCgoを使用する際に、Goのリンカではなく、外部のCリンカ(通常はgccやclang)を使用してリンク処理を行うことを指定するフラグです。Cgoで静的リンクを行う場合によく使用されます。-extldflags:linkmode=externalを使用する際に、外部リンカに渡す追加のオプションを指定するフラグです。-static(リンカオプション): 外部リンカ(例:gcc)に、可能な限り静的リンクを行うように指示するオプションです。-pthread(リンカオプション): POSIXスレッドライブラリ (libpthread) をリンクするためのオプションです。Cgoを使用するGoプログラムでは、Goランタイムがスレッドを使用するため、このライブラリが必要になることがあります。go env: Goの環境変数の設定を表示するコマンドです。eval $(go env)は、このコマンドの出力を評価して、現在のシェルセッションにGoの環境変数を設定するために使用されます。GOROOT: Goのインストールディレクトリを指す環境変数です。Goツールチェーンが正しく動作するために必要です。run.bash: Goプロジェクトのルートディレクトリにあるシェルスクリプトで、Goのビルド、テスト、その他の開発タスクを実行するための主要なエントリポイントとして機能します。
技術的詳細
このコミットの技術的な変更は、主に src/run.bash ファイル内の2つのセクションに集中しています。
-
静的リンクテストの条件付き実行: 以前の
run.bashスクリプトでは、特定のOS/アーキテクチャ(darwin-*,linux-*,windows-*など)に対して、go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtlsというコマンドを無条件に実行していました。このコマンドは、testtlsというテストパッケージを、外部リンカ (-linkmode=external) を使用し、かつ静的リンク (-extldflags "-static -pthread") でビルド・テストすることを試みるものです。このコミットでは、この
go testコマンドの実行前に、システムが静的リンクをサポートしているかどうかをチェックするロジックが追加されました。if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then echo "No support for static linking found (lacks libc.a?), skip cgo static linking test." else go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1 fiこの
if文の条件式! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}'が非常に重要です。$CC: これはCコンパイラ(通常はgccまたはclang)を指す環境変数です。-xc: 入力ファイルがC言語のソースコードであることを明示的に指定します。-o /dev/null: コンパイル結果の実行ファイルを/dev/nullに出力し、ディスクに書き込まないようにします。これは、単に静的リンクが可能かどうかをチェックするだけで、実際の実行ファイルは不要なためです。-static: コンパイラ/リンカに静的リンクを試みるように指示します。-: 標準入力からソースコードを読み込むことを意味します。<<< 'int main() {}': Bashのヒアストリング (here-string) 機能を使用し、非常にシンプルなC言語のプログラムint main() {}を標準入力として$CCコマンドに渡します。このプログラムは、静的リンクの可能性をテストするための最小限のコードです。2>/dev/null: 標準エラー出力(stderr)を/dev/nullにリダイレクトします。これにより、静的リンクが不可能な場合にコンパイラ/リンカが出力するエラーメッセージ(例:cannot find -lc)が画面に表示されなくなり、スクリプトの出力がクリーンになります。if ! ... ; then:$CCコマンドが成功した場合は終了コード0を返しますが、静的リンクが不可能な場合は非ゼロの終了コードを返します。!はその終了コードを反転させるため、コマンドが失敗した場合(静的リンクが不可能な場合)にifブロックが実行されます。
このロジックにより、システムが静的リンクをサポートしていない(例えば
libc.aが見つからない)場合、go testコマンドは実行されずにスキップされ、代わりに「No support for static linking found...」というメッセージが表示されます。これにより、不必要なテスト失敗が回避されます。 -
GOROOT環境変数のエクスポート:run.bashスクリプトの冒頭近くに、eval $(go env)の直後にexport GOROOTという行が追加されました。eval $(go env): このコマンドは、go envの出力(Goの環境変数設定)を現在のシェルで評価し、GOPATHやGOROOTなどの変数を設定します。export GOROOT:eval $(go env)によって設定されたGOROOT変数を、現在のシェルプロセスだけでなく、そこから起動される子プロセス(例えばgo testコマンドなど)にも引き継がれるようにエクスポートします。これにより、run.bashを実行するユーザーが事前にGOROOTを設定していなくても、スクリプト内でGoツールチェーンが正しくGOROOTを認識し、依存するテストやビルドプロセスが問題なく実行されるようになります。コミットメッセージにあるように、「the api test requires GOROOT to be set.」という背景があり、APIテストがGOROOTを必要とするため、このエクスポートが重要になります。
これらの変更により、Goのテストスイートはより堅牢になり、様々なシステム環境での互換性が向上し、開発者の利便性も高まりました。
コアとなるコードの変更箇所
--- a/src/run.bash
+++ b/src/run.bash
@@ -6,6 +6,7 @@
set -e
eval $(go env)
+export GOROOT # the api test requires GOROOT to be set.
unset CDPATH # in case user has it set
unset GOPATH # we disallow local import for non-local packages, if $GOROOT happens
@@ -140,7 +141,11 @@ dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | li
# static linking on FreeBSD/ARM with clang. (cgo depends on
\t\t\t# -fPIC fundamentally.)
*)\n-\t\tgo test -ldflags \'-linkmode=external -extldflags \"-static -pthread\"\' ../testtls || exit 1
+\t\tif ! $CC -xc -o /dev/null -static - 2>/dev/null <<<\'int main() {}\' ; then
+\t\t\techo \"No support for static linking found (lacks libc.a?), skip cgo static linking test.\"\n+\t\telse
+\t\t\tgo test -ldflags \'-linkmode=external -extldflags \"-static -pthread\"\' ../testtls || exit 1
+\t\tfi
\t\t;;\n \tesac
\t;;\n
コアとなるコードの解説
-
export GOROOTの追加:eval $(go env) export GOROOT # the api test requires GOROOT to be set.eval $(go env)は、Goの環境設定(GOROOTやGOPATHなど)を現在のシェルに読み込みます。その直後にexport GOROOTを追加することで、GOROOT環境変数が現在のシェルプロセスだけでなく、このスクリプトから起動されるすべてのサブプロセス(例えばgo testコマンドなど)にも引き継がれるようになります。これにより、run.bashを実行する際に、ユーザーが事前にGOROOTを設定していなくても、GoのAPIテストなどが正しくGOROOTを参照できるようになり、スクリプトの独立性と利便性が向上します。 -
静的リンクテストの条件分岐:
if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then echo "No support for static linking found (lacks libc.a?), skip cgo static linking test." else go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1 fiこのブロックは、Cgoを用いた静的リンクのテスト (
../testtls) を実行する前に、現在のシステムが静的リンクをサポートしているかどうかをチェックします。if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then:$CC: 環境変数CCで指定されたCコンパイラ(通常はgccまたはclang)を実行します。-xc: 入力言語をCとして扱います。-o /dev/null: コンパイル結果を/dev/nullに出力し、ファイルを作成しません。-static: 静的リンクを試みます。-: 標準入力からソースコードを読み込みます。<<< 'int main() {}': 最小限のCプログラムint main() {}を標準入力として渡します。2>/dev/null: 標準エラー出力を/dev/nullにリダイレクトし、エラーメッセージを非表示にします。- このコマンドが成功すれば(終了コード0)、静的リンクが可能であることを意味します。
!はその結果を反転させるため、コマンドが失敗した場合(静的リンクが不可能な場合)にthenブロックが実行されます。
echo "No support for static linking found (lacks libc.a?), skip cgo static linking test.": 静的リンクが不可能な場合に表示されるメッセージです。libc.aが見つからないことが原因である可能性を示唆し、テストがスキップされることを伝えます。else: 静的リンクが可能であると判断された場合に実行されます。go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1:testtlsパッケージのテストを、外部リンカと静的リンクオプションを使用して実行します。|| exit 1は、テストが失敗した場合にスクリプト全体の実行を停止するためのものです。
この条件分岐により、静的リンクがサポートされていない環境でのテスト失敗が回避され、Goのテストスイートの堅牢性が向上しました。
関連リンク
参考にした情報源リンク
- 特になし (提供された情報と一般的なGoおよびシステム知識に基づいて解説を生成しました。)