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

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

このコミットは、Go言語のランタイムパッケージにおけるmkasmh.shスクリプトの修正に関するものです。mkasmh.shは、Goのビルドプロセスにおいて、アセンブリコードから利用されるヘッダーファイルを生成する役割を担っています。具体的には、arch_GOARCH.h, defs_GOOS_GOARCH.h, os_GOOS.h, signals_GOOS.hといったファイルが生成されます。

コミット

Goランタイムのビルドプロセスにおける、一時的なヘッダーファイルのクリーンアップに関するバグ修正。特定の条件下で一時ファイルが適切に削除されず、誤ったヘッダーファイルがコンパイル時に使用される問題を解決します。

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

https://github.com/golang/go/commit/bacb1b70f77764a1e381645c90b44b5818fd9e28

元コミット内容

runtime: fix mkasmh.h

We weren't properly deleting the various header
files (that were temporarily renamed) if a $CC
for the current $GOARCH didn't exist. And since
the compiler checks the current directory for
headers before any -I arguments, this had the
unfortunate side effect of including the last
generated headers instead of the correct ones.

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

変更の背景

このコミットの背景には、Goのビルドシステムにおけるヘッダーファイルの取り扱いに関する問題がありました。mkasmh.shスクリプトは、Goのランタイムが使用するアセンブリヘッダーファイルを生成します。この生成プロセスでは、一時的なヘッダーファイルが作成され、その後削除されることが期待されます。

しかし、以前の実装では、特定の条件下でこれらのヘッダーファイルが適切に削除されないという問題がありました。具体的には、現在の$GOARCH(ターゲットアーキテクチャ、例: amd64, armなど)に対応する$CC(Cコンパイラ)が存在しない場合、スクリプトが途中で終了し、一時ファイルが残ってしまうことがありました。

この問題が深刻だったのは、コンパイラがヘッダーファイルを検索する際に、-Iオプションで指定されたパスよりも現在のディレクトリを優先して検索するという特性があったためです。これにより、以前のビルドで生成された古い、あるいは誤ったヘッダーファイルが現在のビルドで誤って読み込まれてしまい、ビルドの失敗や予期せぬ動作を引き起こす可能性がありました。このコミットは、このような不整合を防ぎ、ビルドプロセスの堅牢性を高めることを目的としています。

前提知識の解説

  • mkasmh.sh: Go言語のランタイムパッケージ(src/pkg/runtime)に存在するシェルスクリプトです。Goのビルドプロセスの一部として実行され、アセンブリコードから参照されるC言語形式のヘッダーファイル(例: arch_GOARCH.h, defs_GOOS_GOARCH.hなど)を生成します。これらのヘッダーファイルには、Goの内部構造や定数、オフセットなどが定義されており、アセンブリコードがGoのランタイムと正しく連携するために不可欠です。

  • $CC$GOARCH:

    • $CC: Goのビルドシステムで使用される環境変数で、Cコンパイラを指定します。Goのランタイムの一部はC言語で書かれており、これをコンパイルするためにCコンパイラが必要です。
    • $GOARCH: Goのビルドシステムで使用される環境変数で、ターゲットとするCPUアーキテクチャを指定します(例: amd64, arm, 386など)。Goのクロスコンパイル機能において重要な役割を果たします。
  • コンパイラのヘッダーファイル検索パス: C/C++コンパイラ(例: GCC, Clang)は、ソースコード中で#includeディレクティブによって指定されたヘッダーファイルを特定の順序で検索します。一般的な検索順序は以下の通りです。

    1. 現在のディレクトリ: ソースファイルが存在するディレクトリ。
    2. -Iオプションで指定されたディレクトリ: コンパイルコマンドラインで-Iフラグを使って明示的に指定されたディレクトリ。
    3. 標準インクルードパス: コンパイラやシステムがデフォルトで認識している標準ライブラリのヘッダーファイルが置かれているディレクトリ。 この順序のため、現在のディレクトリに古いヘッダーファイルが残っていると、-Iで正しいパスが指定されていても、そちらが優先されて誤ったファイルが読み込まれる可能性があります。
  • trapコマンド (シェルスクリプト): Unix/Linuxシェル(Bash, Zshなど)の組み込みコマンドで、スクリプトの実行中に特定のシグナルを受信した際や、スクリプトが終了する際に実行するコマンドを指定できます。

    • 構文: trap 'command_list' SIGNAL1 SIGNAL2 ...
    • EXIT: スクリプトが正常終了または異常終了する直前に実行されます。
    • SIGINT: Ctrl+Cなどによって発生する割り込みシグナル。
    • SIGTERM: プロセス終了要求シグナル。 trapを使用することで、スクリプトの途中でエラーが発生したり、ユーザーによって中断されたりした場合でも、クリーンアップ処理(一時ファイルの削除など)を確実に実行させることができます。

