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

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

このコミットは、Go言語のビルドシステムにおける改善を目的としています。具体的には、buildscript.shがすべての$GOOS/$GOARCH(オペレーティングシステム/アーキテクチャ)の組み合わせに対してビルドスクリプトを正しく生成できるように、cmd/goのためのダミーファイルを生成する変更が含まれています。これにより、クロスコンパイル環境でのビルドプロセスの堅牢性が向上しています。

コミット

commit 0ae6084fefd3707766e98e20e775b2fb4c0c4dc7
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Jan 24 15:03:41 2012 -0500

    build: do not build all C compilers
            In order to allow buildscript.sh to generate buildscripts for all
            $GOOS/$GOARCH combinations, we have to generate dummy files for cmd/go.
            Fixes #2586.
    
    R=rsc, golang-dev
    CC=golang-dev
    https://golang.org/cl/5557050

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

https://github.com/golang/go/commit/0ae6084fefd3707766e98e20e775b2fb4c0c4dc7

元コミット内容

build: do not build all C compilers
        In order to allow buildscript.sh to generate buildscripts for all
        $GOOS/$GOARCH combinations, we have to generate dummy files for cmd/go.
        Fixes #2586.

変更の背景

このコミットの背景には、Go言語のビルドシステムが抱えていた特定の問題があります。Goは、異なるオペレーティングシステム($GOOS)やアーキテクチャ($GOARCH)向けにバイナリを生成する「クロスコンパイル」機能を強力にサポートしています。しかし、buildscript.shというスクリプトが、すべての$GOOS/$GOARCHの組み合わせに対してビルドスクリプトを正しく生成できないという問題が存在していました。

具体的には、cmd/go(Goコマンド自体)のビルドプロセスにおいて、特定のCコンパイラが常に利用可能であると仮定されていた可能性があります。クロスコンパイル環境では、ターゲットとなるOSやアーキテクチャに対応するCコンパイラが、ホスト環境に常に存在したり、ビルド時に自動的に生成されたりするわけではありません。この不整合が、buildscript.shが完全なビルドスクリプトを生成する際の障害となっていました。

このコミットは、この問題を解決し、buildscript.shがより柔軟に、かつ堅牢に動作するようにするためのものです。コミットメッセージにある「Fixes #2586」は、この変更が特定のバグまたは課題(GoプロジェクトのIssue #2586)を修正するものであることを示唆しています。

前提知識の解説

このコミットを理解するためには、以下のGo言語のビルドシステムに関する前提知識が必要です。

  • $GOOS$GOARCH: Go言語の環境変数で、それぞれターゲットとなるオペレーティングシステム(例: linux, windows, darwin)とアーキテクチャ(例: amd64, 386, arm)を指定します。Goはこれらの変数に基づいてクロスコンパイルを行います。
  • クロスコンパイル: あるプラットフォーム(ホスト)で、別のプラットフォーム(ターゲット)向けの実行可能ファイルを生成するプロセスです。Goは言語レベルでクロスコンパイルを強力にサポートしており、開発者は異なる環境向けのバイナリを簡単に作成できます。
  • cmd/go: Go言語のコマンドラインツール(go build, go run, go testなど)を提供するバイナリです。Go言語のビルドシステムの中核をなします。
  • Cコンパイラ(5c, 6c, 8cなど): Go言語の初期のバージョンでは、一部の低レベルなコード(特にランタイムやアセンブリコード)をコンパイルするために、Go独自のCコンパイラが使用されていました。5cはPlan 9の5cコンパイラに由来し、armアーキテクチャ向け、6camd64向け、8c386向けといったように、特定のアーキテクチャに対応していました。これらのコンパイラはGoのソースコードから生成されることがありました。
  • Makefile: ビルドプロセスを自動化するためのツールで、Goプロジェクトでもビルドの依存関係やコマンドを定義するために広く使用されています。
  • mkasmh.sh / mkgodefs.sh: Goのランタイムパッケージ内で使用されるシェルスクリプトで、アセンブリヘッダーファイルやGoの定義ファイル(Cの構造体などをGoの型にマッピングしたもの)を生成するために使われます。これらのスクリプトは、Cコンパイラを使用してCコードを処理し、Goのビルドに必要なファイルを生成します。
  • buildscript.sh: Goのビルドプロセスの一部として、最終的なビルドスクリプトを生成するために使用されるスクリプトです。これは、GoのソースコードからGoツールチェーン全体をビルドする際に重要な役割を果たします。

技術的詳細

