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

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

このコミットは、Go言語のランタイムパッケージにおける自動生成ファイルの管理方法を改善することを目的としています。具体的には、以前の試み(CL 5493063)が失敗に終わったことを踏まえ、Makefileの代わりにシェルスクリプト(autogen.sh)を使用して、OSやアーキテクチャに依存するランタイムの定義ファイルやアセンブリヘッダーファイルを生成するように変更しています。これにより、ビルドプロセスの堅牢性と保守性が向上しています。

コミット

commit 55889409f8d44fab8f7715ec2d66286b857e25e7
Author: Russ Cox <rsc@golang.org>
Date:   Mon Dec 19 15:51:13 2011 -0500

    runtime: separate out auto-generated files, take 2
    
    This is like the ill-fated CL 5493063 except that
    I have written a shell script (autogen.sh) instead of
    thinking I could possibly write a correct Makefile.
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5496075

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

https://github.com/golang/go/commit/55889409f8d44fab8f7715ec2d66286b857e25e7

元コミット内容

runtime: separate out auto-generated files, take 2

このコミットは、自動生成ファイルを分離する2回目の試みです。以前の失敗したCL 5493063とは異なり、今回は正確なMakefileを書くことが不可能だと考え、代わりにシェルスクリプト(autogen.sh)を作成しました。

変更の背景

Go言語のランタイムは、様々なOS(GOOS)とアーキテクチャ(GOARCH)の組み合わせに対応するために、多くのプラットフォーム固有のコードを含んでいます。これらのコードの一部は、ビルド時に自動生成されるファイルに依存しています。以前は、これらの自動生成ファイルの管理がMakefileによって行われていましたが、Makefileの複雑さやプラットフォーム間の差異への対応の難しさから、ビルドプロセスの堅牢性に課題がありました。

コミットメッセージにある「ill-fated CL 5493063」は、おそらく以前の自動生成ファイル分離の試みがうまくいかなかったことを示唆しています。Makefileは強力なツールですが、特にクロスプラットフォーム対応や複雑な依存関係の管理においては、その記述が非常に難しく、エラーが発生しやすいという問題があります。

このコミットの背景には、このようなMakefileの限界を認識し、よりシンプルで堅牢なシェルスクリプト(autogen.sh)に自動生成処理を移行することで、ビルドプロセスの信頼性を向上させたいという意図があります。シェルスクリプトは、Makefileに比べて記述が直接的であり、特定のタスクの自動化に適しています。

前提知識の解説

Go言語のビルドプロセスとクロスコンパイル

Go言語は、その強力なクロスコンパイル機能で知られています。これは、あるOS/アーキテクチャ上で、別のOS/アーキテクチャ向けのバイナリを生成できる能力を指します。この機能は、GOOS(ターゲットOS)とGOARCH(ターゲットアーキテクチャ)という環境変数によって制御されます。

Goのビルドシステムは、これらの環境変数に基づいて、適切なソースファイルを選択し、コンパイルします。例えば、runtimeパッケージには、sys_linux_amd64.sdefs_windows.goのように、特定のOSやアーキテクチャに特化したファイルが存在します。

Makefileとシェルスクリプト

  • Makefile: makeユーティリティが使用するビルド自動化ツールです。依存関係を定義し、それらの依存関係が変更された場合にのみ特定のコマンドを実行することで、効率的なビルドを可能にします。しかし、複雑なロジックや条件分岐、特にクロスプラットフォーム対応が必要な場合には、記述が複雑になりがちです。
  • シェルスクリプト: bashなどのシェルで実行されるスクリプトです。一連のコマンドを順次実行する形式で、特定のタスクの自動化に非常に適しています。Makefileのような依存関係の自動解決機能はありませんが、そのシンプルさから、特定のビルドステップやファイル生成処理の自動化によく用いられます。

Goランタイムパッケージ

Goのruntimeパッケージは、Goプログラムの実行を支える低レベルの機能を提供します。これには、ガベージコレクション、スケジューラ、メモリ管理、システムコールインターフェースなどが含まれます。runtimeパッケージのコードは、Go言語だけでなく、C言語やアセンブリ言語で書かれた部分も多く、OSやアーキテクチャに深く依存しています。

自動生成ファイル

