プログラミング
Windows XP向けPrincipiaの構築
Building Principia for Windows XP (voxelmanip.se)
要約
Principiaは2014年のリリース当初、Windows XPでも動作するゲームでした。オープンソース化された現在、モダンなツールチェインや依存関係によりWindows XPでの動作は保証されませんが、この記事では、カスタムツールチェインを構築し、古い依存関係をビルドすることで、PrincipiaをWindows XPで再び動作させるための技術的な道のりが詳細に説明されています。特に、GCCのコンパイル問題やlibstdc++の互換性問題への対処が詳しく解説されています。
全文翻訳
Windows XP向けPrincipiaの構築 2026年6月28日 2948ワード プロジェクト
Principiaが2014年にWindows向けにリリースされた当時、このゲームはWindows XPのような古いバージョンでも動作しました。Principia 1.4がWindows XPがまだメインストリームサポートを受けていた時期にリリースされたことを考えると、これは当時当然のことであり、当時のツールと依存関係がXPと互換性があったため、サポートしない理由は特にありませんでした。現在、Principiaはオープンソースプロジェクトとして進んでいます。Windows版は依然としてWindows 7まで動作するはずですが、UCRTなどの最新のツールチェイン、依存関係、システムライブラリの使用により、エコシステムが進展するにつれて将来にわたってそれを真に保証することは困難です。しかし、これはいつか変えたいと思っていたことであり、PrincipiaをWindows XPに再び対応させ、その上で動作する完全にオープンソースのビルドを作成したいと考えていました。
Principiaの技術的詳細
まず、この取り組みに関連するPrincipiaの技術的詳細を説明することが役立つと思います。Principiaはもともと2012年頃の携帯電話で動作するように設計されたゲームなので、OpenGL 2.0以上をサポートしていれば、非常に古いハードウェアでも問題なく動作するはずです。Principiaは依存関係が非常に少なく、クロスプラットフォームサポートのためにSDLを利用しています。SDL(SDL2と新しいSDL3の両方)は引き続きWindows XPをサポートしており、前述の通りPrincipiaもWindows XPで動作していました。したがって、オープンソース版の開発中にXP互換性を損なう変更を行っていなければ、コードの変更をそれほど多くすることなく、XPで再び動作させることができるはずです。主な問題は、ツールチェインと、新しいWindowsバージョンに移行したいくつかの他の依存関係です。PrincipiaのWindows版は、公式にはmingw-w64 Windowsツールチェインでのコンパイルのみをサポートしています。歴史的にこれはMSVCがPrincipiaのバックエンドエンジンTMSで使用されているC99機能のサポートを欠いていたためですが、現在の状況がどうなっているかはわかりません。しかし、mingw-w64には、Windowsにネイティブには存在しない単純なC関数のためのさまざまなポリフィルも含まれており、MSVCでPrincipiaをビルドすることに強い関心を持つ人が現れない限り、これは当分変わることはないでしょう。いずれにせよ、FOSSツールチェインは、古いバージョンのWindowsをターゲットにできる最新バージョンを簡単に手に入れることができる傾向があります。しかし、公式のWindowsビルドに使用しているMSYS2の現在のLLVMベースのmingw-w64ツールチェインは、UCRTへのリンク、LLVMのlibc++が7+であること、およびその他のサポートライブラリが例えばVistaに存在するシンボルが常に存在することを期待してビルドされていることの両方のために、Windows XPをターゲットにするには不適切です。したがって、これから脱却して何か別のものを見つける必要があります…あるいは、ソースからビルドするしかありません。
独自のツールチェインを構築しよう!
Vista/7よりさらに古いバージョンに戻ると、既存のmingw-w64ツールチェインの互換性が低下し始めます。LLVMベースのツールチェインは、libc++がそれ以前のものをサポートしていないため、C++プロジェクトでは最低でもWindows 7が必要であり、その他のGCCベースのツールチェインは、Vista+のAPIが常に存在することを期待してビルドされたプリビルドのサポートライブラリを使用しています。95年のような古いバージョンをターゲットとすることを主な目的とするツールチェインもありますが、私は結局、独自のものを作成することにしました。これはおそらく最も簡単な方法であり、特にLinuxホスト上で実行しながらWindowsをターゲットとするクロスコンパイルツールチェインを望んでいたからです。
さて、GCC、binutils、mingw-w64をコンパイルします…他に何が必要でしょうか?ああ、困った…幸いなことに、Martin Storsjö(llvm-mingwの人として知られているかもしれません)が#mingw-w64 IRCチャンネルで以前にリンクしたDockerfileという切り札がありました。私は熱心で好奇心旺盛だったので、すでにこのDockerfileを入手し、単純なシェルスクリプトに書き換え、各コンポーネントごとに個別のステップに分割していました。手元にあったバージョンにいくつかの調整を加え、32ビットWindows用にトリプレットをi686-w64-mingw32に変更し、ターゲットとなるシステムランタイムとしてMSVCRTに切り替え、デフォルトのWIN32_WINNTを0x0501(Windows NT 5.1、Windows XPに対応)に設定しました。そして、まだビルドできるか試してみると…libgmp(GNU MP Bignumライブラリ)のビルドの最初のステップで、「機能するコンパイラがない」という奇妙なエラーで失敗しました。困惑して、autotoolsが生成したconfig.logを見ると、次のような非常に奇妙なコードをコンパイルしようとしてエラーが発生していました:
```c
for(i=0;i<1;i++){if(e(got,got,9,d[i].n)==0)h();g(i,d[i].src,d[i].n,got,d[i].want,9);if(d[i].n)h();}
```
これを最新のGCC 16でビルドしていたのですが、執筆時点でのGMPの最新安定版(6.3.0)は、デフォルト設定ではGCC 15+ではコンパイルできないようです。ビルドシステムには、空のパラメータを持つ関数を含むコードのコンパイル時チェックがあります。Cの古いバージョンでは、これは任意の数の引数を渡すことができることを意味していましたが(これを防ぐにはfoo(void)と記述します)、C23では、空のパラメータリストは引数を渡すことができないことを意味するように変更されました。GCC 15はデフォルトでC23を使用するため、このコードのコンパイルに失敗し、ビルドシステムはそれを壊れたコンパイラとして扱います。ArchのGMPのビルドスクリプトで最初の問題のパッチを見つけましたが、最終的にはautotoolsファイルを再生成することなく、GMPを-std=gnu99でビルドするように設定して、黙らせてビルドプロセスを続行させました。その後は、ほとんど順調に進みました!MPFR、次にMPC、次にbinutils、次にGCCをビルドしました。次に、新しくビルドしたGCCを使用してmingw-w64のCRTとライブラリをビルドし、そのツールチェインを使用してGCCのライブラリをビルドしました。ビルド中に、GCCでWindows XPの互換性を損なう最近の変更がないか、特にC++標準ライブラリで確認したいと思いました。そこで、GCC 16に同梱されているlibstdc++に、Vista+ Win32 API関数の新しいハード依存関係が追加されていることを発見しました。具体的には、std::chronoでタイムゾーン処理に使用されるGetDynamicTimeZoneInformationです。このような独自のツールチェインを構築しているとはいえ、私は他人のツールチェインから借りることも厭いません。w64devkitの32ビットバージョンはGCC 16を使用しており、Windows XPをまだサポートしており、そこでこのことを知りました。彼らは、前述のAPI関数への依存関係を動的なものに変えるパッチも持っており、シンボルを取得しようとし、存在しない場合は何もせずにフォールバックします。std::chronoはC++20の機能であり、PrincipiaはC++11の標準をほとんど利用していないため、スタブアウトするだけでも問題ありませんでした。しかし、既製のクリーンなパッチは常に最善です!そのパッチとGCCのコンパイルに時間を費やした後、Windows XPで動作するバイナリをほぼ確実に生成できるツールチェインができました。すべての部分はNT 5.1をターゲットとしてビルドされており、プログラムが新しい関数を使用しない限り、動作するはずです!単なる動作確認として、Wineで簡単な「Hello World」プログラムをコンパイルして実行したところ、コンパイラは実際に実行可能なWindows実行ファイルを作成できました。
依存関係の構築
Principiaをビルドする前に、新しくビルドしたツールチェインで依存関係をビルドする必要があります。Principiaには、外部から提供する必要がある以下の依存関係があります。
curl
Freetype
libjpeg-turbo
libpng
SDL
zlib
これらは世界で最も移植性の高い普遍的なソフトウェアライブラリの一部です!しかし、この中でcurlは少し手間がかかりました。curl 8.19.0でWindows XPのサポートを非常に最近終了しましたが、ネットワークライブラリとしては正直理解できます。しかし、なぜかcurl 8.18.0でさえ、XPには存在しないmsvcrt.dllのfreopen_s関数を見つけようとするため動作しませんでした。結局、curl 8.17.0を使用することにしましたが、実行する環境を考えるとそれでも非常に新しいものです。Luantiのコア開発者sfan5は、Windows用のさまざまな一般的なライブラリをクロスコンパイルするためのビルドスクリプトのリポジトリ(リンク)を持っており、それを利用しています。