[インデックス 15791] ファイルの概要
このコミットは、Go言語のビルドシステムにおける特定のバグ修正に関するものです。具体的には、64ビットWindowsシステム上で32ビットWindows向けGoプログラムをビルドする際に発生していた問題に対処しています。変更はinclude/libc.h
ファイル内の条件付きコンパイルディレクティブにあり、timespec
構造体の定義に関するロジックが修正されています。
コミット
commit 0f1b4880935a4eddef135d4d32d2240196184e9f
Author: Russ Cox <rsc@golang.org>
Date: Fri Mar 15 12:30:14 2013 -0400
build: fix for 32-bit windows builds on 64-bit windows system
Thanks to jon.forums@ for the fix.
Fixes #5051.
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/7813045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0f1b4880935a4eddef135d4d32d2240196184e9f
元コミット内容
このコミットは、Go言語のビルドプロセスにおいて、64ビットWindows環境で32ビットWindowsバイナリをクロスコンパイルする際の不具合を修正します。具体的には、include/libc.h
ファイル内でtimespec
構造体が誤って定義される問題を解決しています。この修正は、jon.forums@
氏によって提供されたもので、Go issue #5051を解決します。
変更の背景
Go言語はクロスコンパイルを強力にサポートしており、異なるアーキテクチャやオペレーティングシステム向けのバイナリを生成できます。しかし、特定の環境の組み合わせ、特に64ビットWindows上で32ビットWindows向けのGoプログラムをビルドする際に、ビルドシステムが予期せぬ動作をしていました。
この問題は、Goのランタイムや標準ライブラリがC言語のコード(またはC言語のヘッダファイル)と連携する部分で発生していました。include/libc.h
は、Goの内部で利用されるC言語の標準ライブラリ関数や構造体の定義を含むヘッダファイルであり、Goプログラムが低レベルのシステムコールやOS固有の機能とやり取りする際に重要です。
具体的な問題は、timespec
構造体の定義に関するものでした。timespec
は、秒とナノ秒で時間を表現するための構造体で、POSIX標準で定義されており、多くのUNIX系システムや、Windows上でもMinGWなどの環境で利用されます。Goのビルドシステムが、64ビットWindows上で32ビットターゲットをビルドする際に、このtimespec
構造体が正しく条件付きコンパイルされず、結果としてビルドエラーや予期せぬ動作を引き起こしていました。
このバグはGo issue #5051として報告されており、このコミットはその報告された問題を解決するために行われました。
前提知識の解説
このコミットを理解するためには、以下の前提知識が役立ちます。
- クロスコンパイル: あるプラットフォーム(ホスト)で、別のプラットフォーム(ターゲット)向けの実行可能ファイルを生成するプロセス。Go言語は、
GOOS
(ターゲットOS)やGOARCH
(ターゲットアーキテクチャ)といった環境変数を設定することで、簡単にクロスコンパイルが可能です。 - 条件付きコンパイル: C/C++言語において、プリプロセッサディレクティブ(
#ifdef
,#ifndef
,#if
,#elif
,#else
,#endif
など)を使用して、特定の条件が満たされた場合にのみコードの一部をコンパイルする仕組み。これにより、異なるプラットフォームやコンパイラ設定に応じて、適切なコードパスを選択できます。 _WIN32
: Microsoft Visual C++ (MSVC) やMinGWなどのWindows向けコンパイラで定義されるプリプロセッサマクロ。Windowsプラットフォーム向けにコンパイルされていることを示します。_WIN64
: MSVCやMinGWなどのWindows向けコンパイラで定義されるプリプロセッサマクロ。64ビットWindowsプラットフォーム向けにコンパイルされていることを示します。__MINGW64_VERSION_MAJOR
: MinGW-w64コンパイラを使用している場合に定義されるプリプロセッサマクロ。MinGW-w64は、Windows上でGCCツールチェーンを提供するプロジェクトであり、32ビットおよび64ビットのWindowsバイナリを生成できます。このマクロは、MinGW-w64のメジャーバージョンを示します。timespec
構造体: POSIX標準で定義されている時間構造体。秒(tv_sec
)とナノ秒(tv_nsec
)で構成され、高精度な時間表現やタイマー、スリープ関数などで使用されます。Windows環境では、通常はtimeval
構造体が使われることが多いですが、MinGWなどのPOSIX互換レイヤーではtimespec
が提供されることがあります。- Goのビルドシステム: Go言語のビルドシステムは、Goソースコードをコンパイルして実行可能ファイルを生成するだけでなく、C言語で書かれた部分(Goランタイムの一部やcgoでリンクされるライブラリなど)も適切にコンパイル・リンクする役割を担っています。
技術的詳細
このコミットの技術的な核心は、include/libc.h
ファイル内のtimespec
構造体の条件付き定義にあります。
元のコードでは、_WIN32
が定義されている(つまりWindows向けビルドである)場合に、さらに_WIN64
が定義されていない(つまり32ビットWindows向けビルドである)場合にのみtimespec
構造体を定義していました。
#ifdef _WIN32
#ifndef _WIN64 // <-- ここが問題
struct timespec {
int tv_sec;
long tv_nsec;
};
#endif
// ...
このロジックは、Visual C++などのMicrosoftのコンパイラを使用する場合には適切に機能する可能性があります。しかし、MinGW-w64のようなGCCベースのクロスコンパイラを使用する場合に問題が発生しました。
MinGW-w64は、64ビットWindows上で動作しながら、32ビットWindowsターゲット向けのバイナリを生成できます。この場合、コンパイル環境は64ビットWindowsですが、ターゲットは32ビットWindowsです。MinGW-w64環境では、_WIN64
マクロは定義されない可能性があります(ターゲットが32ビットであるため)。しかし、MinGW-w64自体がtimespec
構造体を独自に提供している場合があり、Goのビルドシステムがこの構造体を再定義しようとすると、コンパイラエラーやリンカエラーが発生する可能性がありました。
修正後のコードでは、_WIN64
が定義されていないことに加えて、__MINGW64_VERSION_MAJOR
も定義されていない場合にのみtimespec
構造体を定義するように変更されました。
#ifdef _WIN32
#if !defined(_WIN64) && !defined(__MINGW64_VERSION_MAJOR) // <-- 修正箇所
struct timespec {
int tv_sec;
long tv_nsec;
};
#endif
// ...
この変更により、MinGW-w64コンパイラを使用している場合(__MINGW64_VERSION_MAJOR
が定義されている場合)は、たとえ_WIN64
が定義されていなくても、Goのビルドシステムはtimespec
構造体を再定義しなくなります。これは、MinGW-w64が既に適切なtimespec
定義を提供していることを前提としています。これにより、コンパイラの衝突が回避され、64ビットWindows上での32ビットWindows向けGoビルドが正常に完了するようになります。
この修正は、Goのビルドシステムが異なるコンパイラツールチェーン(MSVCとMinGW)の挙動の違いを適切に考慮し、より堅牢なクロスコンパイル環境を提供する上で重要です。
コアとなるコードの変更箇所
変更はinclude/libc.h
ファイルにあります。
--- a/include/libc.h
+++ b/include/libc.h
@@ -308,7 +308,7 @@ extern void flagprint(int);\
#ifdef _WIN32
-#ifndef _WIN64
+#if !defined(_WIN64) && !defined(__MINGW64_VERSION_MAJOR)
struct timespec {
\tint tv_sec;
\tlong tv_nsec;
コアとなるコードの解説
変更された行は以下の通りです。
- #ifndef _WIN64
(変更前)+ #if !defined(_WIN64) && !defined(__MINGW64_VERSION_MAJOR)
(変更後)
この変更は、timespec
構造体を定義する条件をより厳密にしています。
- 変更前:
_WIN32
が定義されており、かつ_WIN64
が定義されていない場合にtimespec
を定義していました。これは、32ビットWindows環境を意図していました。 - 変更後:
_WIN32
が定義されており、かつ_WIN64
が定義されておらず、さらに__MINGW64_VERSION_MAJOR
も定義されていない場合にのみtimespec
を定義するように変更されました。
この追加された条件!defined(__MINGW64_VERSION_MAJOR)
が重要です。
MinGW-w64コンパイラは、64ビットWindows上で32ビットターゲットをビルドする際に、_WIN64
が定義されないことがあります。しかし、MinGW-w64自体はtimespec
構造体を標準で提供しているため、Goのビルドシステムが独自にtimespec
を定義しようとすると、重複定義となりコンパイルエラーを引き起こします。
この修正により、MinGW-w64を使用している場合(__MINGW64_VERSION_MAJOR
が定義されている場合)は、Goのビルドシステムはtimespec
の定義をスキップし、MinGW-w64が提供する定義を利用するようになります。これにより、コンパイラ間の互換性の問題が解決され、64ビットWindows上での32ビットGoバイナリのビルドが成功するようになります。
関連リンク
- Go issue #5051: https://github.com/golang/go/issues/5051
- Go CL 7813045: https://golang.org/cl/7813045
参考にした情報源リンク
- MinGW-w64プロジェクト: https://mingw-w64.org/
- POSIX
timespec
構造体に関する情報 (例: Linux man pages): https://man7.org/linux/man-pages/man3/timespec.3.html - Microsoftのプリプロセッサ定義に関する情報 (例:
_WIN32
,_WIN64
): https://learn.microsoft.com/ja-jp/cpp/preprocessor/predefined-macros?view=msvc-170 - Go言語のクロスコンパイルに関するドキュメント: https://go.dev/doc/install/source#environment (Goの公式ドキュメント)
- GCC Preprocessor Defines: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html (GCCのプリプロセッサマクロに関する情報)
- Stack Overflowや技術フォーラムでの関連議論 (具体的なURLは省略しますが、
_WIN64
,__MINGW64_VERSION_MAJOR
,timespec
などのキーワードで検索)