VC++ランタイムが不要なPython DLLのビルド

Windows環境でPythonを組み込んだアプリケーションを開発してたんですが、Windowsインストーラでsystem32にコピーされるDLL(python**.dll)は、どうやらVC++ランタイムが必要なようです。

そう、Microsoftから「再頒布可能パッケージ」という名前でダウンロードできるアレ(MSVCR**.dll)です。
VSを持っている人は一緒にインストールされていますけど、普通の人はメーカ製PCでもない限りデフォルトで入っていることがなく、自分の作ったプログラムが他所だと動かない〜! という状況をしばしば作るアレです。
ランタイムのインストーラを組み込むのが正攻法なんでしょうけど、大抵の人はよほど重たいプログラムでない限り、ビルド設定を変更してランタイム不要の実行形式を生成しているんじゃないでしょうか。

御託はいいとして、Python自体はそのようにビルドされていない模様。
というわけで、VC++ランタイムが不要なPythonインタプリタのDLLを、自分でビルドすることにします。


まずは、Python公式へ行って、ソースコードの入ったtarボールをダウンロードしてきます。
とりあえずこの記事の時点では、日本語サイトからはPython 3.2.1のソースが手に入るみたいです。

解凍すると何やら沢山出てきますが、今から用事があるのはPCbuild/pcbuild.sln。これがPython全体のビルドを統括するVS2008のソリューションです。
(旧バージョン用のファイルはPCディレクトリにある)

ソリューションを開くと沢山プロジェクトが出てきますが、とりあえずビルドが必要なのは以下の4個。

  • kill_python
  • make_buildinfo
  • make_versioninfo
  • pythoncore

このうちpythoncorePythonのDLLを生成するプロジェクトです。
こいつの設定を変えてやります。

プロジェクトのプロパティ から、
→構成プロパティ
 →C/C++
  →コード生成
   →ランタイム ライブラリ

を見てやると、Debugビルドでは/MDd、その他では/MDになっていると思うので、これを全部/MTd/MTに変更します。
ランタイムを使いたくないVSユーザにはお馴染みの設定ですね(多分)。

しかし、これだけではまだ設定が足りません。もう一つやることがあります。
make_buildinfo.cを開けると、ご親切にも次のようなコードがあるので、

...
if (strcmp(argv[1], "Release") == 0) {
strcat_s(command, CMD_SIZE, "-MD ");
}
else if (strcmp(argv[1], "Debug") == 0) {
strcat_s(command, CMD_SIZE, "-D_DEBUG -MDd ");
}
else if (strcmp(argv[1], "ReleaseItanium") == 0) {
strcat_s(command, CMD_SIZE, "-MD /USECL:MS_ITANIUM ");
}
else if (strcmp(argv[1], "ReleaseAMD64") == 0) {
strcat_s(command, CMD_SIZE, "-MD ");
strcat_s(command, CMD_SIZE, "-MD /USECL:MS_OPTERON ");
}
else {
...

このコードの文字列中の-MDと-MDdを全部-MTと-MTdに修正します
1個だけ別にコンパイルされるファイルがあるみたいですね。これはそいつのコンパイルオプションのようです。

これで準備完了。
pythoncoreを右クリックしてビルドしてやれば、めでたくソリューションと同じディレクトリにDLLが生成されます。
(他の3個は依存関係が設定されているので、pythoncoreよりも前に自動的にビルドされます)

ところで、このとき生成されるDLLは、

  • Debugビルド ... python**_d.dll
  • Releaseビルド ... python**.dll

となっています。
python**_d.dllはインストーラでは付属してこないので、自分のアプリケーションがDebugビルドでもPythonはReleaseビルドのものを使う、というよく分からないことをしていたのですが、おまけでDebugビルド用のDLLも手に入れることができました。



結局のところ、あんまりインストーラに頼るなってことですかね?
これで作業が進みそうです。