Windows 上での C および C++ 拡張モジュールのビルド
**************************************************

この章では Windows 向けの Python 拡張モジュールを Microsoft Visual C++
を使って作成する方法について簡単に述べ、その後に拡張モジュールのビルド
がどのように動作するのかについて詳しい背景を述べます。この説明は、
Python 拡張モジュールを作成する Windows プログラマと、Unix と Windows
の双方でうまくビルドできるようなソフトウェアの作成に興味がある Unix プ
ログラマの双方にとって有用です。

モジュールの作者には、この節で説明している方法よりも、distutils による
アプローチで拡張モジュールをビルドするよう勧めます。また、Python をビ
ルドした際に使われた C コンパイラが必要です; 通常は Microsoft Visual
C++です。

注釈:

  この章では、Python のバージョン番号が符号化されて入っているたくさん
  のファイル名について触れます。これらのファイル名は "XY" で表されるバ
  ージョン名付きで表現されます; "'X'" は使っている Python リリースのメ
  ジャーバージョン番号、"'Y'" はマイナーバージョン番号です。例えば、
  Python 2.2.1 を使っているなら、"XY" は実際には "22" になります。


型どおりのアプローチ
====================

Unix と同様、Windows で拡張モジュールをビルドする方法には、
"setuptools" パッケージでビルドを制御する方法と、手動で行う方法の 2 つ
があります。 ほとんどの拡張では setuptools が適しています。
"setuptools" による拡張モジュールのビルドとパッケージ化の説明は、
setuptools による C および C++ 拡張のビルド にあります。 手動で行う必
要がある場合は、標準ライブラリの winsound モジュールのプロジェクトファ
イルを調べると参考になるでしょう。


Unix と Windows の相違点
========================

Unix と Windows では、コードの実行時読み込みに全く異なるパラダイムを用
いています。動的ロードされるようなモジュールをビルドしようとする前に、
自分のシステムがどのように動作するか知っておいてください。

Unix の共有オブジェクト (".so") ファイルには、プログラムが使うコードに
加え、プログラム内に存在すると想定する関数やデータの名前が含まれていま
す。 ファイルをプログラムに組み込むと、ファイル内のコードからそれらの
関数やデータへの参照は、メモリ上の実際の配置先を指すように変更されます
。 これは基本的にリンク操作です。

Windows では、動的リンクライブラリ (".dll") ファイルにはぶら下がり参照
(dangling reference) はありません。その代わり、関数やデータへのアクセ
スはルックアップテーブルを介します。従って DLL コードの場合、実行時に
ポインタがプログラムメモリ上の正しい場所を指すように修正する必要はあり
ません; その代わり、コードは常に DLL のルックアップテーブルを使い、ル
ックアップテーブル自体は実行時に実際の関数やデータを指すように修正され
ます。

Unix には、唯一のライブラリファイル形式 (".a") しかありません。 ".a"
ファイルには複数のオブジェクトファイル (".o") 由来のコードが入っていま
す。共有オブジェクトファイル (".so") を作成するリンク処理の段階中に、
リンカは定義場所の不明な識別子に遭遇することがあります。このときリンカ
はライブラリ内のオブジェクトファイルを検索します; もし識別子が見つかる
と、リンカはそのオブジェクトファイルから全てのコードを取り込みます。

Windows では、二つの形式のライブラリ、静的ライブラリとインポートライブ
ラリがあります (どちらも ".lib" と呼ばれています)。静的ライブラリは
Unix における ".a" ファイルに似ています; このファイルには、必要に応じ
て取り込まれるようなコードが入っています。インポートライブラリは、基本
的には特定の識別子が不正ではなく、 DLL がロードされた時点で存在するこ
とを保証するためにだけ使われます。リンカはインポートライブラリからの情
報を使ってルックアップテーブルを作成し、DLL に入っていない識別子を使え
るようにします。アプリケーションや DLL がリンクされるさい、インポート
ライブラリが生成されることがあります。このライブラリは、アプリケーショ
ンや DLL 内のシンボルに依存するような、将来作成される全ての DLL で使う
ために必要になります。

