使用distutils构建一个基于ctypes的"基础"C库

Rob*_*sak 23 python ctypes distutils

按照这个建议,我编写了一个本机C扩展库,通过ctypes优化Python模块的一部分.我之所以选择ctypes而不是编写CPython本地库,是因为它更快更容易(只有几个函数内部都有紧密的循环).

我现在遇到了障碍.如果我希望使用distutils可以轻松地安装我的工作python setup.py install,那么distutils需要能够构建我的共享库并安装它(可能是).但是,这不是一个Python扩展模块,所以据我所知,distutils不能这样做./usr/lib/myproject

我发现了一些对其他人有这个问题的引用:

我知道我可以做一些原生的东西而不是为共享库使用distutils,或者确实使用我的发行版的包装系统.我担心的是,这会限制可用性,因为不是每个人都能轻松安装它.

所以我的问题是:当前最好的分发共享库的方法是什么,这些方法将由ctypes使用,但是其他方面是OS本机而不是Python扩展模块?

如果您可以对其进行扩展并证明为什么这是最好的方法,请随意回答上面链接的其中一个黑客.如果没有更好的东西,至少所有的信息都会在一个地方.

mem*_*lex 6

distutils 文档此处指出:

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

因此,关于普通共享库的唯一区别似乎是初始化函数(除了合理的文件命名约定之外,我认为您没有任何问题)。现在,如果你看一下,distutils.command.build_ext你会发现它定义了一个get_export_symbols()方法:

返回共享扩展必须导出的符号列表。这可以使用“ext.export_symbols”,或者如果未提供,则使用“PyInit_”+ module_name。仅与 Windows 相关,其中 .pyd 文件 (DLL) 必须导出模块“PyInit_”函数。

因此,将它用于普通共享库应该是开箱即用的,除了 Windows 之外。但解决这个问题也很容易。的返回值get_export_symbols()被传递给distutils.ccompiler.CCompiler.link(),文档指出:

“export_symbols”是共享库将导出的符号列表。(这似乎仅在 Windows 上相关。)

因此,不将初始化函数添加到导出符号即可解决问题。为此,您只需要简单地覆盖build_ext.get_export_symbols().

另外,您可能想简化模块名称。build_ext下面是一个可以构建 ctypes 模块以及扩展模块的子类的完整示例:

from distutils.core import setup, Extension
from distutils.command.build_ext import build_ext


class build_ext(build_ext):

    def build_extension(self, ext):
        self._ctypes = isinstance(ext, CTypes)
        return super().build_extension(ext)

    def get_export_symbols(self, ext):
        if self._ctypes:
            return ext.export_symbols
        return super().get_export_symbols(ext)

    def get_ext_filename(self, ext_name):
        if self._ctypes:
            return ext_name + '.so'
        return super().get_ext_filename(ext_name)


class CTypes(Extension): pass


setup(name='testct', version='1.0',
      ext_modules=[CTypes('ct', sources=['testct/ct.c']),
                   Extension('ext', sources=['testct/ext.c'])],
      cmdclass={'build_ext': build_ext})
Run Code Online (Sandbox Code Playgroud)


Len*_*bro -2

这里有一些澄清:

  1. 它不是一个“基于 ctypes”的库。它只是一个标准的 C 库,你想用 distutils 安装它。如果您使用 C 扩展、ctypes 或 cython 来包装该库,则与问题无关。

  2. 由于该库显然不是通用的,而只是包含针对您的应用程序的优化,因此您链接到的建议不适用于您,在您的情况下,编写 C 扩展或使用 Cython 可能更容易,在这种情况下你的问题就被避免了。

对于实际问题,您始终可以使用自己的自定义 distutils 命令,事实上,讨论之一就是链接到这样一个命令,即OOF2 build_shlib命令,它可以完成您想要的操作。在这种情况下,虽然您想要安装一个实际上不共享的自定义库,但我认为您不需要将其安装在 /usr/lib/yourproject 中,但您可以将其安装到 /usr 中的包目录中/lib/python-xx/site-packages/yourmodule,以及您的 python 文件。但我不是 100% 确定,所以你必须尝试一下。