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

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

このコミットは、Go言語のツールチェインを静的にリンクしてビルドする機能を追加するものです。具体的には、cmd/distツールとmake.bashスクリプトに変更が加えられ、GO_DISTFLAGSという新しい環境変数を導入することで、静的リンクされたツールチェインのビルドをサポートします。

コミット

commit 6b188ef57a644838bd4c673d6d14b49879db6297
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Oct 1 23:44:20 2013 -0400

    cmd/dist, build: support building statically linked toolchain
    
    Added a new $GO_DISTFLAGS to make.bash, and while we're here,
    added mention $CXX in make.bash (CL 13704044).
    
    Fixes #6448.
    Update #3564
    We can pass GO_DISTFLAGS=-s from misc/dist to make.bash so that
    it will build a statically linked toolchain.
    (Note: OS X doesn't have the concept of static linking, so don't
    pass GO_DISTFLAGS=-s for OS X builds)
    
    R=adg, rsc, iant
    CC=golang-dev
    https://golang.org/cl/13887043

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

https://github.com/golang/go/commit/6b188ef57a644838bd4c673d6d14b49879db6297

元コミット内容

cmd/dist, build: support building statically linked toolchain

このコミットは、Goのビルドシステムにおいて、静的にリンクされたツールチェインを構築する機能を追加します。make.bashスクリプトに$GO_DISTFLAGSという新しい環境変数が導入され、これを通じて静的リンクを制御できるようになります。また、make.bash$CXX(C++コンパイラ)に関する記述も追加されています(これは関連する変更として同時に行われました)。

この変更により、GO_DISTFLAGS=-smisc/distからmake.bashに渡すことで、静的にリンクされたツールチェインをビルドできるようになります。ただし、OS X(現在のmacOS)では静的リンクの概念が異なるため、OS Xビルドではこのフラグを渡すべきではないという注意書きがあります。

このコミットは、Issue #6448を修正し、Issue #3564を更新します。

変更の背景

このコミットの背景には、Goツールチェインの配布と実行に関する課題がありました。通常、Goのバイナリは動的にリンクされており、実行時にシステムに存在する共有ライブラリに依存します。しかし、異なる環境でGoツールチェインを実行する場合、必要な共有ライブラリが不足していると、ツールチェインが正しく動作しない可能性があります。

静的リンクされたバイナリは、必要なすべてのライブラリをバイナリ自体に含めるため、外部の共有ライブラリに依存しません。これにより、ツールチェインのポータビリティが向上し、様々な環境でのデプロイが容易になります。

コミットメッセージで言及されているIssue #6448は、まさにこの静的リンクの必要性に関する議論であり、Goツールチェインをより堅牢で移植性の高いものにするための要望に応えるものです。Issue #3564は、Goのビルドシステム全般に関するもので、このコミットはその一部を改善するものです。

前提知識の解説

1. 静的リンクと動的リンク

  • 静的リンク (Static Linking): プログラムがコンパイルされる際に、必要なライブラリのコードが実行可能ファイルに直接組み込まれる方式です。
    • 利点:
      • 実行可能ファイルが自己完結型になるため、他のシステムにデプロイする際にライブラリの依存関係を気にする必要がありません。
      • 起動が速い場合があります(共有ライブラリのロードが不要なため)。
    • 欠点:
      • 実行可能ファイルのサイズが大きくなります。
      • ライブラリの更新があった場合、そのライブラリを使用するすべてのプログラムを再コンパイルする必要があります。
      • 複数のプログラムが同じライブラリを使用する場合、メモリ上でライブラリのコードが重複してロードされる可能性があります。
  • 動的リンク (Dynamic Linking): プログラムが実行される際に、必要なライブラリがメモリにロードされ、プログラムとリンクされる方式です。共有ライブラリ(WindowsではDLL、Linuxでは.so、macOSでは.dylib)として提供されます。
    • 利点:
      • 実行可能ファイルのサイズが小さくなります。
      • ライブラリの更新があった場合、プログラムを再コンパイルすることなく、新しいライブラリを利用できます。
      • 複数のプログラムが同じライブラリを使用する場合、メモリ上でライブラリのコードが共有されるため、メモリ効率が良いです。
    • 欠点:
      • 実行時に必要な共有ライブラリが存在しない場合、プログラムが起動できません(「DLLが見つかりません」などのエラー)。
      • 起動に時間がかかる場合があります(共有ライブラリのロードとリンクが必要なため)。

Goのツールチェインを静的にリンクすることで、Goのコンパイラやその他のツールが、それらが実行されるシステムに特定の共有ライブラリが存在することを前提としなくなるため、より幅広い環境での利用が可能になります。

2. Goのビルドシステム (cmd/distmake.bash)