ソフトウェア開発において、特定の情報(バージョン情報、OS/アーキテクチャ固有の定数、構造体のオフセットなど)は、手動で記述するのではなく、スクリプトによって自動的に生成されることがあります。これにより、手作業によるエラーを防ぎ、常に最新かつ正確な情報がコードに反映されるようになります。Goのランタイムでは、ビルド時にこれらの情報がC言語のヘッダーファイルやGo言語のソースファイルとして生成され、他のソースファイルから利用されます。

技術的詳細

このコミットの主要な変更点は、Goランタイムの自動生成ファイルの生成ロジックをMakefileからautogen.shという新しいシェルスクリプトに移行したことです。

autogen.shの導入

src/pkg/runtime/autogen.shが新規に作成されました。このスクリプトは、GOOSGOARCHの組み合わせごとに、以下のファイルを生成します。

  1. zgoarch_*.go: 各アーキテクチャ(386, amd64, arm)に対応するGoの定数ファイル。theGoarchという定数にアーキテクチャ名が設定されます。
  2. zgoos_*.go: 各OS(darwin, freebsd, linux, netbsd, openbsd, plan9, windows)に対応するGoの定数ファイル。theGoosという定数にOS名が設定されます。
  3. zruntime_defs_*.go: mkgodefs.shスクリプトを使用して、C言語の構造体定義をGo言語の構造体定義に変換したファイル。これにより、Goのコードからランタイムの内部構造にアクセスできるようになります。ファイル名はzruntime_defs_GOOS_GOARCH.goの形式になります。
  4. zasm_*.h: mkasmh.shスクリプトを使用して、アセンブリコードからランタイムの構造体オフセットなどの情報を抽出したCヘッダーファイル。アセンブリコードがGoランタイムの内部構造にアクセスする際に利用されます。ファイル名はzasm_GOOS_GOARCH.hの形式になります。
  5. zversion.go: mkversionツールを使用して、Goのバージョン情報をGoの定数として定義したファイル。

これらの生成されたファイルは、ファイル名の先頭にzが付けられています。これは、Goのビルドシステムにおいて、自動生成されたファイルであることを示す慣例的なプレフィックスです。また、これらのファイルには「AUTO-GENERATED by autogen.sh; DO NOT EDIT」というコメントが追加され、手動での編集を避けるように促しています。

Makefileの変更

src/pkg/runtime/Makefileからは、自動生成ファイルに関する複雑なルールが削除されました。代わりに、autogen.shがこれらのファイルを生成する責任を負います。

  • GOFILESリストから、runtime_defs.go, version.go, version_*.goといった自動生成されるファイルが削除され、代わりにzgoarch_$(GOARCH).go, zgoos_$(GOOS).go, zruntime_defs_$(GOOS)_$(GOARCH).go, zversion.goといった新しい自動生成ファイルが追加されました。
  • CLEANFILESからも、古い自動生成ファイルが削除され、新しい自動生成ファイル(z*で始まるファイル)がclean-localターゲットで削除されるようになりました。
  • asm_$(GOARCH).hなどのヘッダーファイルの生成ルールも削除され、autogen.shzasm_GOOS_GOARCH.hを生成するように変更されました。
  • src/make.bashでは、pkgのビルドの前にautogen.shを実行するステップが追加されました。これにより、ランタイムパッケージのビルドに必要な自動生成ファイルが事前に準備されるようになります。

アセンブリファイルの変更

src/pkg/runtime/asm_*.sファイル(例: asm_386.s, asm_amd64.s, asm_arm.s)では、インクルードするヘッダーファイルがasm_$(GOARCH).hからzasm_GOOS_GOARCH.hに変更されました。これは、autogen.shによって生成される新しいヘッダーファイルを参照するためです。

goc2c.cmkversion.cの変更

これらのC言語のソースファイルには、生成されるファイルの先頭に「// AUTO-GENERATED by autogen.sh; DO NOT EDIT」というコメントを追加するためのprintf文が追加されました。

defs_*.goファイルの変更

