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

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

コミット

commit 41a6165c030c41cc7e44b28c251b22c49fb9618b
Author: Russ Cox <rsc@golang.org>
Date:   Tue Dec 20 16:50:13 2011 -0500

    build: use go command during build

    If something goes wrong, it should suffice to set
    USE_GO_TOOL=false in env.bash to fall back to the
    makefiles.  I will delete the makefiles in January.

    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5502047

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

https://github.com/golang/go/commit/41a6165c030c41cc7e44b28c251b22c49fb9618b

元コミット内容

build: use go command during build

If something goes wrong, it should suffice to set
USE_GO_TOOL=false in env.bash to fall back to the
makefiles.  I will delete the makefiles in January.

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5502047

変更の背景

このコミット(インデックス10909、ハッシュ41a6165c030c41cc7e44b28c251b22c49fb9618b)は、Go言語のビルドシステムにおける重要な移行を示しています。それまでのGoのビルドプロセスは、主にmakeコマンドとMakefile群に依存していました。しかし、Go言語自体が成熟し、そのエコシステムが拡大するにつれて、Go言語で書かれたツール(特にgoコマンド)がGoプロジェクトのビルド、テスト、パッケージ管理などを一元的に扱うようになりました。

この変更の背景には、以下のような目的があったと考えられます。

  1. ビルドプロセスの自己完結性向上: Go言語のプロジェクトをGo言語自身のツールでビルドできるようにすることで、外部のビルドツール(makeなど)への依存を減らし、Goエコシステム内での一貫性を高める。
  2. クロスプラットフォームビルドの簡素化: goコマンドは、Go言語のクロスコンパイル機能を活用し、異なるOSやアーキテクチャ向けのビルドを容易にします。Makefileベースのシステムでは、各プラットフォーム向けに個別のルールやスクリプトを記述する必要がありましたが、goコマンドに移行することで、この複雑さを大幅に軽減できます。
  3. 開発者体験の向上: goコマンドは、Go開発者にとって最も馴染み深いツールです。ビルドプロセスをこのコマンドに統合することで、開発者はより直感的で統一されたワークフローでGoプロジェクトを扱えるようになります。
  4. 将来的なMakefileの廃止: コミットメッセージにある「I will delete the makefiles in January.」という記述から、この変更がMakefileベースのビルドシステムを完全に廃止し、goコマンドを標準のビルドメカニズムとするための準備段階であったことがわかります。これにより、ビルドシステムのメンテナンスコスト削減や、コードベースの簡素化が期待されます。

このコミットは、Go言語がその初期段階から、より成熟した自己完結型の開発環境へと進化していく過程の一環として位置づけられます。

前提知識の解説

このコミットを理解するためには、以下の概念について基本的な知識が必要です。

  • Go言語 (Golang): Googleによって開発されたオープンソースのプログラミング言語。シンプルさ、効率性、並行処理のサポートが特徴です。
  • goコマンド: Go言語の公式ツールチェーンの中心となるコマンドラインツール。ソースコードのコンパイル、パッケージの管理(go get)、テストの実行(go test)、ドキュメントの生成(go doc)、そしてビルド(go build)など、Go開発における多岐にわたるタスクを処理します。
  • Makefile: makeユーティリティによって使用されるファイルで、プログラムのコンパイルやインストールなどのタスクを自動化するためのルールを記述します。依存関係に基づいてコマンドを実行する仕組みを提供します。C/C++などのプロジェクトで広く使われてきました。
  • ビルドシステム: ソースコードをコンパイルし、実行可能なプログラムやライブラリを生成するプロセスを管理する仕組み全体を指します。これには、コンパイラの呼び出し、依存関係の解決、リンク、最終的な成果物の配置などが含まれます。
  • クロスコンパイル: あるプラットフォーム(例: Linux x86-64)で、別のプラットフォーム(例: Windows ARM)向けの実行可能ファイルを生成すること。Go言語は、このクロスコンパイルを非常に強力にサポートしています。
  • GOROOT: Go言語のインストールディレクトリを指す環境変数。Goの標準ライブラリやツールチェーンがここに配置されます。
  • GOBIN: go installコマンドでビルドされた実行可能ファイルが配置されるディレクトリを指す環境変数。
  • 8g, 6g, 8c, 6c, 8a, 6a, 8l: これらはGo言語の初期のコンパイラ、アセンブラ、リンカのコマンド名です。
    • 8g: x86 (32-bit) 用 Go コンパイラ
    • 6g: x86-64 (64-bit) 用 Go コンパイラ
    • 8c: x86 (32-bit) 用 C コンパイラ (Goランタイムの一部がCで書かれていたため)
    • 6c: x86-64 (64-bit) 用 C コンパイラ
    • 8a: x86 (32-bit) 用 アセンブラ
    • 6a: x86-64 (64-bit) 用 アセンブラ
    • 8l: x86 (32-bit) 用 リンカ
    • 6l: x86-64 (64-bit) 用 リンカ これらは現在ではgo tool compile, go tool asm, go tool linkなどに統合されていますが、このコミットが作成された2011年当時は直接これらのコマンドが使われていました。
  • gopack: Goのアーカイブ(ライブラリ)ファイルを操作するためのツール。