Go言語のビルドプロセスは、他の多くの言語とは異なり、Go自身でGoのコンパイラやツールチェインをビルドする「ブートストラップ」という仕組みを持っています。

  • make.bash: Goのソースコードリポジトリのルートにあるシェルスクリプトです。Goのツールチェイン全体をビルドするための主要なエントリポイントとなります。このスクリプトは、Goのコンパイラ、リンカ、アセンブラなどのツールをビルドし、Goの標準ライブラリをコンパイルします。
  • cmd/dist: Goのツールチェインの一部であり、make.bashによって呼び出される内部ツールです。distコマンドは、Goのビルドプロセスにおける様々な低レベルのタスク(例えば、ブートストラップコンパイラのビルド、標準ライブラリのインストール、テストの実行など)を管理します。このツールはGoで書かれており、Goのビルドシステムの中核をなします。

このコミットでは、make.bashcmd/distを呼び出す際に、静的リンクを指示するフラグを渡せるように変更されています。

3. GO_DISTFLAGS環境変数

Goのビルドプロセスでは、様々な環境変数を使用して挙動を制御できます。GO_DISTFLAGSは、このコミットで新しく導入された環境変数で、cmd/distツールに渡される追加のフラグを指定するために使用されます。これにより、make.bashからdistコマンドの挙動を外部からカスタマイズできるようになります。

技術的詳細

このコミットは、Goツールチェインのビルドプロセスに静的リンクのオプションを導入するために、以下の主要な変更を行っています。

  1. sflagの導入:

    • src/cmd/dist/a.h: sflagという新しいグローバル変数が宣言されています。これは、静的リンクオプションが有効になっているかどうかを示すフラグとして機能します。
    • src/cmd/dist/main.c: sflagが初期化され、cmd/distプロセス全体で利用可能になります。
  2. cmd/distでの-staticフラグの処理:

    • src/cmd/dist/build.c:
      • cmdbootstrap関数とcmdinstall関数(Goツールチェインのブートストラップビルドとインストールを担当)のコマンドライン引数解析部分に、新しいケース's'が追加されています。これにより、-sフラグが渡された場合にsflagがインクリメントされます。
      • install関数内で、sflagが設定されている場合に、コンパイラ(gccなど)に渡すリンクオプションに-staticが追加されるようになります。これは、GoのツールチェインがC/C++コード(例えば、cgoが使用するランタイムサポートや、一部の低レベルなアセンブリコード)をコンパイル・リンクする際に、静的リンクを強制するための重要な変更です。
  3. make.bashでのGO_DISTFLAGSの利用:

    • src/make.bash:
      • 新しい環境変数GO_DISTFLAGSに関する説明が追加されています。この変数はdist bootstrapに渡される追加フラグを指定するために使用され、-sを渡すことで静的リンクされたツールチェインをビルドできることが明記されています。
      • ./cmd/dist/dist bootstrapコマンドの呼び出し部分に$GO_DISTFLAGSが追加されています。これにより、make.bashを実行する際にGO_DISTFLAGS環境変数を設定することで、distコマンドに-sフラグを渡すことが可能になります。
  4. CXXの言及追加:

    • src/make.bash: CC(Cコンパイラ)の記述に加えて、CXX(C++コンパイラ)に関する記述が追加されています。これは、cgoを使用する際にC++コンパイラが関与する場合があるため、その設定方法を明確にするためのものです。この変更は静的リンク機能とは直接関係ありませんが、同じコミットで同時に行われました。

これらの変更により、ユーザーはGO_DISTFLAGS=-s ./make.bashのようにコマンドを実行することで、Goツールチェイン全体を静的にリンクされたバイナリとしてビルドできるようになります。これにより、ビルドされたツールチェインは、実行環境に特定の共有ライブラリが存在しなくても動作するようになります。

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

src/cmd/dist/a.h

--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -112,6 +112,7 @@ void	goc2c(char*, char*);
 
 // main.c
 extern int vflag;
+extern int sflag;
 void	usage(void);
 void	xmain(int argc, char **argv);
 

sflagという新しい外部変数が宣言されています。これは、静的リンクモードが有効かどうかを示すフラグとして使用されます。

