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

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

このコミットは、Go言語のビルドツール (cmd/go) において、Cgoを使用する際に.sysoファイルを適切にリンクできるようにする変更を導入しています。これにより、Cgoを介してC言語の関数が.sysoファイルに実装されている場合に発生していた未定義シンボルの問題を解決します。

コミット

commit 2f2df2aceb4fdd02ac4a93e43a823a55341c9439
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Sat Aug 4 18:02:12 2012 +0300

    cmd/go: allow to use syso files with cgo
    I have C functions implemented in .syso file (rather than .so or inlined in .go file).
    W/o this change the gcc invocation fails with undefined symbols.
    
    R=minux.ma, rsc
    CC=golang-dev
    https://golang.org/cl/6352076

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

https://github.com/golang/go/commit/2f2df2aceb4fdd02ac4a93e43a823a55341c9439

元コミット内容

cmd/goツールがCgoを使用する際に、.sysoファイルを利用できるようにする。 コミットの作者は、C関数を.sysoファイルに実装しており、この変更がないとgccの呼び出しが未定義シンボルエラーで失敗すると述べている。

変更の背景

Go言語はCgoという機能を提供しており、これによりGoプログラムからC言語のコードを呼び出すことができます。Cgoを使用する際、C言語のソースコードはGoのビルドプロセス中にコンパイルされ、Goの実行可能ファイルにリンクされます。

しかし、C言語の関数が.goファイル内に直接インラインで記述されているか、または共有ライブラリ(.soなど)として提供されるのではなく、事前にコンパイルされたオブジェクトファイルである.sysoファイルとして提供される場合があります。

このコミットが導入される前は、Goのビルドツール(cmd/go)がCgoのビルドプロセスにおいて、.sysoファイルに含まれるシンボルを適切にリンクしていませんでした。その結果、Cgoを介して.sysoファイル内のC関数を呼び出そうとすると、リンカがそれらのシンボルを見つけられず、「undefined symbols」(未定義シンボル)エラーが発生していました。

この変更は、GoのビルドプロセスがCgoを使用する際に、プロジェクト内の.sysoファイルを自動的に検出し、リンク対象に含めることで、この未定義シンボルエラーを解消し、より柔軟なCgoの利用を可能にすることを目的としています。

前提知識の解説

Go言語のビルドプロセス

Go言語のプログラムは、go buildコマンドによってコンパイルされ、実行可能なバイナリが生成されます。このプロセスには、ソースコードのコンパイル、依存関係の解決、そして最終的な実行可能ファイルのリンクが含まれます。リンカは、コンパイルされたオブジェクトファイルやライブラリを結合して、完全なプログラムを作成する役割を担います。

Cgo

Cgoは、GoプログラムからC言語のコードを呼び出すためのGoの機能です。Goのソースファイル内にimport "C"という行を記述し、その後にC言語のコードをコメント形式で記述することで、GoとCの相互運用が可能になります。Cgoを使用すると、Goのビルドツールは内部的にCコンパイラ(通常はGCC)を呼び出し、Cコードをコンパイルし、Goのコードとリンクします。

.sysoファイル

.sysoファイルは、Go言語のビルドシステムにおいて特別な意味を持つファイルです。これらは「system object」ファイルの略で、Goのビルドプロセス中に自動的にリンクされる、事前にコンパイルされたオブジェクトファイル(通常はC、C++、またはアセンブリ言語で書かれたコード)です。

  • 自動リンク: .sysoファイルがGoのソースコードと同じディレクトリに配置されている場合、go buildコマンドは自動的にそのファイルを検出し、最終的な実行可能ファイルにリンクします。
  • 用途:
    • Cgoとの連携: Cgoを使用する際に、C言語のコードを.goファイル内に直接記述する代わりに、外部のC/C++コンパイラでコンパイルしたオブジェクトファイル(.o.obj)を.sysoとして提供し、Goのビルドプロセスに含めることができます。これにより、複雑なCコードの管理や、特定のプラットフォーム向けに最適化されたCコードの配布が容易になります。
    • リソースの埋め込み: Windows環境では、バージョン情報、アイコン、マニフェストなどのリソースをGoの実行可能ファイルに埋め込むためによく使用されます。
    • アセンブリコードの埋め込み: パフォーマンスが重要な部分で、GoのABI(Application Binary Interface)に準拠したアセンブリコードを直接埋め込むためにも使用されることがあります。