技術的詳細

このコミットの核心は、Go言語のビルドプロセスをMakefileベースのシステムから、Go言語自身で書かれたgoコマンドベースのシステムへと移行することです。

具体的には、以下の変更が行われています。

  1. buildscript.shの導入:

    • この新しいスクリプトは、各ターゲットOS/アーキテクチャ(GOOS/GOARCH)に対応するbuildscript_${GOOS}_${GOARCH}.shファイルを自動生成します。
    • 生成されるスクリプトは、まずcmd/gogoコマンド自体)をビルドし、その後、そのgoコマンドを使ってGoツリーの残りの部分(標準ライブラリなど)をビルドするという二段階のプロセスを採用しています。これは、goコマンドがGo言語で書かれているため、goコマンド自身をビルドするために、まず基本的なGoコンパイラとリンカが必要となるというブートストラップ問題を解決するためのアプローチです。
    • go install -a -n cmd/goというコマンドが使われていますが、-nフラグは実際にはコマンドを実行せず、実行されるであろうコマンドを表示するだけです。これは、buildscript.shが実際にビルドを行うのではなく、ビルドを行うためのスクリプトを生成する役割であることを示しています。
  2. buildscript_${GOOS}_${GOARCH}.shファイルの大量追加:

    • src/buildscript_darwin_386.sh, src/buildscript_darwin_amd64.sh, src/buildscript_freebsd_386.shなど、様々なOSとアーキテクチャの組み合わせに対応するビルドスクリプトが新規追加されています。
    • これらのスクリプトは、Goの標準ライブラリの各パッケージ(errors, runtime, sync/atomic, io, unicode, bytes, math, strings, strconv, encoding/base64, reflect, sort, unicode/utf16, encoding/json, syscall, time, os, fmt, flag, bufio, encoding/gob, go/token, path/filepath, go/scanner, go/ast, text/tabwriter, go/printer, regexp/syntax, regexp, io/ioutil, net/url, text/template/parse, text/template, go/doc, go/parser, log, os/exec, path, go/build, cmd/go)を、それぞれのOS/アーキテクチャに対応するGoコンパイラ(8g, 6gなど)、Cコンパイラ(8c, 6cなど)、アセンブラ(8a, 6aなど)、リンカ(8l, 6lなど)を使ってビルドし、gopackでアーカイブ化し、最終的に$GOROOT/pkg/${GOOS}_${GOARCH}/以下に配置する手順を詳細に記述しています。
    • これらのスクリプトは、buildscript.shによって自動生成されるため、手動で編集すべきではない旨のコメント(# AUTO-GENERATED by buildscript.sh; DO NOT EDIT.)が含まれています。
  3. env.bashの変更:

    • USE_GO_TOOLという新しい環境変数が導入されています。これは、ビルドプロセスでgoコマンドを使用するか、従来のMakefileベースのシステムにフォールバックするかを制御するためのフラグです。これにより、移行期間中の互換性と、問題発生時のロールバックパスが提供されます。
  4. make.bashの変更:

    • make.bashは、Goのビルドプロセスを開始するための主要なスクリプトの一つですが、このコミットでは、USE_GO_TOOLが設定されている場合に、新しいbuildscript_${GOOS}_${GOARCH}.shスクリプトを呼び出すように変更されています。これにより、従来のMakefileベースのビルドから、goコマンドベースのビルドへの切り替えが行われます。
  5. run.bashの変更:

    • run.bashもビルド関連のスクリプトですが、同様にgoコマンドの使用を考慮した変更が加えられています。

この変更は、Goのビルドシステムが、Go言語自身のツールによって完全に管理されるようになるための重要な一歩であり、Goエコシステムの成熟を示すものです。これにより、GoのビルドプロセスはよりGoらしい、自己完結的で効率的なものへと進化しました。

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

このコミットは、主に以下のファイルに大きな変更を加えています。

  • src/buildscript.sh: 新規追加。各プラットフォーム向けのビルドスクリプトを生成する役割を担います。
  • src/buildscript_darwin_386.sh: 新規追加。macOS (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_darwin_amd64.sh: 新規追加。macOS (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_freebsd_386.sh: 新規追加。FreeBSD (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_freebsd_amd64.sh: 新規追加。FreeBSD (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_linux_386.sh: 新規追加。Linux (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_linux_amd64.sh: 新規追加。Linux (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_linux_arm.sh: 新規追加。Linux (ARM) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_netbsd_386.sh: 新規追加。NetBSD (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_netbsd_amd64.sh: 新規追加。NetBSD (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_openbsd_386.sh: 新規追加。OpenBSD (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_openbsd_amd64.sh: 新規追加。OpenBSD (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_plan9_386.sh: 新規追加。Plan 9 (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_windows_386.sh: 新規追加。Windows (32-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/buildscript_windows_amd64.sh: 新規追加。Windows (64-bit) 向けのGo標準ライブラリとgoコマンドのビルド手順を記述。
  • src/env.bash: USE_GO_TOOL環境変数の追加と関連ロジックの変更。
  • src/make.bash: goコマンドベースのビルドフローを呼び出すように変更。
  • src/pkg/runtime/autogen.sh: わずかな変更。
  • src/run.bash: goコマンドの使用を考慮した変更。

これらの変更は、Goのビルドシステム全体をgoコマンド中心に再構築する大規模なものです。

コアとなるコードの解説

このコミットにおけるコアとなるコードの変更は、主にsrc/buildscript.shと、それによって生成される各プラットフォーム固有のbuildscript_*.shファイル、そしてビルドの入り口となるsrc/make.bashに見られます。

src/buildscript.sh (新規追加)

#!/bin/sh
# Copyright 2011 The Go Authors.  All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

. ./buildinfo.sh

for sys in $GOOSARCHES
do
	export GOOS=$(echo $sys | sed 's/_.*//')
	export GOARCH=$(echo $sys | sed 's/.*_//')
	targ=buildscript_${GOOS}_$GOARCH.sh
	rm -f $targ

	(echo '#!/bin/bash
# AUTO-GENERATED by buildscript.sh; DO NOT EDIT.
# This script builds the go command (written in Go),
# and then the go command can build the rest of the tree.

export GOOS='$GOOS'
export GOARCH='$GOARCH'
export WORK=$(mktemp -d -t go-build)
trap "rm -rf $WORK" EXIT SIGINT SIGTERM
set -e

'
	go install -a -n cmd/go
	)>$targ
	chmod +x $targ
done
  • このスクリプトは、GoがサポートするすべてのOSとアーキテクチャの組み合わせ($GOOSARCHES変数で定義されている)をループ処理します。
  • 各組み合わせに対して、GOOSGOARCH環境変数を設定し、buildscript_${GOOS}_${GOARCH}.shという名前の新しいシェルスクリプトファイルを生成します。
  • 生成されるスクリプトの冒頭には、#!/bin/bash、自動生成されたものであることの警告、そしてGOOS, GOARCH, WORK(一時ディレクトリ)の設定、エラーハンドリング(trapset -e)が含まれます。
  • 最も重要なのは、go install -a -n cmd/goの部分です。これは、goコマンド自体をビルドするためのコマンドを生成されるスクリプトに含めることを意図しています。-nフラグがあるため、このbuildscript.sh自体がgo installを実行するわけではなく、生成されるスクリプトにそのコマンドが書き込まれます。

src/buildscript_darwin_386.sh (生成されるスクリプトの一例)

#!/bin/bash
# AUTO-GENERATED by buildscript.sh; DO NOT EDIT.
# This script builds the go command (written in Go),
# and then the go command can build the rest of the tree.

export GOOS=darwin
export GOARCH=386
export WORK=$(mktemp -d -t go-build)
trap "rm -rf $WORK" EXIT SIGINT SIGTERM
set -e

#
# errors
#

mkdir -p $WORK/errors/_obj/
 cd $GOROOT/src/pkg/errors
8g -o $WORK/errors/_obj/_go_.6 -p errors -I $WORK ./errors.go
gopack grc $WORK/errors.a $WORK/errors/_obj/_go_.6
mkdir -p $GOROOT/pkg/darwin_386/
cp $WORK/errors.a $GOROOT/pkg/darwin_386/errors.a

# ... (他のパッケージのビルドコマンドが続く) ...

#
# cmd/go
#

mkdir -p $WORK/cmd/go/_obj/
 cd $GOROOT/src/cmd/go
8g -o $WORK/cmd/go/_obj/_go_.6 -p cmd/go -I $WORK ./build.go ./fix.go ./fmt.go ./get.go ./help.go ./list.go ./main.go ./pkg.go ./run.go ./test.go ./testflag.go ./version.go ./vet.go
gopack grc $WORK/cmd/go.a $WORK/cmd/go/_obj/_go_.6
8l -o $WORK/cmd/go/_obj/a.out -L $WORK $WORK/cmd/go.a
mkdir -p $GOBIN/
cp $WORK/cmd/go/_obj/a.out $GOBIN/go
  • これらのスクリプトは、Goの標準ライブラリの各パッケージを、対応するGoコンパイラ(例: 8g for 386, 6g for amd64)、アセンブラ、リンカを使って個別にコンパイルし、アーカイブ(.aファイル)を作成し、適切なpkgディレクトリにコピーする一連のコマンドを含んでいます。
  • 最終的に、cmd/goパッケージ(goコマンドのソースコード)も同様にビルドされ、実行可能ファイルが$GOBIN/goに配置されます。
  • この詳細な手順は、従来のMakefileが担っていた役割を、シェルスクリプトに置き換えたものです。

src/make.bash (変更点)

 # ... (既存のコード) ...

 if [ "$USE_GO_TOOL" = "true" ]; then
 	echo "Building Go with go command..."
 	./buildscript_${GOOS}_${GOARCH}.sh
 else
 	echo "Building Go with makefiles..."
 	# ... (従来のMakefileベースのビルドロジック) ...
 fi

 # ... (既存のコード) ...
  • src/make.bashは、Goのビルドを開始する際に、USE_GO_TOOL環境変数の値を確認します。
  • もしUSE_GO_TOOLtrueに設定されていれば、新しく生成されたbuildscript_${GOOS}_${GOARCH}.shスクリプトを実行し、goコマンドベースのビルドフローを開始します。
  • そうでなければ、従来のMakefileベースのビルドロジックにフォールバックします。

この一連の変更により、Goのビルドシステムは、Go言語自身のツールによってブートストラップされ、管理されるという、より自己完結的でモダンなアプローチへと移行しました。これは、Go言語の設計哲学である「シンプルさ」と「効率性」をビルドプロセスにも適用した結果と言えるでしょう。

関連リンク

  • Go言語公式ウェブサイト: https://go.dev/
  • Go言語のビルドシステムに関する議論(当時のメーリングリストなど): このコミットは2011年のものであり、当時のGoコミュニティのメーリングリスト(golang-nutsやgolang-dev)で詳細な議論が行われていた可能性があります。具体的なリンクはコミットメッセージのhttps://golang.org/cl/5502047から辿れるGoのコードレビューシステム(Gerrit)のページで確認できます。

参考にした情報源リンク

  • Go言語のソースコード(特にsrcディレクトリ以下のビルド関連スクリプト)
  • Go言語の歴史とビルドプロセスの進化に関する一般的な知識
  • Go言語の初期のツールチェーン(8g, 6gなど)に関する情報
  • Gitのコミットログと差分表示
  • https://golang.org/cl/5502047 (GoのコードレビューシステムGerritの該当コミットページ)
  • Go言語のgoコマンドに関する公式ドキュメント(現在のもの)
  • Makefilemakeユーティリティに関する一般的な知識
  • シェルスクリプトの基本的な構文と機能