5. 在 Windows 上构建 C 和 C++ 扩展
**********************************

这一章简要介绍了如何使用 Microsoft Visual C++ 创建 Python 的 Windows
扩展模块，然后再提供有关其工作机理的详细背景信息。 这些说明材料同时适
用于 Windows 程序员学习构建 Python 扩展以及 Unix 程序员学习如何生成在
Unix 和 Windows 上均能成功构建的软件。

鼓励模块作者使用 distutils 方式来构建扩展模块，而不使用本节所描述的方
式。 你仍将需要使用 C 编译器来构建 Python；通常为 Microsoft Visual C++
。

備註:

  这一章提及了多个包括已编码 Python 版本号的文件名。 这些文件名以显示
  为 "XY" 的版本号来代表；在实践中，"'X'" 将为你所使用的 Python 发布版
  的主版本号而 "'Y'" 将为次版本号。 例如，如果你所使用的是 Python
  2.2.1，"XY" 将为 "22"。


5.1. 菜谱式说明
===============

在 Windows 和 Unix 上构建扩展模块都有两种方式：使用 "distutils" 包来控
制构建过程，或者全手动操作。 distutils 方式适用于大多数扩展；使用
"distutils" 构建和打包扩展模块的文档见 發布 Python 模組（舊版）。 如果
你发现你确实需要手动操作，那么研究一下 winsound 标准库模块的项目文件可
能会很有帮助。


5.2. Unix 和 Windows 之间的差异
===============================

Unix 和 Windows 对于代码的运行时加载使用了完全不同的范式。 在你尝试构
建可动态加载的模块之前，要先了解你所用系统是如何工作的。

在 Unix 中，一个共享对象 (".so") 文件中包含将由程序来使用的代码，也包
含在程序中可被找到的函数名称和数据。 当文件被合并到程序中时，对在文件
代码中这些函数和数据的全部引用都会被改为指向程序中函数和数据在内存中所
放置的实际位置。 这基本上是一个链接操作。

在 Windows 中，一个动态链接库 (".dll") 文件中没有悬挂的引用。 而是通过
一个查找表执行对函数或数据的访问。 因此在运行时 DLL 代码不必在运行时进
行修改；相反地，代码已经使用了 DLL 的查找表，并且在运行时查找表会被修
改以指向特定的函数和数据。

In Unix, there is only one type of library file (".a") which contains
code from several object files (".o").  During the link step to create
a shared object file (".so"), the linker may find that it doesn't know
where an identifier is defined.  The linker will look for it in the
object files in the libraries; if it finds it, it will include all the
code from that object file.

In Windows, there are two types of library, a static library and an
import library (both called ".lib").  A static library is like a Unix
".a" file; it contains code to be included as necessary. An import
library is basically used only to reassure the linker that a certain
identifier is legal, and will be present in the program when the DLL
is loaded.  So the linker uses the information from the import library
to build the lookup table for using identifiers that are not included
in the DLL.  When an application or a DLL is linked, an import library
may be generated, which will need to be used for all future DLLs that
depend on the symbols in the application or DLL.

Suppose you are building two dynamic-load modules, B and C, which
should share another block of code A.  On Unix, you would *not* pass
"A.a" to the linker for "B.so" and "C.so"; that would cause it to be
included twice, so that B and C would each have their own copy.  In
Windows, building "A.dll" will also build "A.lib".  You *do* pass
"A.lib" to the linker for B and C.  "A.lib" does not contain code; it
just contains information which will be used at runtime to access A's
code.

In Windows, using an import library is sort of like using "import
spam"; it gives you access to spam's names, but does not create a
separate copy.  On Unix, linking with a library is more like "from
spam import *"; it does create a separate copy.


5.3. DLL 的实际使用
===================

Windows Python is built in Microsoft Visual C++; using other compilers
may or may not work (though Borland seems to).  The rest of this
section is MSVC++ specific.

When creating DLLs in Windows, you must pass "pythonXY.lib" to the
linker. To build two DLLs, spam and ni (which uses C functions found
in spam), you could use these commands:

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

The first command created three files: "spam.obj", "spam.dll" and
"spam.lib".  "Spam.dll" does not contain any Python functions (such as
"PyArg_ParseTuple()"), but it does know how to find the Python code
thanks to "pythonXY.lib".

The second command created "ni.dll" (and ".obj" and ".lib"), which
knows how to find the necessary functions from spam, and also from the
Python executable.

Not every identifier is exported to the lookup table.  If you want any
other modules (including Python) to be able to see your identifiers,
you have to say "_declspec(dllexport)", as in "void
_declspec(dllexport) initspam(void)" or "PyObject _declspec(dllexport)
*NiGetSpamData(void)".

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 "msvcrtxx.lib" to the list of
libraries.