未定義シンボル (Undefined Symbols)

プログラムのリンク時に発生するエラーの一種です。これは、プログラムが参照している関数や変数などのシンボルが、リンク対象のどのオブジェクトファイルやライブラリにも見つからない場合に発生します。リンカは、すべての参照が解決されるまで実行可能ファイルを生成できません。

技術的詳細

このコミットの技術的な核心は、GoのビルドツールがCgoのビルドフェーズで、Goパッケージに属する.sysoファイルをリンカに渡すように変更された点にあります。

Goのビルドプロセスにおいて、src/cmd/go/build.goファイルは、Goコマンドのビルドロジックの大部分を担っています。特に、Cgoに関連する処理は、このファイル内のcgo関数によって管理されています。この関数は、Cgoのソースファイルをコンパイルし、Goのコードとリンクするために必要なgccコマンドの呼び出しを構築します。

変更前は、cgo関数がgccに渡すオブジェクトファイルのリスト(linkobj)に、Goのソースファイルから生成されたオブジェクトファイルやCgoが生成したオブジェクトファイルは含まれていましたが、Goパッケージに属する.sysoファイルは含まれていませんでした。

このコミットでは、p.SysoFilesという、現在のパッケージ(p)に関連付けられた.sysoファイルのリストを、linkobjスライスに追加しています。これにより、gccが最終的なリンクを行う際に、これらの.sysoファイルも考慮されるようになり、.sysoファイル内に定義されているC関数などのシンボルが正しく解決されるようになります。

具体的には、build.go内のcgo関数が、Cgoによって生成されたオブジェクトファイル(ofile)をlinkobjに追加した後、パッケージの.sysoファイルもlinkobjに追加するように修正されています。これにより、Goのビルドシステムは、Cgoのコンパイルとリンクの過程で、ユーザーが提供した.sysoファイルを自動的に含めることができるようになります。

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

diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index ecb2454212..0ded45ed19 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1576,6 +1576,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n 		linkobj = append(linkobj, ofile)\n 		outObj = append(outObj, ofile)\n 	}\n+\tlinkobj = append(linkobj, p.SysoFiles...)\n 	dynobj := obj + "_cgo_.o"\n 	if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym\n 		cgoLDFLAGS = append(cgoLDFLAGS, "-pie")

コアとなるコードの解説

変更はsrc/cmd/go/build.goファイルの1行の追加のみです。

linkobj = append(linkobj, p.SysoFiles...)
  • linkobj: これは、Cgoのビルドプロセスにおいて、最終的にgccなどのCコンパイラ/リンカに渡されるオブジェクトファイルのパスのリストを保持するスライスです。
  • p: 現在ビルド中のGoパッケージを表す構造体です。
  • p.SysoFiles: pパッケージに関連付けられたすべての.sysoファイルのパスのリストです。Goのビルドシステムは、パッケージディレクトリ内の.sysoファイルを自動的に検出し、このリストに格納します。
  • ...: これはGoのスライス展開演算子です。p.SysoFilesスライスのすべての要素を個別の引数としてappend関数に渡します。

この行が追加されることで、Cgoのビルドプロセス中に、Goパッケージが持つ.sysoファイルが、Cコンパイラ/リンカが処理するオブジェクトファイルのリストに明示的に追加されるようになります。これにより、.sysoファイル内のシンボルがGoの実行可能ファイルに正しくリンクされ、未定義シンボルエラーが解消されます。

関連リンク

参考にした情報源リンク