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

来自菜鸟教程
Python/docs/3.9/extending/building
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:4. 构建 C 和 C++ 扩展 — Python 文档}}
 
<div id="building-c-and-c-extensions" class="section">
 
<div id="building-c-and-c-extensions" class="section">
  
 
<span id="building"></span>
 
<span id="building"></span>
= <span class="section-number">4. </span>Building C and C++ Extensions =
+
= 4. 构建 C C++ 扩展 =
  
A C extension for CPython is a shared library (e.g. a <code>.so</code> file on Linux,
+
CPython 的 AC 扩展是一个共享库(例如 Linux 上的 <code>.so</code> 文件,Windows 上的 <code>.pyd</code>),它导出 ''初始化函数''
<code>.pyd</code> on Windows), which exports an ''initialization function''.
 
  
To be importable, the shared library must be available on <span id="index-0" class="target"></span>[[../../using/cmdline#envvar-PYTHONPATH|<code>PYTHONPATH</code>]],
+
为了可导入,共享库必须在 <span id="index-0" class="target"></span>[[../../using/cmdline#envvar-PYTHONPATH|PYTHONPATH]] 上可用,并且必须以模块名称命名,并带有适当的扩展名。 使用 distutils 时,会自动生成正确的文件名。
and must be named after the module name, with an appropriate extension.
 
When using distutils, the correct filename is generated automatically.
 
  
The initialization function has the signature:
+
初始化函数具有签名:
 +
 
 +
; [[../../c-api/structures#c|<span class="n"><span class="pre">PyObject</span></span>]]<span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="sig-name descname"><span class="n"><span class="pre">PyInit_modulename</span></span></span><span class="sig-paren">(</span><span class="kt"><span class="pre">void</span></span><span class="sig-paren">)</span><br />
  
; [[../../c-api/structures#c|PyObject]] *<code>PyInit_modulename</code><span class="sig-paren">(</span>void<span class="sig-paren">)</span>
 
 
:  
 
:  
  
It returns either a fully-initialized module, or a [[../../c-api/module#c|<code>PyModuleDef</code>]]
+
它返回一个完全初始化的模块,或者一个 [[../../c-api/module#c|PyModuleDef]] 实例。 有关详细信息,请参阅 [[../../c-api/module#initializing-modules|初始化 C 模块]]
instance. See [[../../c-api/module#initializing-modules|<span class="std std-ref">Initializing C modules</span>]] for details.
 
  
For modules with ASCII-only names, the function must be named
+
对于只有 ASCII 名称的模块,函数必须命名为 <code>PyInit_&lt;modulename&gt;</code>,用模块名称替换 <code>&lt;modulename&gt;</code>。 使用 [[../../c-api/module#multi-phase-initialization|多阶段初始化]] 时,允许使用非 ASCII 模块名称。 在这种情况下,初始化函数名称是 <code>PyInitU_&lt;modulename&gt;</code>,其中 <code>&lt;modulename&gt;</code> 使用 Python ''punycode'' 编码,连字符替换为下划线。 在 Python 中:
<code>PyInit_&lt;modulename&gt;</code>, with <code>&lt;modulename&gt;</code> replaced by the name of the
 
module. When using [[../../c-api/module#multi-phase-initialization|<span class="std std-ref">Multi-phase initialization</span>]], non-ASCII module names
 
are allowed. In this case, the initialization function name is
 
<code>PyInitU_&lt;modulename&gt;</code>, with <code>&lt;modulename&gt;</code> encoded using Python's
 
''punycode'' encoding with hyphens replaced by underscores. In Python:
 
  
 
<div class="highlight-python notranslate">
 
<div class="highlight-python notranslate">
第30行: 第23行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def initfunc_name(name):
+
<syntaxhighlight lang="python">def initfunc_name(name):
 
     try:
 
     try:
 
         suffix = b'_' + name.encode('ascii')
 
         suffix = b'_' + name.encode('ascii')
 
     except UnicodeEncodeError:
 
     except UnicodeEncodeError:
 
         suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
 
         suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
     return b'PyInit' + suffix</pre>
+
     return b'PyInit' + suffix</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
It is possible to export multiple modules from a single shared library by
+
通过定义多个初始化函数,可以从单个共享库中导出多个模块。 但是,导入它们需要使用符号链接或自定义导入器,因为默认情况下只能找到与文件名对应的函数。 有关详细信息,请参阅 <span id="index-1" class="target"></span>[https://www.python.org/dev/peps/pep-0489 PEP 489] 中的 ''“一个库中的多个模块”'' 部分。
defining multiple initialization functions. However, importing them requires
 
using symbolic links or a custom importer, because by default only the
 
function corresponding to the filename is found.
 
See the ''&quot;Multiple modules in one library&quot;'' section in <span id="index-1" class="target"></span>[https://www.python.org/dev/peps/pep-0489 '''PEP 489'''] for details.
 
  
 
<div id="building-c-and-c-extensions-with-distutils" class="section">
 
<div id="building-c-and-c-extensions-with-distutils" class="section">
  
== <span class="section-number">4.1. </span>Building C and C++ Extensions with distutils ==
+
== 4.1. 使用 distutils 构建 C C++ 扩展 ==
  
Extension modules can be built using distutils, which is included in Python.
+
可以使用 Python 中包含的 distutils 构建扩展模块。 由于 distutils 也支持创建二进制包,用户不一定需要编译器和 distutils 来安装扩展。
Since distutils also supports creation of binary packages, users don't
 
necessarily need a compiler and distutils to install the extension.
 
  
A distutils package contains a driver script, <code>setup.py</code>. This is a plain
+
distutils 包包含一个驱动程序脚本,<code>setup.py</code>。 这是一个普通的 Python 文件,在最简单的情况下,它可能如下所示:
Python file, which, in the most simple case, could look like this:
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第61行: 第47行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from distutils.core import setup, Extension
+
<syntaxhighlight lang="python3">from distutils.core import setup, Extension
  
 
module1 = Extension('demo',
 
module1 = Extension('demo',
第69行: 第55行:
 
       version = '1.0',
 
       version = '1.0',
 
       description = 'This is a demo package',
 
       description = 'This is a demo package',
       ext_modules = [module1])</pre>
+
       ext_modules = [module1])</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
With this <code>setup.py</code>, and a file <code>demo.c</code>, running
+
有了这个 <code>setup.py</code> 和一个文件 <code>demo.c</code>,运行
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第80行: 第66行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>python setup.py build</pre>
+
<syntaxhighlight lang="c">python setup.py build</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
will compile <code>demo.c</code>, and produce an extension module named <code>demo</code> in
+
将编译 <code>demo.c</code>,并在 <code>build</code> 目录中生成名为 <code>demo</code> 的扩展模块。 根据系统的不同,模块文件将在子目录 <code>build/lib.system</code> 中结束,并且可能具有类似 <code>demo.so</code> <code>demo.pyd</code> 的名称。
the <code>build</code> directory. Depending on the system, the module file will end
 
up in a subdirectory <code>build/lib.system</code>, and may have a name like
 
<code>demo.so</code> or <code>demo.pyd</code>.
 
  
In the <code>setup.py</code>, all execution is performed by calling the <code>setup</code>
+
<code>setup.py</code>中,所有的执行都是通过调用<code>setup</code>函数来完成的。 这需要可变数量的关键字参数,上面的示例仅使用其中的一个子集。 具体来说,该示例指定了构建包的元信息,并指定了包的内容。 通常,一个包会包含额外的模块,比如 Python 源模块、文档、子包等。 请参考 [[../../distutils/index#distutils-index|Distributing Python Modules (Legacy version)]] 中的 distutils 文档,了解更多关于 distutils 的特性; 本节仅解释构建扩展模块。
function. This takes a variable number of keyword arguments, of which the
 
example above uses only a subset. Specifically, the example specifies
 
meta-information to build packages, and it specifies the contents of the
 
package. Normally, a package will contain additional modules, like Python
 
source modules, documentation, subpackages, etc. Please refer to the distutils
 
documentation in [[../../distutils/index#distutils-index|<span class="std std-ref">Distributing Python Modules (Legacy version)</span>]] to learn more about the features of
 
distutils; this section explains building extension modules only.
 
  
It is common to pre-compute arguments to <code>setup()</code>, to better structure the
+
通常预先计算 <code>setup()</code> 的参数,以更好地构建驱动程序脚本。 在上面的例子中,[[../../distutils/apiref#distutils.core|setup()]] 的 <code>ext_modules</code> 参数是一个扩展模块列表,每个模块都是 <code>Extension</code> 的一个实例。 在示例中,该实例定义了一个名为 <code>demo</code> 的扩展名,它是通过编译单个源文件 <code>demo.c</code> 来构建的。
driver script. In the example above, the <code>ext_modules</code> argument to
 
[[../../distutils/apiref#distutils.core|<code>setup()</code>]] is a list of extension modules, each of which is
 
an instance of
 
the <code>Extension</code>. In the example, the instance
 
defines an extension named <code>demo</code> which is build by compiling a single source
 
file, <code>demo.c</code>.
 
  
In many cases, building an extension is more complex, since additional
+
在许多情况下,构建扩展更为复杂,因为可能需要额外的预处理器定义和库。 这在下面的示例中进行了演示。
preprocessor defines and libraries may be needed. This is demonstrated in the
 
example below.
 
  
 
<div class="highlight-python3 notranslate">
 
<div class="highlight-python3 notranslate">
第115行: 第83行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from distutils.core import setup, Extension
+
<syntaxhighlight lang="python3">from distutils.core import setup, Extension
  
 
module1 = Extension('demo',
 
module1 = Extension('demo',
第134行: 第102行:
 
This is really just a demo package.
 
This is really just a demo package.
 
''',
 
''',
       ext_modules = [module1])</pre>
+
       ext_modules = [module1])</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In this example, [[../../distutils/apiref#distutils.core|<code>setup()</code>]] is called with additional
+
在这个例子中,[[../../distutils/apiref#distutils.core|setup()]] 被调用时带有额外的元信息,推荐在必须构建分发包时使用。 对于扩展本身,它指定了预处理器定义、包含目录、库目录和库。 根据编译器的不同,distutils 以不同的方式将此信息传递给编译器。 例如,在 Unix 上,这可能会导致编译命令
meta-information, which
 
is recommended when distribution packages have to be built. For the extension
 
itself, it specifies preprocessor defines, include directories, library
 
directories, and libraries. Depending on the compiler, distutils passes this
 
information in different ways to the compiler. For example, on Unix, this may
 
result in the compilation commands
 
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第151行: 第113行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o
+
<syntaxhighlight lang="c">gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o
  
gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so</pre>
+
gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
These lines are for demonstration purposes only; distutils users should trust
+
这些线路仅用于演示目的; distutils 用户应该相信 distutils 会正确调用。
that distutils gets the invocations right.
 
  
  
第166行: 第127行:
  
 
<span id="distributing"></span>
 
<span id="distributing"></span>
== <span class="section-number">4.2. </span>Distributing your extension modules ==
+
== 4.2. 分发扩展模块 ==
  
When an extension has been successfully built, there are three ways to use it.
+
成功构建扩展后,可以通过三种方式使用它。
  
End-users will typically want to install the module, they do so by running
+
最终用户通常希望安装该模块,他们通过运行
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第176行: 第137行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>python setup.py install</pre>
+
<syntaxhighlight lang="c">python setup.py install</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Module maintainers should produce source packages; to do so, they run
+
模块维护者应该制作源码包; 为此,他们运行
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第187行: 第148行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>python setup.py sdist</pre>
+
<syntaxhighlight lang="c">python setup.py sdist</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In some cases, additional files need to be included in a source distribution;
+
在某些情况下,源代码分发中需要包含其他文件; 这是通过 <code>MANIFEST.in</code> 文件完成的; 有关详细信息,请参阅 [[../../distutils/sourcedist#manifest|指定要分发的文件]]
this is done through a <code>MANIFEST.in</code> file; see [[../../distutils/sourcedist#manifest|<span class="std std-ref">Specifying the files to distribute</span>]] for details.
 
  
If the source distribution has been built successfully, maintainers can also
+
如果源分发已成功构建,维护人员还可以创建二进制分发。 根据平台,可以使用以下命令之一来执行此操作。
create binary distributions. Depending on the platform, one of the following
 
commands can be used to do so.
 
  
 
<div class="highlight-c notranslate">
 
<div class="highlight-c notranslate">
第203行: 第161行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>python setup.py bdist_wininst
+
<syntaxhighlight lang="c">python setup.py bdist_wininst
 
python setup.py bdist_rpm
 
python setup.py bdist_rpm
python setup.py bdist_dumb</pre>
+
python setup.py bdist_dumb</syntaxhighlight>
  
 
</div>
 
</div>
第212行: 第170行:
  
 
</div>
 
</div>
 +
 +
</div>
 +
<div class="clearer">
 +
 +
  
 
</div>
 
</div>
  
[[Category:Python 3.9 中文文档]]
+
[[Category:Python 3.9 文档]]

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

4. 构建 C 和 C++ 扩展

CPython 的 AC 扩展是一个共享库(例如 Linux 上的 .so 文件,Windows 上的 .pyd),它导出 初始化函数

为了可导入,共享库必须在 PYTHONPATH 上可用,并且必须以模块名称命名,并带有适当的扩展名。 使用 distutils 时,会自动生成正确的文件名。

初始化函数具有签名:

PyObject *PyInit_modulename(void)

它返回一个完全初始化的模块,或者一个 PyModuleDef 实例。 有关详细信息,请参阅 初始化 C 模块

对于只有 ASCII 名称的模块,函数必须命名为 PyInit_<modulename>,用模块名称替换 <modulename>。 使用 多阶段初始化 时,允许使用非 ASCII 模块名称。 在这种情况下,初始化函数名称是 PyInitU_<modulename>,其中 <modulename> 使用 Python 的 punycode 编码,连字符替换为下划线。 在 Python 中:

def initfunc_name(name):
    try:
        suffix = b'_' + name.encode('ascii')
    except UnicodeEncodeError:
        suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
    return b'PyInit' + suffix

通过定义多个初始化函数,可以从单个共享库中导出多个模块。 但是,导入它们需要使用符号链接或自定义导入器,因为默认情况下只能找到与文件名对应的函数。 有关详细信息,请参阅 PEP 489 中的 “一个库中的多个模块” 部分。

4.1. 使用 distutils 构建 C 和 C++ 扩展

可以使用 Python 中包含的 distutils 构建扩展模块。 由于 distutils 也支持创建二进制包,用户不一定需要编译器和 distutils 来安装扩展。

distutils 包包含一个驱动程序脚本,setup.py。 这是一个普通的 Python 文件,在最简单的情况下,它可能如下所示:

from distutils.core import setup, Extension

module1 = Extension('demo',
                    sources = ['demo.c'])

setup (name = 'PackageName',
       version = '1.0',
       description = 'This is a demo package',
       ext_modules = [module1])

有了这个 setup.py 和一个文件 demo.c,运行

python setup.py build

将编译 demo.c,并在 build 目录中生成名为 demo 的扩展模块。 根据系统的不同,模块文件将在子目录 build/lib.system 中结束,并且可能具有类似 demo.sodemo.pyd 的名称。

setup.py中,所有的执行都是通过调用setup函数来完成的。 这需要可变数量的关键字参数,上面的示例仅使用其中的一个子集。 具体来说,该示例指定了构建包的元信息,并指定了包的内容。 通常,一个包会包含额外的模块,比如 Python 源模块、文档、子包等。 请参考 Distributing Python Modules (Legacy version) 中的 distutils 文档,了解更多关于 distutils 的特性; 本节仅解释构建扩展模块。

通常预先计算 setup() 的参数,以更好地构建驱动程序脚本。 在上面的例子中,setup()ext_modules 参数是一个扩展模块列表,每个模块都是 Extension 的一个实例。 在示例中,该实例定义了一个名为 demo 的扩展名,它是通过编译单个源文件 demo.c 来构建的。

在许多情况下,构建扩展更为复杂,因为可能需要额外的预处理器定义和库。 这在下面的示例中进行了演示。

from distutils.core import setup, Extension

module1 = Extension('demo',
                    define_macros = [('MAJOR_VERSION', '1'),
                                     ('MINOR_VERSION', '0')],
                    include_dirs = ['/usr/local/include'],
                    libraries = ['tcl83'],
                    library_dirs = ['/usr/local/lib'],
                    sources = ['demo.c'])

setup (name = 'PackageName',
       version = '1.0',
       description = 'This is a demo package',
       author = 'Martin v. Loewis',
       author_email = 'martin@v.loewis.de',
       url = 'https://docs.python.org/extending/building',
       long_description = '''
This is really just a demo package.
''',
       ext_modules = [module1])

在这个例子中,setup() 被调用时带有额外的元信息,推荐在必须构建分发包时使用。 对于扩展本身,它指定了预处理器定义、包含目录、库目录和库。 根据编译器的不同,distutils 以不同的方式将此信息传递给编译器。 例如,在 Unix 上,这可能会导致编译命令

gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o

gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so

这些线路仅用于演示目的; distutils 用户应该相信 distutils 会正确调用。


4.2. 分发扩展模块

成功构建扩展后,可以通过三种方式使用它。

最终用户通常希望安装该模块,他们通过运行

python setup.py install

模块维护者应该制作源码包; 为此,他们运行

python setup.py sdist

在某些情况下,源代码分发中需要包含其他文件; 这是通过 MANIFEST.in 文件完成的; 有关详细信息,请参阅 指定要分发的文件

如果源分发已成功构建,维护人员还可以创建二进制分发。 根据平台,可以使用以下命令之一来执行此操作。

python setup.py bdist_wininst
python setup.py bdist_rpm
python setup.py bdist_dumb