“Python/docs/3.9/extending/windows”的版本间差异

来自菜鸟教程
Python/docs/3.9/extending/windows
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:5. 在 Windows 上构建 C 和 C++ 扩展 — Python 文档}}
 
<div id="building-c-and-c-extensions-on-windows" class="section">
 
<div id="building-c-and-c-extensions-on-windows" class="section">
  
 
<span id="building-on-windows"></span>
 
<span id="building-on-windows"></span>
= <span class="section-number">5. </span>Building C and C++ Extensions on Windows =
+
= 5. 在 Windows 上构建 C C++ 扩展 =
  
This chapter briefly explains how to create a Windows extension module for
+
本章简要说明如何使用 Microsoft Visual C++ 为 Python 创建 Windows 扩展模块,然后提供有关其工作原理的更详细的背景信息。 说明材料对学习构建 Python 扩展的 Windows 程序员和有兴趣开发可以在 Unix 和 Windows 上成功构建的软件的 Unix 程序员都很有用。
Python using Microsoft Visual C++, and follows with more detailed background
 
information on how it works. The explanatory material is useful for both the
 
Windows programmer learning to build Python extensions and the Unix programmer
 
interested in producing software which can be successfully built on both Unix
 
and Windows.
 
  
Module authors are encouraged to use the distutils approach for building
+
鼓励模块作者使用 distutils 方法来构建扩展模块,而不是本节中描述的方法。 您仍然需要用于构建 Python 的 C 编译器; 通常是 Microsoft Visual C++
extension modules, instead of the one described in this section. You will still
 
need the C compiler that was used to build Python; typically Microsoft Visual
 
C++.
 
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
This chapter mentions a number of filenames that include an encoded Python
+
本章提到了许多包含编码 Python 版本号的文件名。 这些文件名用显示为 <code>XY</code> 的版本号表示; 实际上,<code>'X'</code> 将是主要版本号,而 <code>'Y'</code> 将是您正在使用的 Python 版本的次要版本号。 例如,如果您使用 Python 2.2.1,<code>XY</code> 实际上将是 <code>22</code>
version number. These filenames are represented with the version number shown
 
as <code>XY</code>; in practice, <code>'X'</code> will be the major version number and <code>'Y'</code>
 
will be the minor version number of the Python release you're working with. For
 
example, if you are using Python 2.2.1, <code>XY</code> will actually be <code>22</code>.
 
  
  
第31行: 第20行:
  
 
<span id="win-cookbook"></span>
 
<span id="win-cookbook"></span>
== <span class="section-number">5.1. </span>A Cookbook Approach ==
+
== 5.1. 食谱方法 ==
  
