Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12526] ファイルの概要

このコミットは、Go言語のCGo機能における共有ライブラリ(.soファイル)のテストケースであるtestsoを再有効化するための変更です。具体的には、Makefileによるビルドプロセスを廃止し、test.bashスクリプト内で直接gccgo 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を解決することを目的としています。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念を把握しておく必要があります。

  1. CGo:

    • Go言語がC言語のコードを呼び出すためのメカニズムです。Goのソースファイル内にimport "C"と記述し、Cの関数やデータ構造をGoから利用できるようにします。
    • CGoを使用すると、GoプログラムとCライブラリの間でデータをやり取りしたり、Cの関数を呼び出したりできます。
    • CGoは、Goのビルドプロセス中にCコンパイラ(通常はgcc)を呼び出してCコードをコンパイルし、Goのコードとリンクします。
  2. 共有ライブラリ(Shared Library / .soファイル):

    • Unix系OS(Linuxなど)で利用される、複数のプログラムから共有して利用できるライブラリ形式です。Windowsでは.dll、macOSでは.dylibに相当します。
    • プログラムの実行時にメモリにロードされ、複数のプロセスで同じライブラリのコードを共有できるため、メモリ使用量の削減やディスク容量の節約に貢献します。
    • 共有ライブラリを使用するプログラムは、コンパイル時にはライブラリのインターフェース情報(ヘッダファイルなど)のみを参照し、実際のコードは実行時に動的にリンクされます。
  3. LD_LIBRARY_PATH環境変数:

    • Unix系OSにおいて、動的リンカ(dynamic linker/loader)が共有ライブラリを検索するパスを指定するための環境変数です。
    • プログラムが共有ライブラリをロードしようとするとき、まず標準のシステムパス(/lib, /usr/libなど)を検索しますが、LD_LIBRARY_PATHに指定されたディレクトリが優先的に検索されます。
    • 開発時やテスト時に、システムにインストールされていない、または特定のバージョンの共有ライブラリを使用したい場合に非常に便利です。
  4. gcc:

    • GNU Compiler Collectionの略で、C、C++、Objective-C、Fortran、Ada、Goなどの様々なプログラミング言語をコンパイルできるコンパイラ群です。
    • このコミットでは、C言語のソースファイル(cgoso_c.c)を共有ライブラリ(libcgosotest.so)にコンパイルするために使用されています。
  5. go build:

    • Go言語のソースコードをコンパイルし、実行可能ファイルを生成するためのコマンドです。
    • CGoを使用している場合、go buildは内部的にgccなどのCコンパイラを呼び出し、CコードとGoコードを統合して最終的な実行ファイルを生成します。
  6. Makefile:

    • makeユーティリティが使用するビルド自動化スクリプトです。プロジェクトのビルド手順や依存関係を記述します。
    • 複雑なプロジェクトのビルドプロセスを自動化し、変更されたファイルのみを再コンパイルするなど、効率的なビルドを可能にします。
    • このコミットでは、Makefileによるビルドプロセスが廃止され、よりシンプルなシェルスクリプトに置き換えられています。
  7. // +build ignoreディレクティブ:

    • Goのソースファイルの先頭に記述されるビルドタグの一種です。
    • このタグが記述されたファイルは、go buildgo installなどの通常のビルドプロセスでは無視されます。
    • 主に、実行可能な例(examples)、テストユーティリティ、または特定の目的のために手動でコンパイルされることを意図したファイルに使用されます。これにより、メインのアプリケーションビルドに不要なコードが含まれるのを防ぎます。

技術的詳細

このコミットの技術的な変更点は多岐にわたりますが、主要なポイントはmisc/cgo/testsoディレクトリ内のビルドおよびテスト実行フローの再構築です。

  1. Makefileの削除:

    • misc/cgo/testso/Makefileが完全に削除されました。このMakefileは、libcgoso.soのビルド(gccを使用)やcgosotest実行ファイルのビルド($(GC)$(LD)を使用)を担当していました。
    • Makefileの削除は、Goプロジェクトにおけるビルドシステムの標準化(go buildへの集約)や、特定のテストケースにおけるビルドプロセスの簡素化の傾向を反映している可能性があります。
  2. 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
      
      テスト実行後に生成された共有ライブラリと実行ファイルを削除し、クリーンな状態を保ちます。
  3. 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を正しく見つけてリンクできるようになります。
  4. cgoso_c.cmain.goへの// +build ignoreの追加:

    • これらのファイルの先頭に// +build ignoreディレクティブが追加されました。
    • これにより、これらのファイルは通常のgo buildプロセスからは無視され、test.bashスクリプトによって明示的にコンパイル・実行されるテスト専用のファイルとして扱われるようになります。これは、これらのファイルがGoモジュールの一部として直接ビルドされるのではなく、特定のテストシナリオでのみ使用されることを明確にします。
  5. .hgignoreの更新:

    • misc/cgo/testso/testsoが追加されました。これは、test.bashスクリプトによって生成される可能性のある実行ファイル名(go buildmain.goから生成する実行ファイルがtestsoという名前になる場合)をバージョン管理システムから無視するためのものです。
  6. src/run.bashの変更:

    • $BROKEN ||で始まるtestso関連の実行ブロックが削除されました。これは、testsoテストの実行が、Goのメインテストスイートの一部としてではなく、独立したtest.bashスクリプトによって管理されるようになったことを示唆しています。

これらの変更により、testsoテストはMakefileの複雑な依存関係から解放され、test.bashという単一のシェルスクリプトによって、共有ライブラリのビルドからGo実行ファイルのビルド、そして実行までの一連のプロセスがより明確かつ直接的に制御されるようになりました。これにより、テストの信頼性とメンテナンス性が向上したと考えられます。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更箇所は、主に以下のファイルに集中しています。

  1. 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
      
    • 変更後: ファイルなし
  2. misc/cgo/testso/cgoso.go:

    • CGoのインポートブロックが変更されました。
    • 変更前:
      //void sofunc(void);
      import "C"
      
    • 変更後:
      /*
      #cgo LDFLAGS: -L. -lcgosotest
      void sofunc(void);
      */
      import "C"
      
  3. 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();
      }
      
  4. 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()
      }
      
  5. 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
      
  6. 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.gocgoso.goをインポートしており、cgoso.goはCGoディレクティブ#cgo LDFLAGS: -L. -lcgosotestを含んでいます。 go buildコマンドは、このCGoディレクティブを解釈し、内部的にリンカを呼び出して、先ほど生成されたlibcgosotest.somain実行ファイルに動的にリンクするように設定します。

  • 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.cmain.goにこのビルドタグが追加されたことで、これらのファイルは通常のgo buildプロセスからは除外されます。これは、これらのファイルがGoモジュールの一部として直接ビルドされるのではなく、test.bashスクリプトによって特定のテストシナリオでのみコンパイル・実行されることを明確にします。これにより、Goプロジェクトのメインビルドプロセスが、テスト固有のファイルによって汚染されるのを防ぎます。

これらの変更は、CGoと共有ライブラリを使用するGoプログラムのテストにおいて、より直接的で制御しやすいビルド・実行フローを確立し、特定の環境依存性やビルドシステムの複雑さを排除することを目的としています。

関連リンク

参考にした情報源リンク