技術的詳細

このコミットの核心は、シェルスクリプトのtrapコマンドを導入することで、一時的に生成されるヘッダーファイルのクリーンアップ処理をより堅牢にした点にあります。

以前のmkasmh.shスクリプトでは、一時ファイルの削除はスクリプトの末尾にrm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.hという形で記述されていました。この方法は、スクリプトが最後まで正常に実行された場合には問題なく機能します。

しかし、コミットメッセージに記載されているように、「$CC for the current $GOARCH didn't exist」といった理由でスクリプトが途中でエラー終了した場合、末尾のrmコマンドは実行されません。その結果、古い、あるいは不完全なヘッダーファイルがビルドディレクトリに残ってしまいます。

この残された古いヘッダーファイルが問題を引き起こします。Goのビルドシステムは、異なる$GOARCH$GOOS(ターゲットOS)に対して、それぞれ異なるヘッダーファイルを生成する必要があります。コンパイラがヘッダーファイルを検索する際、現在のディレクトリを優先するため、もし古いヘッダーファイルが残っていると、新しいビルドで正しいヘッダーファイルが生成されても、コンパイラは誤って古いファイルを読み込んでしまう可能性があります。これは、ビルドの不整合や、最悪の場合、誤ったバイナリの生成につながります。

このコミットでは、スクリプトの冒頭に以下のtrapコマンドを追加することでこの問題を解決しています。 trap "rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h" EXIT SIGINT SIGTERM

このtrapコマンドは、スクリプトが終了する際(EXIT)、またはSIGINT(割り込み)やSIGTERM(終了要求)シグナルを受信した際に、指定されたrm -fコマンドを実行するようにシェルに指示します。これにより、スクリプトが正常終了するか、エラーで中断されるか、ユーザーによって強制終了されるかに関わらず、一時ファイルが確実に削除されるようになります。

この変更により、ビルド環境の不安定性(例えば、必要なコンパイラが見つからない場合など)によってスクリプトが途中で終了しても、一時ファイルが残存して後続のビルドに悪影響を与えることがなくなりました。これは、Goのビルドシステムの堅牢性と信頼性を向上させる重要な修正です。

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

--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.

+trap "rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h" EXIT SIGINT SIGTERM
 set -e

 SYS=$1
@@ -135,5 +136,3 @@ aggr != \"\" && /^\t/ {\
 \tprintf(\"#define %s_%s %s\\n\", aggr, name, offset);\
 }\
 \'
-\
-rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h

コアとなるコードの解説

変更はsrc/pkg/runtime/mkasmh.shファイルに対して行われています。

  1. 追加された行:

    trap "rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h" EXIT SIGINT SIGTERM
    

    この行はスクリプトの冒頭、set -eの直前に追加されています。これは、スクリプトが実行を開始した直後に、クリーンアップ処理をフックとして登録することを意味します。

    • trap: シェルコマンドで、シグナルハンドラを設定します。
    • "rm -f ...": シグナルを受信した際に実行されるコマンドです。rm -fは、指定されたファイルを強制的に削除します(存在しない場合でもエラーにならない)。削除対象は、mkasmh.shが生成する一時的なヘッダーファイルです。
    • EXIT: スクリプトが正常終了するか、エラーで終了するかにかかわらず、スクリプトが終了する直前に指定されたコマンドを実行します。
    • SIGINT: ユーザーがCtrl+Cなどでスクリプトを中断しようとしたときに発生するシグナルです。
    • SIGTERM: プロセスを終了させるための一般的なシグナルです。 このtrap設定により、スクリプトがどのような形で終了しても、一時ファイルが確実に削除されることが保証されます。
  2. 削除された行:

    rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h
    

    この行はスクリプトの末尾から削除されました。これは、trapコマンドによるクリーンアップ処理が導入されたため、スクリプトの通常の実行フローの最後に明示的に削除コマンドを置く必要がなくなったためです。trapはより包括的なクリーンアップメカニズムを提供します。

この変更により、mkasmh.shスクリプトは、その実行が中断されたり、エラーで終了したりした場合でも、生成した一時ファイルを確実にクリーンアップするようになりました。これにより、Goのビルドプロセスにおけるヘッダーファイルの不整合の問題が解消され、ビルドの信頼性が向上しました。

関連リンク

参考にした情報源リンク