このコミットの技術的な核心は、Goのビルドシステムが、すべてのターゲットアーキテクチャ用のCコンパイラを常にビルドする必要がないように変更された点にあります。以前のビルドシステムでは、src/cmd/Makefileにおいて、5c, 6c, 8cといった特定のCコンパイラが常にビルド対象として明示的にリストアップされていました。これは、ランタイムの生成ファイルなどを再ビルドするために、これらのコンパイラが常に必要であるという前提に基づいていたためです。

しかし、クロスコンパイルのシナリオでは、ホスト環境でターゲットアーキテクチャ用のCコンパイラが利用できない場合や、そもそもそのコンパイラが不要な場合があります。このコミットでは、src/cmd/Makefileからこれらの特定のCコンパイラのビルド指示を削除し、代わりに$(O)cという汎用的なプレースホルダーを使用するように変更しています。$(O)cは、現在の$GOOS/$GOARCHの組み合わせに対応するCコンパイラを指すように解決されます。これにより、不要なCコンパイラのビルドが回避され、ビルドプロセスの効率が向上します。

さらに重要な変更は、src/pkg/runtime/mkasmh.shsrc/pkg/runtime/mkgodefs.shという2つのシェルスクリプトに加えられた修正です。これらのスクリプトは、Goのランタイムに必要なアセンブリヘッダーやGoの定義ファイルを生成する際にCコンパイラを使用します。以前は、これらのスクリプトはCコンパイラが常に存在し、実行可能であると仮定していました。

このコミットでは、これらのスクリプトに以下のロジックが追加されています。

  1. Cコンパイラの存在チェック: スクリプトの冒頭で、$GOBIN(Goのバイナリがインストールされるディレクトリ)に指定されたCコンパイラ($CC)が実行可能であるかどうかをチェックします。
  2. ダミーファイルの生成: もしCコンパイラが実行可能でない場合(これはクロスコンパイル環境でターゲットアーキテクチャ用のCコンパイラが利用できない場合に発生しえます)、スクリプトは実際の処理をスキップし、代わりに「ダミーファイル」を生成して終了します。このダミーファイルは、cmd/goがビルドスクリプトを正しく生成するために必要な最小限のプレースホルダーとして機能します。例えば、mkasmh.shでは// dummy file for cmd/go to correctly generate buildscriptというコメントを含むファイルが、mkgodefs.shではpackage runtimeという行を含むファイルが生成されます。
  3. $GOBIN/$CCの使用: Cコンパイラを呼び出す際に、単に$CCとするのではなく、$GOBIN/$CCと明示的にパスを指定するように変更されています。これにより、システムパスに依存せず、Goのビルドシステムが管理するCコンパイラを確実に使用できるようになります。

これらの変更により、buildscript.shは、たとえ特定のCコンパイラがビルド時に利用できなくても、すべての$GOOS/$GOARCHの組み合わせに対してビルドスクリプトを生成できるようになります。これは、Goのクロスコンパイル機能の柔軟性と堅牢性を大幅に向上させるものです。

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

このコミットによる主要なコード変更は以下の3つのファイルに集中しています。

  1. src/cmd/Makefile:

    • DIRS変数から、特定のCコンパイラ(5c, 6c, 8c)の明示的なビルド指示が削除されました。
    • 代わりに、汎用的な$(O)cが追加されました。
    --- a/src/cmd/Makefile
    +++ b/src/cmd/Makefile
    @@ -8,12 +8,9 @@ all: install
     
     # Only build tools for current architecture, and only tools written in C.
     # The tools written in Go are managed by ../pkg/Makefile.
    -# We need all the C compilers for rebuilding generated files in runtime.
     DIRS=\
      	$(O)a\\\
    -\t5c\\\
    -\t6c\\\
    -\t8c\\\
    +\t$(O)c\\\
      	$(O)g\\\
      	$(O)l\\\
      	cc\\\
    
  2. src/pkg/runtime/mkasmh.sh:

    • Cコンパイラが存在しない場合にダミーファイルを生成するロジックが追加されました。
    • Cコンパイラの呼び出しが$CCから$GOBIN/$CCに変更されました。
    --- a/src/pkg/runtime/mkasmh.sh
    +++ b/src/pkg/runtime/mkasmh.sh
    @@ -29,6 +29,10 @@ cat <<'EOF'
     // AUTO-GENERATED by autogen.sh; DO NOT EDIT
     
     EOF
    +if [ ! -x "${GOBIN:=$GOROOT/bin}/$CC" ]; then
    +\techo "// dummy file for cmd/go to correctly generate buildscript"
    +\texit
    +fi
     
      case "$GOARCH" in
      386)
    @@ -110,7 +114,7 @@ arm)
      esac
      echo
      
    -$CC $CFLAGS -a proc.c |
    +$GOBIN/$CC $CFLAGS -a proc.c |
      awk '\
      { gsub(/\r/, ""); }\
      /^aggr G$/ { aggr="g" }
    
  3. src/pkg/runtime/mkgodefs.sh:

    • Cコンパイラが存在しない場合にダミーファイルを生成するロジックが追加されました。
    • Cコンパイラの呼び出しが$CCから$GOBIN/$CCに変更されました。
    --- a/src/pkg/runtime/mkgodefs.sh
    +++ b/src/pkg/runtime/mkgodefs.sh
    @@ -27,7 +27,14 @@ cp signals_$GOOS.h signals_GOOS.h
     cat <<EOF
      // Go definitions for C variables and types.
      // AUTO-GENERATED by autogen.sh; DO NOT EDIT
    +EOF
    +if [ ! -x "${GOBIN:=$GOROOT/bin}/$CC" ]; then
    +\techo "// dummy file for cmd/go to correctly generate buildscript"
    +\techo "package runtime"
    +\texit
    +fi
      
    +cat <<EOF
      package runtime
      import "unsafe"
      var _ unsafe.Pointer
    @@ -35,7 +42,7 @@ var _ unsafe.Pointer
      EOF
      
      for i in "$@"; do
    -\t$CC $CFLAGS -q $i
    +\t$GOBIN/$CC $CFLAGS -q $i
      done | awk '\
      /^func/ { next }\
      /^const/ { next }\
    

