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

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

このコミットは、Go言語のビルドツール (cmd/go) におけるSWIG (Simplified Wrapper and Interface Generator) の統合に関する改善です。具体的には、SWIGによって生成される共有ライブラリにC/C++ファイルが適切に含まれるようにし、またSWIG共有ライブラリの検索パスにアクションのオブジェクトディレクトリを追加することで、SWIGを利用したGoプログラムのビルドプロセスをより堅牢にすることを目的としています。

コミット

commit c774e902083c677cffb9873e7d46346bcbf8cc21
Author: Ian Lance Taylor <iant@golang.org>
Date:   Wed Oct 9 10:35:46 2013 -0700

    cmd/go: add any .c/.cc files to the SWIG shared library
    
    Also add the action's object directory to the list of
    directories we use to find SWIG shared libraries.
    
    Fixes #6521.
    
    R=golang-dev, minux.ma
    CC=golang-dev
    https://golang.org/cl/14369043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c774e902083c677cffb9873e7d46346bcbf8cc21

元コミット内容

cmd/go: add any .c/.cc files to the SWIG shared library Also add the action's object directory to the list of directories we use to find SWIG shared libraries. Fixes #6521.

変更の背景

このコミットは、GoのビルドツールがSWIGを使用する際に、C言語 (.c) およびC++言語 (.cc) のソースファイルをSWIGによって生成される共有ライブラリに適切に含めるようにするためのものです。また、SWIGが共有ライブラリを検索する際に、ビルドアクションのオブジェクトディレクトリも検索パスに追加することで、ビルドの信頼性を向上させています。

Fixes #6521 と記載されていますが、現在のGoリポジトリのIssue番号ははるかに大きいため、このIssueは非常に古いか、既にクローズされている可能性があります。しかし、この記述から、以前のGoビルドプロセスでは、SWIGを使用する際にC/C++ファイルが共有ライブラリに正しくリンクされない、あるいはSWIGが生成した共有ライブラリを見つけられないという問題が存在していたことが推測されます。この問題は、GoとC/C++コードをSWIGを介して連携させるアプリケーションの開発において、ビルドエラーや実行時エラーを引き起こす可能性がありました。

前提知識の解説

  • Go言語のビルドシステム (cmd/go): Go言語の公式ビルドツールであり、ソースコードのコンパイル、リンク、パッケージ管理などを行います。go build コマンドなどがこれに該当します。
  • SWIG (Simplified Wrapper and Interface Generator): C/C++/Objective-C/Java/Python/Ruby/Goなど、様々な言語間でC/C++コードを呼び出すためのインターフェースコードを自動生成するツールです。Go言語から既存のC/C++ライブラリを利用する際に、SWIGがその橋渡し役となります。SWIGは、C/C++のヘッダファイルやインターフェース定義ファイル (.i ファイル) を読み込み、ターゲット言語(この場合はGo)からC/C++関数を呼び出すためのラッパーコードと、C/C++側からGoの関数を呼び出すためのコールバックコードを生成します。
  • 共有ライブラリ (Shared Library): 複数のプログラムから共有して利用できるライブラリです。WindowsではDLL (Dynamic Link Library)、LinuxではSO (Shared Object) ファイルとして知られています。SWIGは、GoからC/C++コードを呼び出す際に、C/C++コードを共有ライブラリとしてコンパイルし、Goプログラムがそれをロードして利用する形式を取ることがあります。
  • オブジェクトファイル (Object File): コンパイラによってソースコードが機械語に変換された中間ファイルです。通常、.o.obj の拡張子を持ちます。これらのオブジェクトファイルがリンカによって結合され、実行可能ファイルや共有ライブラリが生成されます。
  • gcc / g++: GNU Compiler Collectionの一部であり、C言語およびC++言語のコンパイラです。Goのビルドシステムは、CgoやSWIGを使用する際に、内部的にこれらのコンパイラを呼び出してC/C++コードをコンパイルします。
  • ld (Linker): リンカは、コンパイルされたオブジェクトファイルやライブラリを結合して、最終的な実行可能ファイルや共有ライブラリを生成するツールです。

技術的詳細

このコミットの主要な変更点は以下の2つです。

  1. SWIG共有ライブラリへのC/C++ファイルの追加:

    • 以前の cmd/go のSWIG処理では、SWIGによって生成されたC/C++ラッパーコードはコンパイルされていましたが、ユーザーが提供する追加のC/C++ソースファイル (.c.cc) が共有ライブラリに適切に含まれていない可能性がありました。
    • このコミットでは、b.swig 関数が gccfiles (Cファイル) と gxxfiles (C++ファイル) の両方を受け取るように変更されました。
    • b.swig 関数内で、これらのC/C++ファイルが gcc または g++ を使用して個別にオブジェクトファイル (.o ファイル) にコンパイルされ、extraObj というスライスに追加されます。
    • 最終的に、SWIGによって生成される共有ライブラリをリンクする際に、これらの extraObj がリンカに渡されることで、ユーザーが提供するC/C++コードも共有ライブラリの一部として含まれるようになります。これにより、GoプログラムからSWIGを介してC/C++の機能全体を呼び出すことが可能になります。
  2. SWIG共有ライブラリ検索パスへのオブジェクトディレクトリの追加:

    • Goのビルドシステムは、SWIGによって生成された共有ライブラリをロードする際に、特定のディレクトリを検索します。
    • このコミットでは、gcToolchain.ld および tools gccgoToolchain.ld 関数内で、ビルドアクションのオブジェクトディレクトリ (a.objdir) がSWIG共有ライブラリの検索パス (swigDirs) に追加されるようになりました。
    • これにより、SWIGが生成した共有ライブラリが一時的なオブジェクトディレクトリに配置された場合でも、Goのビルドシステムがそのライブラリを確実に見つけてロードできるようになり、ビルドの失敗を防ぎます。

