[インデックス 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およびシステム知識に基づいて解説を生成しました。)