コアとなるコードの解説

このコミットの核心は、Goのビルドシステムが、特定のCコンパイラに過度に依存することなく、より柔軟に動作するように設計された点にあります。

src/cmd/Makefileの変更は、ビルド対象となるCコンパイラを特定のアーキテクチャに限定せず、現在のビルド環境($GOOS/$GOARCH)に応じて適切なCコンパイラ($(O)c)のみをビルドするように指示しています。これにより、例えばamd64環境でarm向けのCコンパイラをビルドする必要がなくなります。

src/pkg/runtime/mkasmh.shsrc/pkg/runtime/mkgodefs.shの変更は、Goのクロスコンパイル戦略において非常に重要です。これらのスクリプトは、GoのランタイムがCコードと連携するために必要なヘッダーファイルや定義ファイルを生成します。以前は、これらのスクリプトはCコンパイラが常に利用可能であることを前提としていました。しかし、クロスコンパイルのシナリオでは、ターゲットアーキテクチャ用のCコンパイラがホスト環境にインストールされていない場合があります。

追加されたif [ ! -x "${GOBIN:=$GOROOT/bin}/$CC" ]; then ... fiブロックは、この問題を解決します。

  • "${GOBIN:=$GOROOT/bin}/$CC": これは、Cコンパイラのパスを構築しています。$GOBINが設定されていればそれを使用し、そうでなければ$GOROOT/binをデフォルトとして使用します。
  • [ ! -x ... ]: これは、指定されたパスのファイルが存在し、かつ実行可能でない場合に真となります。つまり、Cコンパイラが見つからないか、実行権限がない場合にこの条件が満たされます。

この条件が真の場合、スクリプトは実際のCコンパイラを使った処理をスキップし、代わりに簡単なダミーファイルを出力して終了します。このダミーファイルは、Goのビルドシステムが後続のステップでエラーを起こさずに進むために必要な最小限の構造を提供します。例えば、mkgodefs.shが生成するダミーファイルにはpackage runtimeという行が含まれており、これはGoのパッケージとして認識されるために最低限必要な情報です。

この「ダミーファイル生成」のメカニズムは、Goのビルドシステムが、完全なCコンパイラが利用できない場合でも、ビルドスクリプトの生成を継続できるようにするための巧妙なフォールバック戦略です。これにより、buildscript.shは、すべての$GOOS/$GOARCHの組み合わせに対して、たとえ一部のツールが利用できない環境であっても、ビルドスクリプトを生成できるようになり、Goのクロスコンパイルの柔軟性と信頼性が向上しました。

関連リンク

  • Go言語の公式Issueトラッカー: https://github.com/golang/go/issues (Issue #2586に関連する情報がある可能性がありますが、直接的なリンクはコミットメッセージにはありませんでした。)
  • Go言語のコードレビューシステム (Gerrit): https://golang.org/cl/5557050 (このコミットの元の変更リスト)

参考にした情報源リンク

  • Go言語のソースコード (特にsrc/cmd/Makefile, src/pkg/runtime/mkasmh.sh, src/pkg/runtime/mkgodefs.sh): https://github.com/golang/go
  • Go言語のクロスコンパイルに関するドキュメント (Goの公式ドキュメントやブログ記事): https://go.dev/doc/
  • Go言語のビルドシステムに関する一般的な情報源 (Goの内部構造に関する記事や書籍)