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

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

このコミットは、Go言語の標準ライブラリの一部であるlib9/fmtパッケージ内のtest.cファイルが、ライブラリアーカイブlib9.amainシンボルを含めてしまう問題を修正するものです。具体的には、test.cファイルをビルドプロセスから除外することで、この問題を解決しています。

コミット

commit 44336459c833ca728133d0769c71691d43a1cf20
Author: Russ Cox <rsc@golang.org>
Date:   Mon Sep 24 12:57:05 2012 -0400

    lib9/fmt: do not put a main symbol into lib9.a
    
    Fixes #4143.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/6541064

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

https://github.com/golang/go/commit/44336459c833ca728133d0769c71691d43a1cf20

元コミット内容

このコミットの目的は、「lib9/fmtlib9.amainシンボルを含めないようにする」ことです。これは、Issue #4143を修正するための変更であり、test.cファイルがビルドプロセスから除外されるように修正されています。

変更の背景

Go言語の初期のバージョンでは、一部の標準ライブラリ(特にlib9関連)は、Plan 9オペレーティングシステム由来のC言語コードを含んでいました。これらのCコードは、Goのビルドシステムによってコンパイルされ、ライブラリアーカイブ(.aファイル)としてリンクされることがありました。

test.cのようなテスト用のCファイルには、通常、独立して実行可能なプログラムとして機能するためのmain関数が含まれています。しかし、このtest.cが誤ってlib9.aというライブラリアーカイブにコンパイルされてしまうと、問題が発生します。

ライブラリは、他のプログラムから利用されることを目的としており、通常はmain関数を含みません。もしライブラリがmain関数を含んでしまうと、そのライブラリを利用する別のプログラムが独自のmain関数を持っている場合に、リンカが複数のmainシンボルを見つけてしまい、シンボル衝突エラー("multiple definition of main"など)を引き起こす可能性があります。これは、GoプログラムがCgoを介してCライブラリをリンクする際に特に問題となります。

このコミットは、このシンボル衝突の問題(Issue #4143)を解決するために行われました。test.cはテスト目的のファイルであり、最終的なライブラリには含まれるべきではないため、ビルドプロセスから明示的に除外する必要がありました。

前提知識の解説

  1. Go言語のビルドシステムとビルドタグ(Build Tags): Go言語のビルドシステムは、ソースファイルをコンパイルする際に、特定の条件に基づいてファイルを含めたり除外したりする機能を持っています。この機能は「ビルドタグ」または「ビルド制約(Build Constraints)」と呼ばれ、ソースファイルの先頭に特別なコメントとして記述されます。

    • // +build tag_name (Go 1.17以前の構文) または //go:build tag_name (Go 1.17以降の構文)
    • これらのタグは、OS、アーキテクチャ、またはカスタムタグに基づいてファイルを条件付きでコンパイルするために使用されます。
    • // +build ignore ディレクティブは、そのファイルがGoの標準ビルドプロセスから完全に無視されるべきであることをGoツールチェインに指示します。これは、テストユーティリティ、コード生成スクリプト、または特定の環境でのみ使用されるべきファイルなど、通常のパッケージの一部としてコンパイルされるべきではないファイルによく使用されます。
  2. lib9.a: lib9.aは、Go言語の初期のコードベースにおいて、Plan 9オペレーティングシステムから派生したC言語のユーティリティ関数群を含む静的ライブラリです。Go言語自体がPlan 9の影響を強く受けているため、初期のGoランタイムや標準ライブラリには、Plan 9の慣習やコードが取り入れられていました。.a拡張子は、Unix系システムにおける静的ライブラリアーカイブを示します。

  3. mainシンボルとリンカ: C言語やGo言語のようなコンパイル型言語では、プログラムのエントリポイント(実行開始点)は通常main関数です。コンパイラはmain関数をコンパイルして、実行可能ファイル内にmainというシンボル(記号)を生成します。 リンカは、コンパイルされたオブジェクトファイルやライブラリを結合して最終的な実行可能ファイルを生成するツールです。リンカは、プログラムのエントリポイントとしてmainシンボルを探します。もし複数のmainシンボルが見つかった場合、リンカはどのmain関数から実行を開始すべきか判断できず、エラー(多重定義エラー)を報告します。ライブラリは通常、それ自体が実行可能ファイルではないため、main関数を持つべきではありません。

技術的詳細

このコミットの技術的な核心は、GoのビルドシステムがC言語のソースファイルをどのように扱うか、そして// +build ignoreディレクティブがそのプロセスにどのように影響するかという点にあります。

Goのビルドシステムは、Go言語のソースファイルだけでなく、Cgo(GoとCの相互運用機能)を通じてC言語のソースファイルもコンパイルできます。src/lib9/fmt/test.cは、lib9/fmtパッケージの一部として扱われていたC言語のテストファイルでした。

// +build ignoreディレクティブは、Goツールチェインに対して、そのファイルが通常のビルドプロセスの一部ではないことを明示的に伝えます。このディレクティブがファイルに追加されると、go buildコマンドはそのファイルをコンパイル対象から除外します。これにより、test.cに含まれるmain関数がlib9.aに誤ってリンクされることがなくなります。

この修正は、Goのビルドシステムが、テストコードやユーティリティスクリプトなど、特定の目的のために存在するが、最終的なバイナリやライブラリには含まれるべきではないファイルを適切に管理するための標準的なメカニズムを利用したものです。これにより、リンカエラーを防ぎ、ライブラリの整合性を保つことができます。

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

--- a/src/lib9/fmt/test.c
+++ b/src/lib9/fmt/test.c
@@ -1,3 +1,5 @@
+// +build ignore
+
 /*
  * The authors of this software are Rob Pike and Ken Thompson,
  * with contributions from Mike Burrows and Sean Dorward.

コアとなるコードの解説

変更はsrc/lib9/fmt/test.cファイルの冒頭に2行を追加するだけです。

  1. // +build ignore この行は、Goのビルドタグ(Build Tag)ディレクティブです。これはGoツールチェインに対して、このファイル(test.c)を通常のビルドプロセスから完全に無視するよう指示します。つまり、go buildコマンドが実行された際に、このCファイルはコンパイルされなくなり、その結果、ファイル内のmain関数がlib9.aライブラリに誤って含まれることがなくなります。

  2. // この行は単なる空のコメント行です。+buildディレクティブはファイルの先頭に記述される必要があり、その直後に続くコードとの間に空白行を設けることで、可読性を向上させています。技術的な機能はありません。

このシンプルな変更により、test.cはGoのビルドシステムによって無視されるようになり、mainシンボルがlib9.aに混入する問題が解決されました。

関連リンク

参考にした情報源リンク