[インデックス 11451] ファイルの概要
このコミットは、Go言語プロジェクト内のC言語で書かれたツール(cov, nm, prof, pprof)のビルドおよびインストールプロセスを再構築するものです。具体的には、新しいMakefileの導入、ツールの名称変更、インストールパスの変更、そしてシステムワイドなインストールスクリプトの更新が含まれます。
コミット
commit 4a9138751abd2dbd2c2dbe86697fdd08718535c7
Author: Rob Pike <r@golang.org>
Date: Sun Jan 29 10:14:36 2012 -0800
cmd/go: c tools not used during compilation
cov, nm, pprof, prof
R=rsc, r, rsc
CC=golang-dev
https://golang.org/cl/5576067
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4a9138751abd2dbd2c2dbe86697fdd08718535c7
元コミット内容
このコミットの元のメッセージは以下の通りです。
cmd/go: c tools not used during compilation
cov, nm, pprof, prof
これは、cov, nm, pprof, prof といったC言語で書かれたツールが、Goのコンパイルプロセス中に直接使用されないことを示唆しています。この変更は、これらのツールのビルドと配布方法を整理し、Goのビルドシステム全体から独立させることを目的としていると考えられます。
変更の背景
このコミットの背景には、Goプロジェクトにおけるツールの管理と配布の標準化があります。以前は、C言語で書かれたツール(cov, nm, prof など)は、Make.ccmd という汎用的なMakefileを使用してビルドされ、6cov、6nm、6prof のようなプレフィックス付きの名前でインストールされていました。また、インストール先も $GOBIN ディレクトリ直下でした。
このコミットは、以下の問題点や改善点を解決しようとしています。
- ビルドプロセスの明確化: C言語で書かれたツールに特化した新しいMakefile (
Make.ctool) を導入することで、ビルドプロセスをより明確にし、Go言語で書かれたツールとは異なるビルド要件を適切に管理します。 - ツールの命名規則の統一:
6covのようなプレフィックスは、Goのバージョンやアーキテクチャを示すものでしたが、Goツールチェインが成熟するにつれて、より汎用的な名前 (cov,nm,prof) が望ましくなりました。これにより、ツールの利用者が混乱することなく、直感的にツールを識別できるようになります。 - インストールパスの整理: Goのツールは通常
$GOROOT/binまたは$GOBINにインストールされますが、このコミットではC言語ツールを$GOROOT/bin/go-tool/という専用のサブディレクトリに配置することで、Goツールチェインの他の部分との分離を明確にし、管理を容易にします。これは、これらのツールがGoコンパイラやリンカとは異なる補助的な役割を持つことを示唆しています。 - システムワイドなインストールの改善:
sudo.bashスクリプトの更新は、これらのツールをシステム全体にインストールする際のパスと名前の整合性を確保し、古いバイナリの残存を防ぐためのものです。
これらの変更は、Goプロジェクトが成長し、ツールチェインが複雑化する中で、よりクリーンで保守しやすい構造を目指す一環として行われました。
前提知識の解説
このコミットを理解するためには、以下の概念について知っておく必要があります。
- Go言語のビルドシステム: Goプロジェクトは、独自のビルドシステムを使用しており、Makefileがその一部を構成しています。
Make.inc、Make.ccmd、そしてこのコミットで導入されるMake.ctoolなど、様々なMakefileがGoのソースコードやツールをビルドするために利用されます。 - Makefile:
makeコマンドによって実行されるビルド自動化ツールです。依存関係に基づいてファイルをコンパイル、リンク、インストールする手順を定義します。 $GOROOTと$GOBIN:$GOROOT: Goのインストールディレクトリのルートパスを示す環境変数です。Goの標準ライブラリ、ツール、ドキュメントなどが含まれます。$GOBIN: Goの実行可能バイナリがインストールされるディレクトリを示す環境変数です。通常は$GOROOT/binまたはユーザーの$HOME/go/binに設定されます。
cov(Go Coverage Tool): Goのコードカバレッジを測定するためのツールです。テストがコードのどの部分を実行したかを分析し、カバレッジレポートを生成します。nm(Go Symbol Table Tool): Unix系のnmコマンドに似たツールで、Goのオブジェクトファイルや実行可能ファイル内のシンボル(関数名、変数名など)をリスト表示します。デバッグやバイナリの解析に役立ちます。prof/pprof(Go Profiling Tools): Goアプリケーションのパフォーマンスプロファイリングを行うためのツール群です。CPU使用率、メモリ割り当て、ゴルーチンブロックなどを分析し、パフォーマンスのボトルネックを特定するのに役立ちます。pprofは、プロファイリングデータを視覚化するためのツールとして広く知られています。HOST_CC,HOST_LD,HOST_O: Goのビルドシステム内で使用される変数で、ホストシステム(Goのビルドが実行される環境)のCコンパイラ、リンカ、オブジェクトファイルの拡張子をそれぞれ指します。これにより、クロスコンパイル環境でも適切にCコードをビルドできます。bison: Yacc互換のパーサジェネレータです。文法定義ファイルからC言語のソースコードを生成し、構文解析器を作成します。y.tab.hやy.tab.cといったファイルが生成されるのは、bisonが使用されていることを示します。gdb: GNU Debuggerの略で、プログラムの実行を制御し、内部状態を検査するためのデバッグツールです。
技術的詳細
このコミットの技術的詳細は、主にGoのビルドシステムにおけるC言語ツールの取り扱いに関するものです。
-
src/Make.ctoolの導入:- この新しいMakefileは、C言語で書かれたGoツールをビルドするための標準的なルールを定義しています。
TARG変数に.exe拡張子を付加することで、Windows環境での実行可能ファイル名を自動的に処理します。$(HOST_LD)を使用して、$(OFILES)(オブジェクトファイル) と$(LIB)(ライブラリ) をリンクし、最終的な実行可能ファイル$(TARG)を生成します。-L"$(GOROOT)"/libは、Goのライブラリディレクトリをリンカの検索パスに追加します。-lmach,-lbio,-l9,-lmは、特定のシステムライブラリへのリンクを示唆しています。$(OFILES)が$(HFILES)に依存することを定義しており、ヘッダーファイルの変更がオブジェクトファイルの再コンパイルをトリガーするようにしています。cleanおよびnukeターゲットは、ビルド生成物やインストールされたバイナリを削除するための標準的なクリーンアップメカニズムを提供します。特にnukeは、インストールされたツールを$GOROOT/bin/go-tool/から削除します。installターゲットは、ビルドされたツールを$GOROOT/bin/go-tool/ディレクトリにコピーします。mkdir -pを使用して、必要に応じてディレクトリを作成します。y.tab.hおよびy.tab.cのルールは、bisonを使用してパーサ関連のファイルを生成するプロセスを定義しています。これは、covやprofのようなツールが構文解析を必要とする場合に利用されます。%.$(HOST_O): %.cルールは、Cソースファイルをオブジェクトファイルにコンパイルする方法を定義しています。$(PWD)/$*.cを使用することで、gdbのようなデバッガがスタックトレースで完全なパスを表示できるようにしています。
-
ツールの名称変更とMakefileの更新:
src/cmd/cov/Makefile,src/cmd/nm/Makefile,src/cmd/prof/Makefileの各ファイルで、TARG変数の値が6covからcov、6nmからnm、6profからprofへと変更されています。これにより、生成されるバイナリの名前が簡潔になります。- これらのMakefileは、
include ../../Make.ccmdからinclude ../../Make.ctoolへと変更され、新しいCツール専用のビルドシステムを利用するようになりました。 NOINSTALL=1の削除は、これらのツールがデフォルトでインストールされるようになったことを意味します。- インストールパスが
$(GOBIN)/$(TARG)から$(GOBIN)/go-tool/$(TARG)へと変更され、専用のサブディレクトリに配置されるようになりました。 src/cmd/prof/gopprofがsrc/cmd/prof/pprofにリネームされました。これは、pprofツール自体がGo言語で書かれたスクリプトまたはバイナリであり、その名前を簡潔にするための変更です。
-
src/cmd/go/tool.goの変更:sort.StringSlice(names).Sort()がsort.Strings(names)に変更されています。これは、Go 1.8で導入されたsort.Strings関数(sort.StringSliceのヘルパー関数)を使用する、より現代的で簡潔なGoのイディオムへの更新です。機能的な変更はありませんが、コードの可読性と保守性が向上します。
-
src/sudo.bashの変更:- このスクリプトは、
covとprofツールをシステムワイドにインストールするためのものです。 - 古い
6$i形式のバイナリを削除し、新しい$i形式のバイナリをインストールするように変更されています。 - インストールパスは
/usr/local/bin/6$iから/usr/local/bin/go$iへと変更されています。これは、Goツールであることを明示し、他のシステムツールとの名前の衝突を避けるための命名規則の変更です。 chgrp procmodとchmod g+sは、特定のグループ (procmod) に所有権を与え、setgidビットを設定することで、これらのツールが特定の権限で実行されるようにするためのものです。これは、プロファイリングやカバレッジ測定のような操作が、システムリソースへのアクセスを必要とする場合があるためです。
- このスクリプトは、
これらの変更は、Goのビルドシステムが進化し、よりモジュール化され、特定の種類のツール(C言語で書かれたもの)の管理が改善されたことを示しています。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下のファイルに集中しています。
-
src/Make.ctool(新規ファイル):- C言語で書かれたGoツールをビルドするための新しいMakefileの定義。
- Windows環境での
.exe拡張子の自動付与。 HOST_LDとHOST_CCを使用したコンパイル・リンク規則。$GOROOT/bin/go-toolへのインストールルール。bisonを使用したパーサファイルの生成ルール。
-
src/cmd/cov/Makefile:TARG=6covからTARG=covへの変更。include ../../Make.ccmdからinclude ../../Make.ctoolへの変更。- インストールパスを
$(GOBIN)/$(TARG)から$(GOBIN)/go-tool/$(TARG)へ変更。
-
src/cmd/nm/Makefile:TARG=6nmからTARG=nmへの変更。include ../../Make.ccmdからinclude ../../Make.ctoolへの変更。
-
src/cmd/prof/Makefile:TARG=6profからTARG=profへの変更。include ../../Make.ccmdからinclude ../../Make.ctoolへの変更。- インストールパスを
$(GOBIN)/$(TARG)から$(GOBIN)/go-tool/$(TARG)へ変更。 install-pprofターゲットのソースとインストールパスの変更。
-
src/cmd/prof/{gopprof => pprof}(ファイル名変更):gopprofスクリプトがpprofにリネームされました。
-
src/sudo.bash:covとprofのシステムワイドインストールロジックの更新。- 古い
6$iバイナリの削除と、新しいgo$iバイナリのインストール。 - インストールパスが
/usr/local/bin/6$iから/usr/local/bin/go$iへ変更。
-
src/cmd/go/tool.go:sort.StringSlice(names).Sort()からsort.Strings(names)への変更。
コアとなるコードの解説
src/Make.ctool (抜粋)
# Tools always go into $GOROOT/bin/go-tool
ifeq (windows,$(findstring windows, $(shell uname | tr A-Z a-z | sed 's/mingw/windows/')))\n+TARG:=$(TARG).exe
endif
$(TARG): $(OFILES) $(LIB)
$(HOST_LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lmach -lbio -l9 -lm $(HOST_LDFLAGS)
# ... (clean, nuke, y.tab.h/c rules) ...
ifneq ($(NOINSTALL),1)
install: $(QUOTED_GOROOT)/bin/go-tool/$(TARG)
endif
$(QUOTED_GOROOT)/bin/go-tool/$(TARG): $(TARG)
mkdir -p "$(GOROOT)/bin/go-tool" && cp $(TARG) "$(GOROOT)/bin/go-tool/$(TARG)"
%.$(HOST_O): %.c
$(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
この新しいMakefileは、C言語で書かれたGoツールをビルドするための中心的な役割を担います。特に注目すべきは、$GOROOT/bin/go-tool という専用のインストールディレクトリが導入された点です。これにより、Goの標準ツールとC言語で書かれた補助ツールが明確に分離されます。Windows環境での .exe 拡張子の自動付与は、クロスプラットフォーム対応の一環です。
src/cmd/cov/Makefile (抜粋)
-TARG=6cov
+TARG=cov
OFILES=\
main.$O\
tree.$O\
# ...
NOINSTALL=1
-include ../../Make.ccmd
+include ../../Make.ctool
# ... (install-darwin, install-default rules) ...
install-default: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+ cp $(TARG) "$(GOBIN)"/go-tool/$(TARG)
cov ツールのMakefileの変更は、他のCツール(nm, prof)にも共通するパターンを示しています。
TARGの変更:6covからcovへと名前が簡潔になりました。includeの変更: 汎用的なMake.ccmdから、Cツール専用のMake.ctoolへとビルドシステムが切り替わりました。これにより、Cツールに特化したビルドルールが適用されます。- インストールパスの変更:
$(GOBIN)直下ではなく、$(GOBIN)/go-tool/サブディレクトリにインストールされるようになりました。これは、Goツールチェイン内のツールの役割と配置をより明確にするための整理です。
src/sudo.bash (抜粋)
for i in prof cov
do
# Remove old binaries if present
sudo rm -f /usr/local/bin/6$i
# Install new binaries
sudo cp "$GOROOT"/src/cmd/$i/$i /usr/local/bin/go$i
sudo chgrp procmod /usr/local/bin/go$i
sudo chmod g+s /usr/local/bin/go$i
done
このシェルスクリプトは、cov と prof をシステムワイドにインストールする際のロジックを更新しています。
sudo rm -f /usr/local/bin/6$i: 以前の命名規則 (6cov,6prof) でインストールされていた古いバイナリを削除します。sudo cp "$GOROOT"/src/cmd/$i/$i /usr/local/bin/go$i: 新しい命名規則 (cov,prof) でビルドされたバイナリを、/usr/local/bin/go$iというパスでシステムにコピーします。これにより、例えばgocovやgoprofのようなコマンド名でこれらのツールが利用できるようになります。sudo chgrp procmod /usr/local/bin/go$iとsudo chmod g+s /usr/local/bin/go$i: これらのコマンドは、インストールされたバイナリのグループ所有者をprocmodに変更し、setgidビットを設定します。setgidビットが設定された実行可能ファイルは、そのファイルが属するグループの権限で実行されます。これは、プロファイリングやカバレッジ測定ツールが、システムプロセス情報へのアクセスなど、特定の特権を必要とする場合に用いられるセキュリティ設定です。
src/cmd/go/tool.go (抜粋)
func listTools() {
// ...
// Old: sort.StringSlice(names).Sort()
sort.Strings(names) // New
for _, name := range names {
// ...
}
}
この変更は、Goの標準ライブラリの sort パッケージの利用方法を更新したものです。sort.StringSlice(names).Sort() は、[]string 型を sort.Interface インターフェースに適合させるための古いイディオムでした。sort.Strings(names) は、Go 1.8で導入された sort パッケージのヘルパー関数であり、[]string を直接ソートできるため、より簡潔で読みやすいコードになります。これは機能的な変更ではなく、コードの現代化とベストプラクティスへの準拠を示しています。
関連リンク
- Go言語公式ウェブサイト: https://golang.org/
- Goのソースコードリポジトリ (GitHub): https://github.com/golang/go
- GoのIssue Tracker (Gerrit): https://go.dev/issue (このコミットのChange-Id:
5576067に関連するGerritの変更セットは、古いGerritインスタンスのものである可能性があり、直接アクセスできない場合があります。)
参考にした情報源リンク
- Go言語のMakefileに関するドキュメントや議論 (Goのソースコード内のコメントや関連するコミット履歴)
- Goの
sortパッケージのドキュメント: https://pkg.go.dev/sort - Unix
nmコマンドのmanページ bisonのドキュメントgdbのドキュメント