[インデックス 11572] ファイルの概要
このコミットは、Go言語のビルドシステムに大きな変更を導入するもので、新しいGoディストリビューションツールである cmd/dist
を追加します。このツールは、既存のMakefileベースのビルドプロセスを置き換え、GoのビルドにおけるBashやその他のUnixツール、特にWindows環境でのCygwinへの依存を排除することを目的としています。
コミット
commit 3dd1e5be54417819c3c5e3024c9efbc8f8344195
Author: Russ Cox <rsc@golang.org>
Date: Thu Feb 2 19:41:39 2012 -0500
cmd/dist: new command
dist is short for distribution. This is the new Go distribution tool.
The plan is to replace the Makefiles with what amounts to
'go tool dist bootstrap', although it cannot be invoked like
that since it is in charge of getting us to the point where we
can build the go command.
It will also add additional commands to replace bash scripts
like test/run (go tool dist testrun), eventually eliminating our
dependence on not just bash but all the Unix tools and all
of cygwin.
This is strong enough to build (cc *.c) and run (a.out bootstrap)
to build not just the C libraries and tools but also the basic
Go packages up to the bootstrap form of the go command
(go_bootstrap). I've run it successfully on both Linux and Windows.
This means that once we've switched to this tool in the build,
we can delete the buildscripts.
This tool is not nearly as nice as the go tool. There are many
special cases that turn into simple if statements or tables in
the code. Please forgive that. C does not enjoy the benefits
that we designed into Go.
I was planning to wait to do this until after Go 1, but the
Windows builders are both broken due to a bug in either
make or bash or both involving the parsing of quoted command
arguments. Make thinks it is invoking
quietgcc -fno-common -I"c:/go/include" -ggdb -O2 -c foo.c
but bash (quietgcc is a bash script) thinks it is being invoked as
quietgcc -fno-common '-Ic:/go/include -ggdb' -O2 -c foo.c
which obviously does not have the desired effect. Rather than fight
these clumsy ports, I accelerated the schedule for the new tool.
We should be completely off cygwin (using just the mingw gcc port,
which is much more standalone) before Go 1.
It is big for a single CL, and for that I apologize. I can cut it into
separate CLs along file boundaries if people would prefer that.
R=golang-dev, adg, gri, bradfitz, alex.brainman, dsymonds, iant, ality, hcwfrichter
CC=golang-dev
https://golang.org/cl/5620045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3dd1e5be54417819c3c5e3024c9efbc8f8344195
元コミット内容
このコミットは、Go言語の新しいディストリビューションツールである cmd/dist
を導入します。このツールは、Goのビルドプロセスを管理し、既存のMakefileベースのシステムを置き換えることを目的としています。将来的には、test/run
のようなBashスクリプトも go tool dist testrun
のようなコマンドに置き換え、GoのビルドにおけるBash、Unixツール、およびCygwinへの依存を完全に排除することを目指しています。
cmd/dist
は、C言語で書かれたライブラリやツール、そしてGoの基本的なパッケージをブートストラップ形式の go
コマンド(go_bootstrap
)までビルドする能力を持っています。このツールは既にLinuxとWindowsの両方で動作することが確認されており、導入後は既存のビルドスクリプトを削除できるようになります。
開発者は、このツールが go tool
ほど洗練されていないことを認めつつも、C言語の制約の中で多くの特殊ケースをシンプルに処理していると説明しています。
この変更は、当初Go 1リリース後に予定されていましたが、Windows環境での make
または bash
の引用符付きコマンド引数のパースに関するバグにより、Windowsビルドが機能しなくなったため、前倒しで導入されました。この問題は、quietgcc
のようなBashスクリプトが make
から誤った形式の引数を受け取ることに起因していました。この dist
ツールの導入により、Go 1リリース前にCygwinへの依存を完全に解消し、よりスタンドアロンなMinGW GCCポートのみを使用できるようになることが期待されています。
このコミットは単一の変更セットとしては大規模ですが、その必要性が強調されています。
変更の背景
Go言語の初期のビルドシステムは、Unix系の環境で広く使われている make
とBashスクリプトに大きく依存していました。これは、GoがUnixライクなシステムで開発されたため自然な選択でしたが、Windowsのような異なるOS環境でのビルドにおいて問題を引き起こしていました。
特に、Windows環境では make
やBashのポート(Cygwinなど)が、引用符付きのコマンド引数のパースに関して予期せぬバグを抱えていました。コミットメッセージに具体例として挙げられているように、make
が quietgcc -fno-common -I"c:/go/include" -ggdb -O2 -c foo.c
のようにコマンドを呼び出そうとしても、Bashスクリプトはこれを quietgcc -fno-common '-Ic:/go/include -ggdb' -O2 -c foo.c
のように誤って解釈し、ビルドが失敗するという問題が発生していました。
このようなクロスプラットフォームでのビルドの不安定性は、Go言語の普及と開発効率にとって大きな障害となっていました。Go 1のリリースを控える中で、この問題を根本的に解決し、より堅牢でポータブルなビルドシステムを確立することが急務でした。
このため、当初Go 1リリース後に計画されていた、Cygwinやその他のUnixツールへの依存を排除する新しいディストリビューションツールの開発が前倒しで実施されることになりました。これが cmd/dist
の導入の直接的な背景です。
前提知識の解説
このコミットを理解するためには、以下の概念について基本的な知識があると役立ちます。
-
Go言語のブートストラップ (Bootstrapping):
- Go言語のコンパイラやツールチェイン自体もGo言語で書かれています。しかし、Go言語のコンパイラをビルドするためには、まず動作するGoコンパイラが必要です。この循環的な依存関係を解決するために、「ブートストラップ」というプロセスが用いられます。
- 初期のGoコンパイラはC言語で書かれたり、以前のバージョンのGoコンパイラ(または別の言語のコンパイラ)を使ってビルドされたりします。このコミットで導入される
cmd/dist
は、このブートストラッププロセスを管理し、C言語で書かれたツールやライブラリ、そしてGo言語で書かれた初期のgo
コマンド(go_bootstrap
)をビルドする役割を担います。 - ブートストラップが完了すると、その
go_bootstrap
コマンドを使って、より完全なGoツールチェインをビルドできるようになります。
-
Makefile:
make
は、プログラムのソースコードから実行可能ファイルやライブラリをビルドするプロセスを自動化するためのツールです。Makefile
はmake
が実行するタスク(ターゲット)とその依存関係、および実行するコマンドを記述したファイルです。- Go言語の初期のビルドシステムは、この
Makefile
を広範に利用していました。しかし、make
はUnix系の環境で非常に強力ですが、Windows環境での互換性や挙動の差異が問題となることがあります。
-
Bash (Bourne Again SHell):
- Unix系OSで広く使われているコマンドラインシェルであり、スクリプト言語でもあります。Goのビルドプロセスでは、複雑なタスクを自動化するためにBashスクリプトが使用されていました。
- Windows環境では、Cygwinのようなツールを通じてBashが利用できますが、これがWindowsネイティブのコマンドプロンプトやPowerShellとは異なる挙動を示すことがあり、互換性の問題を引き起こすことがあります。
-
Cygwin:
- Windows上でUnixライクな環境を提供するソフトウェアスイートです。これにはBashシェルや、
make
、gcc
などの多くのUnixツールが含まれています。 - GoのWindowsビルドでは、これらのUnixツールを利用するためにCygwinに依存していましたが、これがWindows固有のビルド問題(特にパスの扱いや引用符の解釈)の原因となることがありました。
- Windows上でUnixライクな環境を提供するソフトウェアスイートです。これにはBashシェルや、
-
MinGW (Minimalist GNU for Windows):
- Windowsネイティブアプリケーションを開発するためのGNUツールチェイン(GCCなど)のポートです。Cygwinとは異なり、Unixエミュレーションレイヤーを必要とせず、よりスタンドアロンな形でWindows上で動作する実行ファイルを生成できます。
- このコミットの目的の一つは、Cygwinへの依存を排除し、MinGWのようなよりネイティブに近いツールチェインに移行することです。
-
C言語のメモリ管理 (Buf, Vec):
- この
cmd/dist
ツールはC言語で書かれています。C言語では、メモリ管理(確保と解放)をプログラマが手動で行う必要があります。 - コミットで導入される
Buf
(バイトバッファ) とVec
(文字列ベクトル) は、Go言語の[]byte
や[]string
のような動的なデータ構造をC言語で安全かつ効率的に扱うためのカスタム実装です。これらは、メモリリークを防ぎ、コードの可読性を向上させるための工夫です。
- この
これらの知識があると、cmd/dist
がなぜ必要とされ、どのような問題を解決しようとしているのか、そしてどのように実装されているのかをより深く理解できます。
技術的詳細
cmd/dist
は、Go言語のビルドプロセスを制御するための新しいC言語製ツールです。その設計と実装には、ポータビリティ、依存関係の削減、および堅牢性の向上が強く意識されています。
1. C言語での実装とポータビリティ層
cmd/dist
は、Go言語のツールチェインをブートストラップするために、Go言語自体に依存しないC言語で書かれています。- ポータビリティを最大化するため、C標準ライブラリを含むCライブラリとのすべての相互作用は、システム固有のファイル(
plan9.c
,unix.c
,windows.c
)に限定されています。これにより、異なるOSへの移植が容易になります。 - ポータビリティ層の関数は、既存の関数名との衝突や混同を避けるために
x
プレフィックス(例:xprintf
はポータブルなprintf
)を使用しています。
2. Buf
と Vec
データ構造
- C言語での文字列や動的配列の扱いの複雑さを軽減するため、
Buf
(バイトバッファ) とVec
(文字列ベクトル) というカスタムデータ構造が導入されています。 Buf
: Goの[]byte
に相当し、動的にサイズが変更可能なバイトバッファです。binit
(初期化),bfree
(解放),bgrow
(容量拡張),bwrite
(書き込み),bstr
(NUL終端文字列取得) などの操作が提供されます。Vec
: Goの[]string
に相当し、動的にサイズが変更可能な文字列の配列です。vinit
(初期化),vfree
(解放),vgrow
(容量拡張),vadd
(文字列追加),vuniq
(ソートと重複排除) などの操作が提供されます。- これらの構造体は、自身が指すデータの所有権を持ち、
binit
/vinit
で初期化し、bfree
/vfree
でメモリを解放するという慣用句(idiom)を強制することで、メモリリークのリスクを低減し、レキシカルスコープでのメモリ管理を可能にしています。
3. ビルドプロセスの管理 (build.c
)
build.c
は、Goのビルドプロセスの中核を担います。- 環境変数の初期化:
GOROOT
,GOBIN
,GOOS
,GOARCH
などの重要な環境変数を初期化し、検証します。 - ディレクトリ構造のセットアップ:
GOROOT/bin
,GOROOT/bin/go-tool
,GOROOT/pkg
などの必要なディレクトリを作成し、古いツールバイナリを削除します。 - 依存関係の解決:
deptab
というテーブルを使用して、特定のターゲット(例:lib9
,cmd/cc
)に対するカスタム依存関係(インクルードファイル、除外ファイル、ディレクトリ全体のスキャンなど)を定義します。 - ファイルフィルタリング (
shouldbuild
):go/build
パッケージのコンテキストタグと同様のルールを適用し、ファイル名やファイル内容の// +build
行に基づいて、どのソースファイルをビルドに含めるべきかを決定します。これにより、特定のOSやアーキテクチャに特化したファイルが適切に選択されます。 - コンパイルとリンク: C言語のソースファイル (
.c
,.s
) はgcc
を使用してコンパイルされ、Go言語のソースファイル (.go
) はブートストラップコンパイラ (%sg
など) を使用してコンパイルされます。最終的なバイナリやライブラリは、ar
(Cライブラリ),pack
(Goパッケージ),ld
(Cコマンド), またはブートストラップリンカ (%sl
) を使用してリンクされます。 - ビルド順序 (
buildorder
):go bootstrap
コマンドのビルド順序を定義する静的な配列buildorder
が存在し、これに従ってライブラリ、パッケージ、コマンドが順次ビルドされます。
4. 特殊なファイル生成 (buildgc.c
)
buildgc.c
は、cmd/gc
(Goコンパイラ) のビルドに必要な特殊なファイルを生成するヘルパー関数を提供します。gcopnames
:go.h
からGoのオペコード(OXXX
enum)を抽出し、それらの名前を文字列としてマッピングするopnames.h
を生成します。mkenam
:[568].out.h
(アセンブラの出力ヘッダ) を読み込み、アセンブラの命令名を文字列としてマッピングするenam.c
を生成します。
5. コマンドラインインターフェース (main.c
)
main.c
はcmd/dist
のエントリポイントであり、コマンドライン引数をパースして適切なサブコマンド(bootstrap
,env
,install
)を呼び出します。
6. OS固有の実装 (unix.c
, windows.c
)
- これらのファイルは、ファイルシステム操作(
mkdir
,readfile
,writefile
,removeall
)、環境変数アクセス(getenv
,setenv
)、プロセス実行(run
,runv
)、パス操作(isabs
,isdir
,isfile
,mtime
)など、OSに依存する低レベルの機能を実装しています。 unix.c
はUnix系システム(Linux, macOSなど)向け、windows.c
はWindows向けの実装を提供します。これにより、コアロジックはOS非依存に保たれ、ポータビリティが実現されます。
これらの技術的詳細は、cmd/dist
がいかにしてGoのビルドプロセスをより制御可能で、クロスプラットフォーム対応にし、外部ツールへの依存を減らすように設計されているかを示しています。
コアとなるコードの変更箇所
このコミットでは、src/cmd/dist
ディレクトリが新規に作成され、以下の8つのファイルが追加されています。
src/cmd/dist/README
src/cmd/dist/a.h
src/cmd/dist/buf.c
src/cmd/dist/build.c
src/cmd/dist/buildgc.c
src/cmd/dist/main.c
src/cmd/dist/unix.c
src/cmd/dist/windows.c
これらのファイルはすべて新規追加であり、既存のコードの変更は含まれていません。これは、cmd/dist
が既存のビルドシステムとは独立した新しいツールとして導入されたことを意味します。
コアとなるコードの解説
追加された各ファイルの役割は以下の通りです。
-
src/cmd/dist/README
:dist
ツールの目的と基本的な設計原則を説明するドキュメントです。- Goディストリビューションのブートストラップツールであり、Cプログラム(Goコンパイラなど)と初期の
go
ツールをビルドする役割を担うと説明されています。 - C言語で書かれており、ポータビリティのためにシステム固有のコードが分離されていること、
Buf
とVec
というカスタムデータ構造がメモリ管理を容易にすることなどが記述されています。
-
src/cmd/dist/a.h
:cmd/dist
全体で共有される共通のヘッダファイルです。bool
型の定義、nil
(NULL) マクロ、nelem
(配列要素数) マクロなどが含まれます。Buf
(バイトバッファ) とVec
(文字列ベクトル) の構造体定義と、それらに関連する関数のプロトタイプ宣言が含まれます。build.c
,buildgc.c
,main.c
, およびOS固有のファイル (unix.c
,windows.c
) で定義される主要な関数のプロトタイプ宣言も含まれており、ツール全体のインターフェースを定義しています。
-
src/cmd/dist/buf.c
:Buf
(バイトバッファ) とVec
(文字列ベクトル) の実装を提供します。Buf
の操作(binit
,breset
,bfree
,bgrow
,bwrite
,bwritestr
,bstr
,btake
,bwriteb
,bequal
)と、Vec
の操作(vinit
,vreset
,vfree
,vgrow
,vcopy
,vadd
,vaddn
,vuniq
,splitlines
,splitfields
)が含まれます。- これらの関数は、動的な文字列やバイト列の効率的かつ安全な操作をC言語で実現するための基盤となります。
-
src/cmd/dist/build.c
:cmd/dist
のビルドロジックの大部分を実装しています。- 環境変数の初期化、ビルドディレクトリのセットアップ、古いツールのクリーンアップを行います。
deptab
を使用して、各ターゲット(ライブラリ、パッケージ、コマンド)の依存関係を定義し、ソースファイルのフィルタリング (shouldbuild
) を行います。- C言語のソースファイルやGo言語のソースファイルをコンパイルし、最終的なライブラリや実行ファイルをリンクするプロセスを管理します。
cmdbootstrap
(ブートストラップビルドの実行),cmdenv
(環境変数の表示),cmdinstall
(指定されたパッケージのインストール) といったサブコマンドの具体的な実装が含まれます。buildorder
という配列で、ブートストラップビルドにおける各コンポーネントのビルド順序が定義されています。
-
src/cmd/dist/buildgc.c
:- Goコンパイラ (
cmd/gc
) のビルドに必要な特殊なファイルを生成するヘルパー関数を実装しています。 gcopnames
関数は、Goのオペコード名を定義するopnames.h
を生成します。mkenam
関数は、アセンブラの命令名を定義するenam.c
を生成します。
- Goコンパイラ (
-
src/cmd/dist/main.c
:cmd/dist
のメインエントリポイントです。- コマンドライン引数を解析し、
cmdtab
に定義されたサブコマンド(bootstrap
,env
,install
)に対応する関数を呼び出します。 - 引数が不足している場合や不明なコマンドが指定された場合には、使用方法のメッセージを表示して終了します。
-
src/cmd/dist/unix.c
:- Unix系オペレーティングシステム(Linux, macOSなど)向けのOS固有の機能を実装しています。
- ファイルシステム操作(
open
,read
,write
,stat
,mkdir
,unlink
,rmdir
,opendir
,readdir
)、プロセス実行(fork
,execvp
,waitpid
,pipe
)、環境変数アクセス(getenv
,setenv
)、メモリ管理(malloc
,realloc
,free
,strdup
)などのシステムコールをラップした関数が含まれます。 - エラー処理 (
fatal
) や一時ディレクトリの作成 (xworkdir
) なども含まれます。
-
src/cmd/dist/windows.c
:- Windowsオペレーティングシステム向けのOS固有の機能を実装しています。
unix.c
と同様の機能を提供しますが、Windows API (CreateFile
,ReadFile
,WriteFile
,CreateDirectory
,DeleteFile
,RemoveDirectory
,FindFirstFile
,FindNextFile
,GetEnvironmentVariable
,SetEnvironmentVariable
,_spawnvpe
,_pipe
,_getdcwd
,_chdir
,_stat
,_mktemp
) を使用して実装されています。- これにより、
cmd/dist
がWindows環境でもネイティブに動作し、Cygwinのようなエミュレーションレイヤーへの依存を排除できるようになります。
これらのファイルが連携することで、cmd/dist
はGo言語のブートストラップビルドをクロスプラットフォームで実行できる、自己完結型のツールとして機能します。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Go言語のブートストラップに関する議論(一般的な情報源):
- Goのビルドプロセスに関する公式ドキュメントやブログ記事(当時のものを見つけるのは難しいかもしれませんが、現在のGoのビルドシステムに関する情報が参考になる可能性があります)。
参考にした情報源リンク
- コミットメッセージ:
https://golang.org/cl/5620045
(これはコミットメッセージ内に記載されているGo Code Reviewのリンクであり、コミットの元情報です。) - Go言語のソースコード:
https://github.com/golang/go
(コミットされたコード自体が主要な情報源です。) - Cygwin 公式サイト: https://www.cygwin.com/
- MinGW 公式サイト: https://www.mingw-w64.org/
make
コマンドに関する一般的な情報源 (例: GNU Make マニュアル)- Bashに関する一般的な情報源 (例: GNU Bash リファレンスマニュアル)
- C言語の標準ライブラリ関数に関する情報源 (例: C言語リファレンス)
- Go言語のブートストラップに関する一般的な概念を説明する記事やドキュメント (特定のURLは挙げませんが、Goのビルドシステムに関する一般的な解説が参考になります。)