\chapter{Windows 上での C および \Cpp{} 拡張モジュールのビルド%
     \label{building-on-windows}}


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

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

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


\section{型どおりのアプローチ \label{win-cookbook}}

Windows での拡張モジュールのビルドには、\UNIX{} と同じように、
\ulink{\module{distutils}}{../lib/module-distutils.html} パッケージを使
ったビルド作業の制御と手動の二通りのアプローチがあります。
distutils によるアプローチはほとんどの拡張モジュールで
うまくいきます; \ulink{\module{distutils}}{../lib/module-distutils.html} 
を使った拡張モジュールのビルドとパッケージ化については、
\citetitle[../dist/dist.html]{Python モジュールの配布} に
あります。この節では、C や \Cpp で書かれた Python 拡張モジュール
を手動でビルドするアプローチについて述べます。

以下の説明に従って拡張モジュールをビルドするには、インストールされている
Python と同じバージョンの Python のソースコードを持っていなければ
なりません。また、 Microsoft Visual \Cpp{} ``Developer Studio''
が必要になります; プロジェクトファイルは V\Cpp{} バージョン 7.1
向けのものが提供されていますが、以前のバージョンの V\Cpp も
使えます。Python自体をビルドしたものと同じバージョンの V\Cpp を使わなけ
ればならないことに注意しましょう。
ここで述べる例題のファイルは、Python ソースコードと
共に配布されており、\file{PC\textbackslash example_nt\textbackslash} 
ディレクトリにあります。

\begin{enumerate}
  \item
  \strong{例題ファイルをコピーする}\\
\file{example_nt} ディレクトリは \file{PC} ディレクトリのサブディレクトリ
になっています。これは PC 関連の全てのファイルをソースコード配布物内の
同じディレクトリに置くための措置です。とはいえ実際には、
\file{example_nt} ディレクトリは\file{PC} の下では利用できません。
そこで、まずこのディレクトリを一階層上にコピーして、
\file{example_nt} が \file{PC} および \file{Include} と同じ
階層のディレクトリになるようにします。
以降の作業は、移動先の新しいディレクトリ内で行ってください。

  \item
  \strong{プロジェクトを開く}\\
V\Cpp から、 \menuselection{ファイル \sub ソリューションを開く}
ダイアログメニューを選択します (\menuselection{ファイル \sub 開く}
ではありません!)。ディレクトリ階層を辿って、\file{example_nt}
\emph{をコピーしたディレクトリ} 内の\file{example.sln} を選択
し、「開く」をクリックします。

  \item
  \strong{例題の DLL をビルドする}\\
設定が全て正しく行われているか調べるために、ビルドしてみます:

    \begin{enumerate}
      \item

ビルド構成を選びます。このステップは省略できます。
\menuselection{ビルド \sub 設定マネージャー \sub アクティブなソリューシ
ョンの設定} を選び、\guilabel{リリース} または \guilabel{デバッグ} を選
びます。このステップを飛ばすと、V\Cpp{} はデフォルトでデバッグ構成を使い
ます。

      \item
DLL をビルドします。
\menuselection{ビルド \sub ソリューションのビルド} を選びます。
この操作で。全ての中間ファイルおよび最終ファイルが、上のビルド構成
で選んだ構成に従って\file{Debug} または \file{Release} という名前の
ディレクトリに生成されます。
    \end{enumerate}

  \item
  \strong{デバッグモードの DLL をテストする}\\
デバッグビルドが成功したら、コマンドプロンプトを起動し、
\file{example_nt\textbackslash Debug} ディレクトリに移動して
ください。以下のセッション通りにコマンドを実行できるはずです
(\code{C>} は DOS コマンドのプロンプト、\code{>>>} は
Python のプロンプトです; ビルド情報や様々なデバッグ出力は、
ここに示したスクリーン出力と一致しないこともあるので注意して下さい):