src/cmd/dist/build.c

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -720,6 +720,8 @@ install(char *dir)
 		tvadd(&link, bpathf(&b, "%s/%s", tooldir, name));
 	} else {
 		vcopy(&link, gccargs.p, gccargs.len);
+		if(sflag)
+			tvadd(&link, "-static");
 		tvadd(&link, "-o");
 		targ = link.len;
 		tvadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
@@ -1527,6 +1529,9 @@ cmdbootstrap(int argc, char **argv)
 	case 'a':
 		rebuildall = 1;
 		break;
+	case 's':
+		sflag++;
+		break;
 	case 'v':
 		vflag++;
 		break;
@@ -1613,6 +1618,9 @@ cmdinstall(int argc, char **argv)
 	int i;
 
 	ARGBEGIN{
+	case 's':
+		sflag++;
+		break;
 	case 'v':
 		vflag++;
 		break;

install関数内で、sflagが真の場合にリンカオプションとして-staticが追加されるようになります。これにより、Goツールチェインが依存するC/C++コードが静的にリンクされます。 また、cmdbootstrapcmdinstall関数に-sオプションの処理が追加され、このオプションが渡されるとsflagがインクリメントされます。

src/cmd/dist/main.c

--- a/src/cmd/dist/main.c
+++ b/src/cmd/dist/main.c
@@ -5,6 +5,7 @@
 #include "a.h"
 
 int vflag;
+int sflag;
 char *argv0;
 
 // cmdtab records the available commands.

sflagが定義され、cmd/distプログラム全体で利用可能なグローバル変数として設定されています。

src/make.bash

--- a/src/make.bash
+++ b/src/make.bash
@@ -37,6 +37,11 @@
 #
 # CC: Command line to run to get at host C compiler.
 # Default is "gcc". Also supported: "clang".
+# CXX: Command line to run to get at host C++ compiler, only recorded
+# for cgo use. Default is "g++". Also supported: "clang++".
+#
+# GO_DISTFLAGS: extra flags to provide to "dist bootstrap". Use "-s"
+# to build a statically linked toolchain.
 
 set -e
 if [ ! -f run.bash ]; then
@@ -140,7 +145,7 @@ buildall=\"-a\"\n if [ \"$1\" = \"--no-clean\" ]; then
 \tbuildall=\"\"\n fi
-./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap
+./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
 # Delay move of dist tool to now, because bootstrap may clear tool directory.
 mv cmd/dist/dist "$GOTOOLDIR"/dist
 "$GOTOOLDIR"/go_bootstrap clean -i std

GO_DISTFLAGSという新しい環境変数に関する説明が追加され、-sフラグを使って静的リンクされたツールチェインをビルドできることが示されています。 ./cmd/dist/dist bootstrapコマンドの呼び出しに$GO_DISTFLAGSが追加され、この環境変数を介してdistコマンドにフラグを渡せるようになります。 また、CXX環境変数に関する説明も追加されています。

コアとなるコードの解説

このコミットの核心は、GoのビルドシステムがC/C++コンパイラ(通常はGCCやClang)を呼び出す際に、静的リンクを指示する-staticフラグを条件付きで追加するロジックにあります。

  1. sflagの役割: sflagは、ユーザーが静的リンクを要求したかどうかをcmd/distツール全体で追跡するための単純な整数フラグです。コマンドラインで-sオプションが指定されるたびにインクリメントされます。

  2. build.cにおける-staticの挿入:

    • src/cmd/dist/build.cinstall関数は、Goツールチェインの各コンポーネント(コンパイラ、リンカなど)をビルドし、インストールする役割を担っています。
    • この関数内で、GoのツールがC/C++コードをコンパイル・リンクするために外部のC/C++コンパイラ(gccなど)を呼び出す部分があります。
    • if(sflag)という条件文が追加され、もしsflagが設定されていれば、vadd(&link, "-static");という行が実行されます。これは、コンパイラに渡される引数リストに-staticという文字列を追加することを意味します。
    • -staticフラグは、GCCやClangのようなコンパイラに対して、可能な限りすべてのライブラリを静的にリンクするよう指示する標準的なオプションです。これにより、Goツールチェインが依存するCランタイムライブラリなどが、共有ライブラリとしてではなく、ツールチェインのバイナリ自体に組み込まれるようになります。
  3. make.bashGO_DISTFLAGSの連携:

    • make.bashはGoのビルドプロセスの最上位スクリプトです。
    • 以前は、./cmd/dist/dist bootstrapというコマンドが直接呼び出されていましたが、このコミットにより$GO_DISTFLAGSが追加されました。
    • これにより、ユーザーはGO_DISTFLAGS="-s" ./make.bashのように環境変数を設定してmake.bashを実行することで、dist bootstrapコマンドに-sフラグを透過的に渡すことができます。
    • distコマンドは-sフラグを受け取ると、内部のsflagをセットし、その後のビルドプロセスでC/C++コンパイラを呼び出す際に-staticオプションを付加するようになります。

この一連の変更により、Goツールチェインのビルド時に静的リンクを簡単に有効にできるようになり、Goツールのポータビリティと独立性が向上しました。ただし、OS Xでは静的リンクの概念が異なるため、このフラグは適用されないという注意が必要です。これは、OS Xのシステムライブラリが通常、動的リンクを前提としているためです。

関連リンク

参考にした情報源リンク