[インデックス 12526] ファイルの概要
このコミットは、Go言語のCGo機能における共有ライブラリ(.so
ファイル)のテストケースであるtestso
を再有効化するための変更です。具体的には、Makefile
によるビルドプロセスを廃止し、test.bash
スクリプト内で直接gcc
とgo build
コマンドを使用して共有ライブラリと実行ファイルを生成・実行するように変更しています。これにより、以前のビルドシステムに依存しない、より直接的なテスト実行フローが確立されました。
コミット
commit dc57ed8cafe7c6e8940231c46cdcf3633e6c5eaa
Author: Francisco Souza <franciscossouza@gmail.com>
Date: Thu Mar 8 12:13:41 2012 -0500
misc/cgo: re-enable testso
The test.bash file generates .so file using gcc, builds the executable
using the go tool and then run it with the $LD_LIBRARY_PATH variable
pointing to the directory where the .so file lives.
Fixes #2982.
R=rsc, remyoudompheng
CC=golang-dev
https://golang.org/cl/5788043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/dc57ed8cafe7c6e8940231c46cdcf3633e6c5eaa
元コミット内容
このコミットの目的は、misc/cgo
ディレクトリ内のtestso
テストを再有効化することです。
コミットメッセージによると、test.bash
スクリプトがgcc
を使用して.so
(共有ライブラリ)ファイルを生成し、go tool
を使用して実行可能ファイルをビルドし、その後$LD_LIBRARY_PATH
変数を.so
ファイルが存在するディレクトリに設定して実行するように変更されています。
この変更は、Issue #2982を修正するものです。
変更の背景
このコミットの背景には、Go言語のCGo機能における共有ライブラリのテストが一時的に無効化されていた、または正しく機能していなかったという問題があります。コミットメッセージにあるFixes #2982
が示すように、特定の不具合(Issue 2982)が存在し、それがtestso
テストの実行を妨げていたと考えられます。
Go言語は、CGoというメカニズムを通じてC言語のコードを呼び出すことができます。CGoを使用する際に、C言語で書かれた共有ライブラリ(.so
ファイル)をGoプログラムから利用するケースは一般的です。このようなシナリオを適切にテストするためには、共有ライブラリのビルド、Goプログラムからのリンク、そして実行時のライブラリパスの解決が正しく行われることを検証する必要があります。
以前のtestso
テストは、おそらくMakefile
に依存していましたが、何らかの理由でそのビルド・実行プロセスが不安定であったか、またはGoのビルドシステムや環境の変化に対応できていなかった可能性があります。このコミットは、Makefile
への依存を排除し、よりシンプルで堅牢なtest.bash
スクリプトによる直接的なビルド・実行フローに切り替えることで、テストの信頼性を向上させ、Issue #2982を解決することを目的としています。
前提知識の解説
このコミットを理解するためには、以下の技術的な概念を把握しておく必要があります。
-
CGo:
- Go言語がC言語のコードを呼び出すためのメカニズムです。Goのソースファイル内に
import "C"
と記述し、Cの関数やデータ構造をGoから利用できるようにします。 - CGoを使用すると、GoプログラムとCライブラリの間でデータをやり取りしたり、Cの関数を呼び出したりできます。
- CGoは、Goのビルドプロセス中にCコンパイラ(通常は
gcc
)を呼び出してCコードをコンパイルし、Goのコードとリンクします。
- Go言語がC言語のコードを呼び出すためのメカニズムです。Goのソースファイル内に
-
共有ライブラリ(Shared Library /
.so
ファイル):- Unix系OS(Linuxなど)で利用される、複数のプログラムから共有して利用できるライブラリ形式です。Windowsでは
.dll
、macOSでは.dylib
に相当します。 - プログラムの実行時にメモリにロードされ、複数のプロセスで同じライブラリのコードを共有できるため、メモリ使用量の削減やディスク容量の節約に貢献します。
- 共有ライブラリを使用するプログラムは、コンパイル時にはライブラリのインターフェース情報(ヘッダファイルなど)のみを参照し、実際のコードは実行時に動的にリンクされます。
- Unix系OS(Linuxなど)で利用される、複数のプログラムから共有して利用できるライブラリ形式です。Windowsでは
-
LD_LIBRARY_PATH
環境変数:- Unix系OSにおいて、動的リンカ(dynamic linker/loader)が共有ライブラリを検索するパスを指定するための環境変数です。
- プログラムが共有ライブラリをロードしようとするとき、まず標準のシステムパス(
/lib
,/usr/lib
など)を検索しますが、LD_LIBRARY_PATH
に指定されたディレクトリが優先的に検索されます。 - 開発時やテスト時に、システムにインストールされていない、または特定のバージョンの共有ライブラリを使用したい場合に非常に便利です。
-
gcc
:- GNU Compiler Collectionの略で、C、C++、Objective-C、Fortran、Ada、Goなどの様々なプログラミング言語をコンパイルできるコンパイラ群です。
- このコミットでは、C言語のソースファイル(
cgoso_c.c
)を共有ライブラリ(libcgosotest.so
)にコンパイルするために使用されています。
-
go build
:- Go言語のソースコードをコンパイルし、実行可能ファイルを生成するためのコマンドです。
- CGoを使用している場合、
go build
は内部的にgcc
などのCコンパイラを呼び出し、CコードとGoコードを統合して最終的な実行ファイルを生成します。
-
Makefile
:make
ユーティリティが使用するビルド自動化スクリプトです。プロジェクトのビルド手順や依存関係を記述します。- 複雑なプロジェクトのビルドプロセスを自動化し、変更されたファイルのみを再コンパイルするなど、効率的なビルドを可能にします。
- このコミットでは、
Makefile
によるビルドプロセスが廃止され、よりシンプルなシェルスクリプトに置き換えられています。
-
// +build ignore
ディレクティブ:- Goのソースファイルの先頭に記述されるビルドタグの一種です。
- このタグが記述されたファイルは、
go build
やgo install
などの通常のビルドプロセスでは無視されます。 - 主に、実行可能な例(examples)、テストユーティリティ、または特定の目的のために手動でコンパイルされることを意図したファイルに使用されます。これにより、メインのアプリケーションビルドに不要なコードが含まれるのを防ぎます。
技術的詳細
このコミットの技術的な変更点は多岐にわたりますが、主要なポイントはmisc/cgo/testso
ディレクトリ内のビルドおよびテスト実行フローの再構築です。
-
Makefile
の削除:misc/cgo/testso/Makefile
が完全に削除されました。このMakefile
は、libcgoso.so
のビルド(gcc
を使用)やcgosotest
実行ファイルのビルド($(GC)
と$(LD)
を使用)を担当していました。Makefile
の削除は、Goプロジェクトにおけるビルドシステムの標準化(go build
への集約)や、特定のテストケースにおけるビルドプロセスの簡素化の傾向を反映している可能性があります。
-
test.bash
スクリプトの変更:- このスクリプトが、
testso
テストのビルドと実行の主要なオーケストレーターとなりました。 - 共有ライブラリのビルド:
gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
gcc
コマンドを直接呼び出し、cgoso_c.c
からlibcgosotest.so
という共有ライブラリを生成しています。-fPIC
: Position-Independent Code(位置独立コード)を生成するためのフラグ。共有ライブラリには必須です。-g
: デバッグ情報を生成します。-shared
: 共有ライブラリを生成するためのフラグ。-o libcgosotest.so
: 出力ファイル名を指定します。
- Go実行ファイルのビルド:
go build main.go
go build
コマンドを直接呼び出し、main.go
から実行可能ファイル(デフォルトではmain
という名前)を生成します。この際、main.go
がCGoを使用しているため、go build
は内部的にlibcgosotest.so
へのリンクを処理します。 - 実行と
LD_LIBRARY_PATH
の設定:
生成された実行ファイルLD_LIBRARY_PATH=. ./main
main
を実行する際に、LD_LIBRARY_PATH
環境変数を現在のディレクトリ(.
)に設定しています。これにより、動的リンカはlibcgosotest.so
を現在のディレクトリから見つけることができます。 - クリーンアップ:
テスト実行後に生成された共有ライブラリと実行ファイルを削除し、クリーンな状態を保ちます。rm -f libcgosotest.so main
- このスクリプトが、
-
cgoso.go
の変更:- CGoのインポートブロックが変更されました。
から//void sofunc(void);
に変更されています。/* #cgo LDFLAGS: -L. -lcgosotest void sofunc(void); */ import "C"
#cgo LDFLAGS: -L. -lcgosotest
: これはCGoのディレクティブで、GoコンパイラにCコードをリンクする際のリンカフラグを指示します。-L.
: 現在のディレクトリ(.
)をライブラリ検索パスに追加します。-lcgosotest
:libcgosotest.so
という名前のライブラリをリンクするように指示します。GoのCGoは、lib
プレフィックスと.so
サフィックスを自動的に補完します。
- この変更により、Goプログラムが
libcgosotest.so
を正しく見つけてリンクできるようになります。
- CGoのインポートブロックが変更されました。
-
cgoso_c.c
とmain.go
への// +build ignore
の追加:- これらのファイルの先頭に
// +build ignore
ディレクティブが追加されました。 - これにより、これらのファイルは通常の
go build
プロセスからは無視され、test.bash
スクリプトによって明示的にコンパイル・実行されるテスト専用のファイルとして扱われるようになります。これは、これらのファイルがGoモジュールの一部として直接ビルドされるのではなく、特定のテストシナリオでのみ使用されることを明確にします。
- これらのファイルの先頭に
-
.hgignore
の更新:misc/cgo/testso/testso
が追加されました。これは、test.bash
スクリプトによって生成される可能性のある実行ファイル名(go build
がmain.go
から生成する実行ファイルがtestso
という名前になる場合)をバージョン管理システムから無視するためのものです。
-
src/run.bash
の変更:$BROKEN ||
で始まるtestso
関連の実行ブロックが削除されました。これは、testso
テストの実行が、Goのメインテストスイートの一部としてではなく、独立したtest.bash
スクリプトによって管理されるようになったことを示唆しています。
これらの変更により、testso
テストはMakefile
の複雑な依存関係から解放され、test.bash
という単一のシェルスクリプトによって、共有ライブラリのビルドからGo実行ファイルのビルド、そして実行までの一連のプロセスがより明確かつ直接的に制御されるようになりました。これにより、テストの信頼性とメンテナンス性が向上したと考えられます。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、主に以下のファイルに集中しています。
-
misc/cgo/testso/Makefile
:- ファイル全体が削除されました。
- 変更前:
# Copyright 2011 The Go Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. include ../../../src/Make.inc TARG=cgosotest CGO_DEPS+=libcgoso.so CGO_LDFLAGS+=-lcgoso -L. CLEANFILES+=out libcgoso.so CGOFILES=\ cgoso.go\ include ../../../src/Make.pkg libcgoso.so: cgoso_c.c gcc cgoso_c.c -fPIC -o $@ $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) out: install main.go $(GC) $(GCFLAGS) $(GCIMPORTS) main.go $(LD) -o $@ main.$O
- 変更後: ファイルなし
-
misc/cgo/testso/cgoso.go
:- CGoのインポートブロックが変更されました。
- 変更前:
//void sofunc(void); import "C"
- 変更後:
/* #cgo LDFLAGS: -L. -lcgosotest void sofunc(void); */ import "C"
-
misc/cgo/testso/cgoso_c.c
:- ビルドタグが追加されました。
- 変更前:
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. void sofunc(void) { extern void goCallback(void); goCallback(); }
- 変更後:
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build ignore void sofunc(void) { extern void goCallback(void); goCallback(); }
-
misc/cgo/testso/main.go
:- ビルドタグとインポートパスが変更されました。
- 変更前:
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import "cgosotest" func main() { cgosotest.Test() }
- 変更後:
// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build ignore package main import "." func main() { cgosotest.Test() }
-
misc/cgo/testso/test.bash
:- ビルドと実行のロジックが大幅に変更されました。
- 変更前:
#!/bin/bash # Copyright 2011 The Go Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. set -e gomake out LD_LIBRARY_PATH=. ./out gomake clean
- 変更後:
#!/bin/bash # Copyright 2011 The Go Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. set -e gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c go build main.go LD_LIBRARY_PATH=. ./main rm -f libcgosotest.so main
-
src/run.bash
:testso
関連の実行ブロックが削除されました。- 変更前(関連部分のみ抜粋):
$BROKEN || [ "$CGO_ENABLED" != 1 ] || [ "$GOHOSTOS" == windows ] || [ "$GOHOSTOS" == darwin ] || (xcd ../misc/cgo/testso -"$GOMAKE" clean ./test.bash ) || exit $?
- 変更後(関連部分のみ抜粋):
[ "$CGO_ENABLED" != 1 ] || [ "$GOHOSTOS" == windows ] || [ "$GOHOSTOS" == darwin ] || (xcd ../misc/cgo/testso ./test.bash ) || exit $?
コアとなるコードの解説
このコミットの核心は、misc/cgo/testso/Makefile
の削除と、それに伴うmisc/cgo/testso/test.bash
スクリプトの大幅な変更です。
misc/cgo/testso/Makefile
の削除:
これは、testso
テストのビルドプロセスが、Goの標準的なビルドツール(go build
)とシンプルなシェルスクリプトに完全に移行したことを意味します。以前はMakefile
がCGoライブラリのコンパイルとGo実行ファイルのリンクを管理していましたが、この依存関係が解消されました。これにより、ビルドシステムがより簡素化され、Goのツールチェーンとの整合性が高まります。
misc/cgo/testso/test.bash
の変更:
このスクリプトは、testso
テストの新しいエントリポイントとなります。
-
gcc -fPIC -g -shared -o libcgosotest.so cgoso_c.c
: この行は、C言語のソースファイルcgoso_c.c
をコンパイルして、libcgosotest.so
という名前の共有ライブラリを生成します。-fPIC
は、生成されるコードがメモリ上の任意の位置にロードされても正しく動作するようにするための重要なフラグです。共有ライブラリには必須です。-shared
は、出力が共有ライブラリであることを示します。- このステップにより、Goプログラムから呼び出されるCの機能が、独立した共有ライブラリとして利用可能になります。
-
go build main.go
: この行は、Goのソースファイルmain.go
をコンパイルして実行可能ファイルを生成します。main.go
はcgoso.go
をインポートしており、cgoso.go
はCGoディレクティブ#cgo LDFLAGS: -L. -lcgosotest
を含んでいます。go build
コマンドは、このCGoディレクティブを解釈し、内部的にリンカを呼び出して、先ほど生成されたlibcgosotest.so
をmain
実行ファイルに動的にリンクするように設定します。 -
LD_LIBRARY_PATH=. ./main
: この行は、ビルドされたmain
実行ファイルを実行します。ここで重要なのはLD_LIBRARY_PATH=.
の部分です。LD_LIBRARY_PATH
は、Unix系システムで動的リンカが共有ライブラリを検索するパスを指定する環境変数です。LD_LIBRARY_PATH=.
と設定することで、現在のディレクトリ(.
)が共有ライブラリの検索パスに追加されます。これにより、システム標準のパスにインストールされていないlibcgosotest.so
を、main
実行ファイルが正しく見つけてロードできるようになります。- この設定がなければ、
main
実行ファイルはlibcgosotest.so
を見つけられず、実行時エラー(例: "error while loading shared libraries")が発生する可能性があります。
-
rm -f libcgosotest.so main
: テスト実行後、生成された共有ライブラリと実行ファイルを削除し、作業ディレクトリをクリーンな状態に戻します。これは、テストの独立性を保ち、不要なファイルが残らないようにするための標準的なプラクティスです。
cgoso.go
のCGoディレクティブ変更:
#cgo LDFLAGS: -L. -lcgosotest
の追加は、Goコンパイラに対して、CGoコードをビルドする際にlibcgosotest.so
を現在のディレクトリから探してリンクするように明示的に指示します。これにより、GoプログラムがCの共有ライブラリと正しく連携できるようになります。
// +build ignore
の追加:
cgoso_c.c
とmain.go
にこのビルドタグが追加されたことで、これらのファイルは通常のgo build
プロセスからは除外されます。これは、これらのファイルがGoモジュールの一部として直接ビルドされるのではなく、test.bash
スクリプトによって特定のテストシナリオでのみコンパイル・実行されることを明確にします。これにより、Goプロジェクトのメインビルドプロセスが、テスト固有のファイルによって汚染されるのを防ぎます。
これらの変更は、CGoと共有ライブラリを使用するGoプログラムのテストにおいて、より直接的で制御しやすいビルド・実行フローを確立し、特定の環境依存性やビルドシステムの複雑さを排除することを目的としています。
関連リンク
- Go言語公式ドキュメント - CGo: https://go.dev/blog/c-go-is-not-go (CGoの概要について)
- Go言語公式ドキュメント -
go build
コマンド: https://go.dev/cmd/go/#hdr-Compile_packages_and_dependencies - Issue 2982 on Go GitHub: https://github.com/golang/go/issues/2982 (このコミットが修正した具体的な問題)
- Go CL 5788043: https://golang.org/cl/5788043 (このコミットに対応するGoの変更リスト)
参考にした情報源リンク
LD_LIBRARY_PATH
について: https://linuxjm.osdn.jp/html/LDP_man-pages/man8/ld.so.8.html- GCCの
-fPIC
と-shared
オプションについて: https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html - Goのビルドタグ(
// +build
)について: https://go.dev/cmd/go/#hdr-Build_constraints - 共有ライブラリの概念: https://ja.wikipedia.org/wiki/%E5%85%B1%E6%9C%89%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA
- CGoの
#cgo
ディレクティブについて: https://go.dev/cmd/cgo/