There are two approaches to building extension modules on Windows, just as there
+
有两种方法可以在 Windows 上构建扩展模块,就像在 Unix 上一样:使用 [[../../library/distutils#module-distutils|distutils]] 包来控制构建过程,或者手动进行。 distutils 方法适用于大多数扩展; 关于使用 [[../../library/distutils#module-distutils|distutils]] 构建和打包扩展模块的文档可在 [[../../distutils/index#distutils-index|Distributing Python Modules (Legacy version)]] 中找到。 如果你发现你真的需要手动做事,研究项目文件可能对你有帮助。 [[#id1|:source:`winsound `]] 标准库模块。
are on Unix: use the [[../../library/distutils#module-distutils|<code>distutils</code>]] package to control the build process, or
 
do things manually. The distutils approach works well for most extensions;
 
documentation on using [[../../library/distutils#module-distutils|<code>distutils</code>]] to build and package extension modules
 
is available in [[../../distutils/index#distutils-index|<span class="std std-ref">Distributing Python Modules (Legacy version)</span>]]. If you find you really need to do
 
things manually, it may be instructive to study the project file for the
 
[https://github.com/python/cpython/tree/3.9/PCbuild/winsound.vcxproj winsound] standard library module.
 
  
  
第46行: 第29行:
  
 
<span id="dynamic-linking"></span>
 
<span id="dynamic-linking"></span>
== <span class="section-number">5.2. </span>Differences Between Unix and Windows ==
+
== 5.2. Unix Windows 之间的差异 ==
  
Unix and Windows use completely different paradigms for run-time loading of
+
Unix Windows 使用完全不同的范例来运行时加载代码。 在尝试构建可以动态加载的模块之前,请注意您的系统是如何工作的。
code. Before you try to build a module that can be dynamically loaded, be aware
 
of how your system works.
 
  
In Unix, a shared object (<code>.so</code>) file contains code to be used by the
+
Unix 中,共享对象 (<code>.so</code>) 文件包含程序要使用的代码,以及它希望在程序中找到的函数和数据的名称。 当文件加入程序时,文件代码中对这些函数和数据的所有引用都将更改为指向程序中函数和数据在内存中放置的实际位置。 这基本上是一个链接操作。
program, and also the names of functions and data that it expects to find in the
 
program. When the file is joined to the program, all references to those
 
functions and data in the file's code are changed to point to the actual
 
locations in the program where the functions and data are placed in memory.
 
This is basically a link operation.
 
  
In Windows, a dynamic-link library (<code>.dll</code>) file has no dangling
+
Windows 中,动态链接库 (<code>.dll</code>) 文件没有悬空引用。 相反,对函数或数据的访问通过查找表。 因此不必在运行时修复 DLL 代码以引用程序的内存; 相反,代码已经使用了 DLL 的查找表,并且在运行时修改了查找表以指向函数和数据。
references. Instead, an access to functions or data goes through a lookup
 
table. So the DLL code does not have to be fixed up at runtime to refer to the
 
program's memory; instead, the code already uses the DLL's lookup table, and the
 
lookup table is modified at runtime to point to the functions and data.
 
  
In Unix, there is only one type of library file (<code>.a</code>) which contains code
+
Unix 中,只有一种类型的库文件 (<code>.a</code>) 包含来自多个目标文件 (<code>.o</code>) 的代码。 在创建共享对象文件 (<code>.so</code>) 的链接步骤期间,链接器可能会发现它不知道在哪里定义了标识符。 链接器将在库的目标文件中寻找它; 如果找到它,它将包含该目标文件中的所有代码。
from several object files (<code>.o</code>). During the link step to create a shared
 
object file (<code>.so</code>), 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
+
Windows 中,有两种类型的库,静态库和导入库(均称为 <code>.lib</code>)。 一个静态库就像一个 Unix <code>.a</code> 文件; 它包含必要时包含的代码。 导入库基本上仅用于向链接器保证某个标识符是合法的,并且会在加载 DLL 时出现在程序中。 因此,链接器使用来自导入库的信息来构建查找表,以使用未包含在 DLL 中的标识符。 链接应用程序或 DLL 时,可能会生成一个导入库,该库将需要用于依赖于应用程序或 DLL 中的符号的所有未来 DLL。
library (both called <code>.lib</code>). A static library is like a Unix <code>.a</code>
 
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
+
假设您正在构建两个动态加载模块 B 和 C,它们应该共享另一个代码块 A。 在 Unix 上,您将 '''' <code>A.a</code> 传递给 <code>B.so</code> <code>C.so</code> 的链接器; 这将导致它被包含两次,因此 B C 将各自拥有自己的副本。 在 Windows 中,构建 <code>A.dll</code> 也会构建 <code>A.lib</code>。 您 ''do'' <code>A.lib</code> 传递给 B C 的链接器。 <code>A.lib</code> 不包含代码; 它只包含将在运行时用于访问 A 代码的信息。
another block of code A. On Unix, you would ''not'' pass <code>A.a</code> to the
 
linker for <code>B.so</code> and <code>C.so</code>; that would cause it to be included
 
twice, so that B and C would each have their own copy. In Windows, building
 
<code>A.dll</code> will also build <code>A.lib</code>. You ''do'' pass <code>A.lib</code> to the
 
linker for B and C. <code>A.lib</code> 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 <code>import spam</code>; it
+
Windows 中,使用导入库有点像使用 <code>import spam</code>; 它使您可以访问垃圾邮件的名称,但不会创建单独的副本。 在 Unix 上,链接库更像是 <code>from spam import *</code>; 它确实创建了一个单独的副本。
gives you access to spam's names, but does not create a separate copy. On Unix,
 
linking with a library is more like <code>from spam import *</code>; it does create a
 
separate copy.
 
  
  
第99行: 第50行:
  
 
<span id="win-dlls"></span>
 
<span id="win-dlls"></span>
== <span class="section-number">5.3. </span>Using DLLs in Practice ==
+
== 5.3. 在实践中使用 DLL ==
  
Windows Python is built in Microsoft Visual C++; using other compilers may or
+
Windows Python 是用 Microsoft Visual C++ 构建的; 使用其他编译器可能会也可能不会(尽管 Borland 似乎可以)。 本节的其余部分是 MSVC++ 特定的。
may not work (though Borland seems to). The rest of this section is MSVC++
 
specific.
 
  
When creating DLLs in Windows, you must pass <code>pythonXY.lib</code> to the linker.
+
Windows 中创建 DLL 时,必须将 <code>pythonXY.lib</code> 传递给链接器。 要构建两个 DLL,垃圾邮件和 ni(使用垃圾邮件中的 C 函数),您可以使用以下命令:
To build two DLLs, spam and ni (which uses C functions found in spam), you could
 
use these commands:
 
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第113行: 第60行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>cl /LD /I/python/include spam.c ../libs/pythonXY.lib
+
<syntaxhighlight lang="c">cl /LD /I/python/include spam.c ../libs/pythonXY.lib
cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib</pre>
+
cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The first command created three files: <code>spam.obj</code>, <code>spam.dll</code> and
+
第一个命令创建了三个文件:<code>spam.obj</code><code>spam.dll</code> <code>spam.lib</code><code>Spam.dll</code> 不包含任何 Python 函数(例如 [[../../c-api/arg#c|PyArg_ParseTuple()]]),但由于 <code>pythonXY.lib</code>,它确实知道如何找到 Python 代码。
<code>spam.lib</code>. <code>Spam.dll</code> does not contain any Python functions (such
 
as [[../../c-api/arg#c|<code>PyArg_ParseTuple()</code>]]), but it does know how to find the Python code
 
thanks to <code>pythonXY.lib</code>.
 
  
The second command created <code>ni.dll</code> (and <code>.obj</code> and <code>.lib</code>),
+
第二个命令创建了 <code>ni.dll</code>(以及 <code>.obj</code> <code>.lib</code>),它知道如何从垃圾邮件以及 Python 可执行文件中找到必要的函数。
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
+
并非每个标识符都导出到查找表。 如果您希望任何其他模块(包括 Python)能够看到您的标识符,您必须说 <code>_declspec(dllexport)</code>,如 <code>void _declspec(dllexport) initspam(void)</code> <code>PyObject _declspec(dllexport) *NiGetSpamData(void)</code>
modules (including Python) to be able to see your identifiers, you have to say
 
<code>_declspec(dllexport)</code>, as in <code>void _declspec(dllexport) initspam(void)</code> or
 
<code>PyObject _declspec(dllexport) *NiGetSpamData(void)</code>.
 
  
Developer Studio will throw in a lot of import libraries that you do not really
+
Developer Studio 会放入很多您并不真正需要的导入库,为您的可执行文件增加大约 100K。 要摆脱它们,请使用“项目设置”对话框的“链接”选项卡,指定 ''忽略默认库'' 。 将正确的 <code>msvcrtxx.lib</code> 添加到库列表中。
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 <code>msvcrtxx.lib</code> to the list of libraries.
 
  
  
第142行: 第78行:
  
 
</div>
 
</div>
 +
<div class="clearer">
  
[[Category:Python 3.9 中文文档]]
+
 
 +
 
 +
</div>
 +
 
 +
[[Category:Python 3.9 文档]]

2021年10月31日 (日) 04:50的最新版本

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

本章简要说明如何使用 Microsoft Visual C++ 为 Python 创建 Windows 扩展模块,然后提供有关其工作原理的更详细的背景信息。 说明材料对学习构建 Python 扩展的 Windows 程序员和有兴趣开发可以在 Unix 和 Windows 上成功构建的软件的 Unix 程序员都很有用。

鼓励模块作者使用 distutils 方法来构建扩展模块,而不是本节中描述的方法。 您仍然需要用于构建 Python 的 C 编译器; 通常是 Microsoft Visual C++。

笔记

本章提到了许多包含编码 Python 版本号的文件名。 这些文件名用显示为 XY 的版本号表示; 实际上,'X' 将是主要版本号,而 'Y' 将是您正在使用的 Python 版本的次要版本号。 例如,如果您使用 Python 2.2.1,XY 实际上将是 22


5.1. 食谱方法

有两种方法可以在 Windows 上构建扩展模块,就像在 Unix 上一样:使用 distutils 包来控制构建过程,或者手动进行。 distutils 方法适用于大多数扩展; 关于使用 distutils 构建和打包扩展模块的文档可在 Distributing Python Modules (Legacy version) 中找到。 如果你发现你真的需要手动做事,研究项目文件可能对你有帮助。 :source:`winsound ` 标准库模块。


5.2. Unix 和 Windows 之间的差异

Unix 和 Windows 使用完全不同的范例来运行时加载代码。 在尝试构建可以动态加载的模块之前,请注意您的系统是如何工作的。

在 Unix 中,共享对象 (.so) 文件包含程序要使用的代码,以及它希望在程序中找到的函数和数据的名称。 当文件加入程序时,文件代码中对这些函数和数据的所有引用都将更改为指向程序中函数和数据在内存中放置的实际位置。 这基本上是一个链接操作。

在 Windows 中,动态链接库 (.dll) 文件没有悬空引用。 相反,对函数或数据的访问通过查找表。 因此不必在运行时修复 DLL 代码以引用程序的内存; 相反,代码已经使用了 DLL 的查找表,并且在运行时修改了查找表以指向函数和数据。

在 Unix 中,只有一种类型的库文件 (.a) 包含来自多个目标文件 (.o) 的代码。 在创建共享对象文件 (.so) 的链接步骤期间,链接器可能会发现它不知道在哪里定义了标识符。 链接器将在库的目标文件中寻找它; 如果找到它,它将包含该目标文件中的所有代码。

在 Windows 中,有两种类型的库,静态库和导入库(均称为 .lib)。 一个静态库就像一个 Unix .a 文件; 它包含必要时包含的代码。 导入库基本上仅用于向链接器保证某个标识符是合法的,并且会在加载 DLL 时出现在程序中。 因此,链接器使用来自导入库的信息来构建查找表,以使用未包含在 DLL 中的标识符。 链接应用程序或 DLL 时,可能会生成一个导入库,该库将需要用于依赖于应用程序或 DLL 中的符号的所有未来 DLL。

假设您正在构建两个动态加载模块 B 和 C,它们应该共享另一个代码块 A。 在 Unix 上,您将 A.a 传递给 B.soC.so 的链接器; 这将导致它被包含两次,因此 B 和 C 将各自拥有自己的副本。 在 Windows 中,构建 A.dll 也会构建 A.lib。 您 doA.lib 传递给 B 和 C 的链接器。 A.lib 不包含代码; 它只包含将在运行时用于访问 A 代码的信息。

在 Windows 中,使用导入库有点像使用 import spam; 它使您可以访问垃圾邮件的名称,但不会创建单独的副本。 在 Unix 上,链接库更像是 from spam import *; 它确实创建了一个单独的副本。


5.3. 在实践中使用 DLL

Windows Python 是用 Microsoft Visual C++ 构建的; 使用其他编译器可能会也可能不会(尽管 Borland 似乎可以)。 本节的其余部分是 MSVC++ 特定的。

在 Windows 中创建 DLL 时,必须将 pythonXY.lib 传递给链接器。 要构建两个 DLL,垃圾邮件和 ni(使用垃圾邮件中的 C 函数),您可以使用以下命令:

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

第一个命令创建了三个文件:spam.objspam.dllspam.libSpam.dll 不包含任何 Python 函数(例如 PyArg_ParseTuple()),但由于 pythonXY.lib,它确实知道如何找到 Python 代码。

第二个命令创建了 ni.dll(以及 .obj.lib),它知道如何从垃圾邮件以及 Python 可执行文件中找到必要的函数。

并非每个标识符都导出到查找表。 如果您希望任何其他模块(包括 Python)能够看到您的标识符,您必须说 _declspec(dllexport),如 void _declspec(dllexport) initspam(void)PyObject _declspec(dllexport) *NiGetSpamData(void)

Developer Studio 会放入很多您并不真正需要的导入库,为您的可执行文件增加大约 100K。 要摆脱它们,请使用“项目设置”对话框的“链接”选项卡,指定 忽略默认库 。 将正确的 msvcrtxx.lib 添加到库列表中。