これらの変更により、GoとSWIGを組み合わせた開発において、C/C++コードの統合がよりスムーズになり、ビルドプロセスの信頼性が向上しました。

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

  • misc/swig/callback/callback.cc: 新規追加されたC++ファイル。SWIGのコールバック機能のテスト/サンプルコードの一部として追加されたようです。Caller::call() メソッドの実装が含まれています。
  • misc/swig/callback/callback.h: callback.cc に対応するヘッダファイル。Caller::call() の宣言が変更され、インライン実装から外部実装(callback.cc)に移行しています。これは、callback.cc がSWIG共有ライブラリに適切に含まれることをテストするための一環である可能性があります。
  • src/cmd/go/build.go: Goのビルドロジックの核心部分。
    • func (b *builder) build(a *action) (err error): b.swig の呼び出しが変更され、a.p.CXXFiles (C++ファイル) が新しい引数として渡されるようになりました。
    • func (gcToolchain) ld(...) および func (tools gccgoToolchain) ld(...): SWIG共有ライブラリの検索パスに a.objdir (アクションのオブジェクトディレクトリ) を追加するロジックが追加されました。
    • func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) ...: この関数のシグネチャが変更され、gxxfiles (C++ファイル) を受け取るようになりました。関数内で gccfilesgxxfiles のそれぞれに対して b.gcc または b.gxx を呼び出してオブジェクトファイルを生成し、extraObj スライスに格納するロジックが追加されています。
    • func (b *builder) swigOne(...): extraObj スライスを新しい引数として受け取るように変更され、最終的なリンカコマンド (b.run(...)) に extraObj が渡されるようになりました。

コアとなるコードの解説

src/cmd/go/build.go の変更点

  1. build メソッド内の swig 呼び出しの変更:

    // 変更前
    // outGo, outObj, err := b.swig(a.p, obj, gccfiles)
    // 変更後
    outGo, outObj, err := b.swig(a.p, obj, gccfiles, a.p.CXXFiles)
    

    b.swig 関数に、パッケージ (a.p) に含まれるC++ソースファイル (a.p.CXXFiles) が明示的に渡されるようになりました。これにより、SWIG処理においてC++ファイルも考慮されるようになります。

  2. ld メソッドにおけるSWIG共有ライブラリ検索パスの追加:

    // gcToolchain.ld および tools gccgoToolchain.ld 内
    if a.objdir != "" && !swigDirs[a.objdir] {
        swigArg[1] += ":"
        swigArg[1] += a.objdir
        swigDirs[a.objdir] = true
    }
    

    リンカがSWIG共有ライブラリを検索するパス (swigArg[1]) に、現在のビルドアクションのオブジェクトディレクトリ (a.objdir) が追加されます。これにより、SWIGが生成した共有ライブラリが一時的なビルドディレクトリに存在する場合でも、リンカがそれを見つけられるようになります。

  3. swig メソッドの変更:

    // 変更前
    // func (b *builder) swig(p *Package, obj string, gccfiles []string) (outGo, outObj []string, err error) {
    // 変更後
    func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles []string) (outGo, outObj []string, err error) {
        var extraObj []string
        for _, file := range gccfiles {
            // ... CファイルのコンパイルとextraObjへの追加 ...
        }
        for _, file := range gxxfiles {
            // ... C++ファイルのコンパイルとextraObjへの追加 ...
        }
        // ...
        // b.swigOne の呼び出しに extraObj を渡す
        // goFile, objFile, err := b.swigOne(p, f, obj, false, intgosize, extraObj)
    }
    

    swig 関数は、Cファイル (gccfiles) とC++ファイル (gxxfiles) の両方を受け取るようになりました。これらのファイルはそれぞれ b.gcc または b.gxx を使って個別にコンパイルされ、生成されたオブジェクトファイルは extraObj スライスに集められます。この extraObj は、後続の swigOne 関数に渡され、最終的な共有ライブラリのリンク時に使用されます。

  4. swigOne メソッドの変更:

    // 変更前
    // func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string) (outGo, outObj string, err error) {
    // 変更後
    func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize string, extraObj []string) (outGo, outObj string, err error) {
        // ...
        // b.run の呼び出しに extraObj を渡す
        // b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", target, gccObj, extraObj, ldflags)
    }
    

    swigOne 関数は、extraObj スライスを受け取るようになりました。この extraObj は、SWIGによって生成されたラッパーコードのオブジェクトファイル (gccObj) と共に、最終的な共有ライブラリを生成するためのリンカコマンド (b.run) に渡されます。これにより、ユーザーが提供するC/C++ソースファイルが共有ライブラリに正しくリンクされることが保証されます。

misc/swig/callback/callback.ccmisc/swig/callback/callback.h の変更点

これらのファイルは、SWIGのコールバック機能のテストまたはサンプルとして追加されたものです。callback.cc が新規追加され、callback.hCaller::call() メソッドがインライン実装から外部実装に変わっています。これは、cmd/go の変更が、このような外部のC++ソースファイルがSWIGによって生成される共有ライブラリに適切にコンパイル・リンクされることを保証するためのテストケースの一部である可能性が高いです。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/cmd/go/build.go)
  • SWIGのドキュメンテーション
  • C/C++コンパイル・リンクの一般的な知識
  • 共有ライブラリの概念に関する一般的な情報