二つの動的ロードモジュール、B と C を作成し、別のコードブロック A を共
有するとします。Unix では、 "A.a" を "B.so" や "C.so"  をビルドすると
きのリンカに渡したりは *しません* ; そんなことをすれば、コードは二度取
り込まれ、B と C のそれぞれが自分用のコピーを持ってしまいます。
Windows では、 "A.dll" をビルドすると "A.lib" もビルドされます。 B や
C のリンクには "A.lib" を渡します。 "A.lib" にはコードは入っていません
; 単に A のコードにアクセスするするために実行時に用いられる情報が入っ
ているだけです。

Windows ではインポートライブラリの使用は "import spam" とするようなも
のです; この操作によって spam の名前にアクセスできますが、コードのコピ
ーを個別に作成したりはしません。Unix では、ライブラリとのリンクはむし
ろ "from spam import *" に似ています;  この操作では個別にコードのコピ
ーを生成します。

Py_NO_LINK_LIB

   CPython のヘッダーファイル内で行われる、"#pragma" による Python ラ
   イブラリへの暗黙のリンクを無効にします。

   Added in version 3.14.


DLL 使用の実際
==============

Windows 版 Python は Microsoft Visual C++ でビルドされています。 ほか
のコンパイラで動作するかどうかは分かりません。 この節の残りは、MSVC++
固有の説明です。

Windows で DLL を作成する場合、CPython のライブラリを使う方法は 2 つあ
ります。

1. デフォルトでは、"PC/pyconfig.h" を直接、または "Python.h" を通じて
   インクルードすると、設定に応じたライブラリが暗黙にリンクされます。
   ヘッダーファイルは、Debug では "pythonXY_d.lib"、Release では
   "pythonXY.lib"、Limited API を有効にした Release では "pythonX.lib"
   を選びます。

   spam と、spam 内の C 関数を使う ni という 2 つの DLL をビルドするに
   は、次のコマンドを使えます。

      cl /LD /I/python/include spam.c
      cl /LD /I/python/include ni.c spam.lib

   最初のコマンドは、"spam.obj"、"spam.dll"、"spam.lib" の 3 つのファ
   イルを作成します。 "Spam.dll" には "PyArg_ParseTuple()" などの
   Python の関数は含まれていませんが、暗黙にリンクされた
   "pythonXY.lib" によって Python のコードを見つけられます。

   二つ目のコマンドでは、 "ni.dll" (および ".obj" と ".lib") ができ、
   このライブラリは spam と Python 実行形式中の必要な関数をどうやって
   見つければよいか知っています。

2. "Python.h" をインクルードする前に "Py_NO_LINK_LIB" マクロを定義し、
   手動でリンクします。 リンカーに "pythonXY.lib" を渡さなければなりま
   せん。

   spam と、spam 内の C 関数を使う ni という 2 つの DLL をビルドするに
   は、次のコマンドを使えます。

      cl /LD /DPy_NO_LINK_LIB /I/python/include spam.c ../libs/pythonXY.lib
      cl /LD /DPy_NO_LINK_LIB /I/python/include ni.c spam.lib ../libs/pythonXY.lib

   最初のコマンドで、三つのファイル: "spam.obj" 、 "spam.dll"  および
   "spam.lib" ができます。 "Spam.dll" には ("PyArg_ParseTuple()" のよ
   うな) Python 関数は全く入っていませんが、 "pythonXY.lib" のおかげで
   Python コードを見つけることはできます。

   二つ目のコマンドでは、 "ni.dll" (および ".obj" と ".lib") ができ、
   このライブラリは spam と Python 実行形式中の必要な関数をどうやって
   見つければよいか知っています。

全ての識別子がルックアップテーブル上に公開されるわけではありません。他
のモジュール (Python 自体を含みます) から、自作の識別子が見えるように
するには、"void _declspec(dllexport) initspam(void)" や "PyObject
_declspec(dllexport) *NiGetSpamData(void)" のように、
"_declspec(dllexport)" で宣言せねばなりません。

Developer Studio will throw in a lot of import libraries that you do
not really need, adding about 100K to your executable.  To get rid of
them, use the Project Settings dialog, Link tab, to specify *ignore
default libraries*.  Add the correct "msvcrt*xx*.lib" to the list of
libraries.