src/pkg/runtime/defs*_*.goファイルには、// +build ignoreというビルドタグが追加されました。これは、これらのファイルが直接Goのビルドプロセスに含まれるのではなく、cgo -cdefsのようなツールによって処理されることを示しています。

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

  • src/pkg/runtime/autogen.sh: 新規追加されたシェルスクリプト。自動生成ファイルの生成ロジックをカプセル化。
  • src/pkg/runtime/Makefile: 自動生成ファイルに関する複雑なルールが削除され、新しい自動生成ファイルが参照されるように変更。
  • src/make.bash: autogen.shの実行ステップが追加され、ビルドプロセスに組み込まれた。
  • src/pkg/runtime/asm_*.s: インクルードするヘッダーファイルがasm_$(GOARCH).hからzasm_GOOS_GOARCH.hに変更。
  • src/pkg/runtime/goc2c.c, src/pkg/runtime/mkversion.c: 自動生成コメントの追加。

コアとなるコードの解説

autogen.sh

このスクリプトは、Goランタイムのビルドプロセスにおいて、OSやアーキテクチャに依存する様々なファイルを自動的に生成する中心的な役割を担います。

#!/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.

# This script generates the various derived files involved in
# building package runtime. 
#
# autogen.sh rebuilds everything
# autogen.sh -clean deletes the generated files

# ... (GOARCHES, GOOSES, GOOSARCHES, HELPERS の定義) ...

rm -f $HELPERS z* # 既存のヘルパーと自動生成ファイルを削除

if [ "$1" = "-clean" ]; then
	exit 0
fi

set -e # エラーが発生したらスクリプトを終了

if [ "$GOROOT" = "" ]; then
	echo "$0"': $GOROOT must be set' >&2
	exit 2
fi

# Use goc2c to translate .goc files into arch-specific .c files.
quietgcc -o goc2c -I "$GOROOT/include" goc2c.c "$GOROOT/lib/lib9.a"
for file in *.goc
do
	for arch in $GOARCHES
	do
		base=$(echo $file | sed 's/\.goc$//')
		GOARCH=$arch ./goc2c $file >z.tmp
		mv -f z.tmp z${base}_$arch.c
	done
done

# Version constants.
quietgcc -o mkversion -I "$GOROOT/include" mkversion.c "$GOROOT/lib/lib9.a"
GOROOT="$GOROOT_FINAL" ./mkversion >z.tmp
mv z.tmp zversion.go

for arch in $GOARCHES
do
	(
		echo '// AUTO-GENERATED by autogen.sh; DO NOT EDIT'
		echo
		echo 'package runtime'
		echo
		echo 'const theGoarch = "'$arch'"'
	) >zgoarch_$arch.go
done

for os in $GOOSES
do
	(
		echo '// AUTO-GENERATED by autogen.sh; DO NOT EDIT'
		echo
		echo 'package runtime'
		echo
		echo 'const theGoos = "'$os'"'
	) >zgoos_$os.go
done

# Definitions of runtime structs, translated from C to Go.
for osarch in $GOOSARCHES
do
	./mkgodefs.sh $osarch proc.c iface.c hashmap.c chan.c >z.tmp
	mv -f z.tmp zruntime_defs_$osarch.go
done

# Struct field offsets, for use by assembly files.
for osarch in $GOOSARCHES
do
	./mkasmh.sh $osarch proc.c defs.h >z.tmp
	mv -f z.tmp zasm_$osarch.h
done

rm -f $HELPERS

このスクリプトは、goc2cmkversionmkgodefs.shmkasmh.shといったヘルパースクリプトやツールを呼び出し、それぞれのOS/アーキテクチャの組み合わせに対して必要なファイルを生成します。これにより、ビルドシステムはこれらの自動生成ファイルを直接利用できるようになり、Makefileの複雑な依存関係管理から解放されます。

Makefileの変更の意図

src/pkg/runtime/Makefileから自動生成に関するルールを削除し、src/make.bashautogen.shを呼び出すように変更したことで、ビルドプロセスの責任分担が明確になりました。Makefileはコンパイルとリンクのルールに集中し、ファイルの生成はautogen.shに任せることで、それぞれのツールの得意分野を活かしています。これにより、ビルドシステムの全体的な理解と保守が容易になります。

アセンブリファイルのヘッダー変更

アセンブリファイルがzasm_GOOS_GOARCH.hをインクルードするように変更されたのは、autogen.shによって生成される新しいヘッダーファイルが、OSとアーキテクチャに特化した構造体オフセットなどの情報を提供するためです。これにより、アセンブリコードは常に正確なランタイムの内部構造にアクセスできるようになります。

関連リンク

参考にした情報源リンク