\begin{verbatim}
C>..\..\PCbuild\python_d
Adding parser accelerators ...
Done.
Python 2.2 (#28, Dec 19 2001, 23:26:37) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
>>> import example
[4897 refs]
>>> example.foo()
Hello, world
[4903 refs]
>>>
\end{verbatim}

おめでとうございます! とうとう初めての Python 拡張モジュールのビルド
に成功しましたね。

  \item
  \strong{自分用にプロジェクトを作成する}\\
プロジェクト用のディレクトリを適当な名前で作成してください。
自作の C ソースコードをディレクトリ内にコピーします。
モジュールのソースコードファイル名は必ずしもモジュール名と
一致している必要はありませんが、初期化関数の名前はモジュール名と
一致していなければなりません --- 初期化関数の名前が
\cfunction{initspam()} なら、モジュールは\module{spam} という
名前でしか import できません。\cfunction{initspam()} は
第一引数を \code{"spam"} にして、\cfunction{Py_InitModule()} を
呼び出します (このディレクトリにある、最小限の内容が書かれている
\file{example.c} を手がかりにするとよいでしょう)。
ならわしとして、ファイルは\file{spam.c} または \file{spammodule.c} 
という名前にしておきます。
出力ファイル名はリリースモードでは \file{smap.dll} や \file{spam.pyd}、
デバッグモードでは\file{smap_d.dll} や \file{spam_d.pyd}、になるはず
です (後者は、システムライブラリ \file{spam.dll} と、Python
インタフェースとなる自作のモジュールとの混同を避けるために
推奨されています) 。

さて、やり方は二通りあります:

    \begin{enumerate}
      \item  \file{example.dsw} と \file{example.vcproj} をコピーし、
\file{spam.*} に名前を変えて、手作業で編集する
      \item  新しくプロジェクトを作成する; 説明は下にあります。
    \end{enumerate}

どちらの場合も、\file{example_nt\textbackslash example.def} を
\file{spam\textbackslash spam.def} にコピーして、新たにできた
\file{spam.def} を編集し、二行目に `\code{initspam}' が入るように
します。
自分で新たなプロジェクトを作成したのなら、ここで \file{spam.def} を
プロジェクトに追加しておいてください (このファイルはたった二行しか
ない目障りなファイルです。\file{.def} ファイルを全く無視するという
方法もあり、それには \programopt{/exprt:initspam} を
「プロジェクトのプロパティ」ダイアログにあるリンク設定のどこかに
手動で追加します)。

  \item
  \strong{新しくプロジェクトを作成する}\\
\menuselection{ファイル \sub 新規作成 \sub プロジェクト} ダイアログ
を使って、新たなプロジェクト用ワークスペースを作成します。
\guilabel{Visual C++ プロジェクト/Win32/Win32 プロジェクト} を選択し、名
前(\samp{spam}) を入れ、「場所」が先ほど作成した \file{spam} ディレクト
リの親ディレクトリに (Python ビルドツリーの直下のサブディレクトリで、
\file{Include} および \file{PC} と同じディレクトリになるはずです) あるこ
とを確かめます。「作成」をクリックします。

TODO
    You should now create the file \file{spam.def} as instructed in
    the previous section. Add the source files to the project, using
    \menuselection{Project \sub Add Existing Item}. Set the pattern to
    \code{*.*} and select both \file{spam.c} and \file{spam.def} and
    click OK.  (Inserting them one by one is fine too.)

\menuselection{プロジェクト \sub spam のプロパティ} ダイアログを開きます。
ほんのいくつかですが、設定の変更が必要です。\guilabel{構成} ドロップダウ
ンリストに \guilabel{すべての構成} が設定されているか確かめてください。
C/\Cpp{} タブを選び、ポップアップメニューから「一般」カテゴリを選びます。
以下のテキスト:

\begin{verbatim}
..\Include,..\PC
\end{verbatim}

を、\guilabel{追加のインクルードディレクトリ} とラベルされた
エントリボックスに入力します

次に、「リンカ」タブの「一般」カテゴリを選び、

\begin{verbatim}
..\PCbuild
\end{verbatim}

を \guilabel{追加のライブラリディレクトリ} と書かれたテキストボックスに
入力します。

さて、構成ごとに特有の設定をいくつか行う必要があります:

「構成」 ドロップダウンリストから、\guilabel{リリース} を
選んでください。「リンク」タブをクリックし、「入力」カテゴリを
選んで、「追加の依存ファイル」ボックス内のリストに\code{pythonXY.lib} 
を追加します。

「構成」 ドロップダウンリストから、\guilabel{デバッグ} に切り替え、
「追加の依存ファイル」ボックス内のリストに\code{pythonXY_d.lib} 
を追加します。
次に C/\Cpp{} タブをクリックして、 \guilabel{コード生成} をカテゴリから
選び、 \guilabel{ラインタイムライブラリ} に対して 
\guilabel{マルチスレッド デバッグ DLL} を選びます。

「構成」ドロップダウンリストから \guilabel{リリース} に切り替えなおし
ます。 \guilabel{ラインタイムライブラリ} に対して
\guilabel{マルチスレッド DLL} を選びます。

前の節で述べた\file{spam.def} をここで作成しておかねばなりません。
その後、\menuselection{追加 \sub ファイルをプロジェクトに追加} 
ダイアログを選びます。「ファイルの種類」を \code{*.*} にして、
\file{spam.c} と \file{spam.def} を選び、 OK をクリックします
(一つ一つファイルを追加してもかまいません)。
\end{enumerate}


作っているモジュールが新たな型を作成するのなら、
以下の行:

\begin{verbatim}
    PyObject_HEAD_INIT(&PyType_Type)
\end{verbatim}

がうまくいかないはずです。そこで:

\begin{verbatim}
    PyObject_HEAD_INIT(NULL)
\end{verbatim}

に変更してください。また、以下の行をモジュール初期化関数に加えます:

\begin{verbatim}
    MyObject_Type.ob_type = &PyType_Type;
\end{verbatim}

この操作を行う詳しい理由は、
\citetitle[http://www.python.org/doc/FAQ.html]{Python FAQ} の
第 3 節を参照してください。


\section{\UNIX{} と Windows の相違点}
\label{dynamic-linking}
\sectionauthor{Chris Phoenix}{cphoenix@best.com}


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

\UNIX{} では、共有オブジェクト (\file{.so}) ファイルにプログラムが
使うコード、そしてプログラム内で使う関数名やデータが入っています。
ファイルがプログラムに結合されると、これらの関数やデータに
対するファイルのコード内の全ての参照は、メモリ内で関数やデータが
配置されている、プログラム中の実際の場所を指すように変更されます。
これは基本的にはリンク操作にあたります。

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

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

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

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

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


\section{DLL 使用の実際 \label{win-dlls}}
\sectionauthor{Chris Phoenix}{cphoenix@best.com}

Windows 版の Python は Microsoft Visual \Cpp でビルドされています; 
他のコンパイラを使うと、うまく動作したり、しなかったりします
(Borland も一見うまく動作しません)。この節の残りの部分は MSV\Cpp{}
向けの説明です。

Windows で DLL を作成する際は、\file{pythonXY.lib} をリンカに
渡さねばなりません。 例えば二つの DLL 、spam と ni (spam の中には
C 関数が入っているとします) をビルドするには、以下のコマンドを
実行します:

\begin{verbatim}
cl /LD /I/python/include spam.c ../libs/pythonXY.lib
cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib
\end{verbatim}

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

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

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

Developer Studio は必要もなく大量のインポートライブラリを DLL に
突っ込んで、実行形式のサイズを 100K も大きくしてしまいます。
不用なライブラリを追い出したければ、「プロジェクトのプロパティ」
ダイアログを選び、「リンカ」タブに移動して、
\emph{インポートライブラリの無視} を指定します。その後、
適切な\file{msvcrt\var{xx}.lib} をライブラリのリストに追加してください。
