使用distutils构建基于ctypes的C库

31

按照这个建议,我已经编写了一个本地的C扩展库,通过ctypes优化Python模块的一部分。 我选择使用ctypes而不是编写一个CPython本地库,因为它更快、更容易(只需几个带有所有紧密循环的函数)。

现在我遇到了一个问题。如果我想让我的工作可以轻松安装使用distutils使用python setup.py install,那么distutils需要能够构建并安装我的共享库(可能会安装到/usr/lib/myproject)。然而,这不是Python扩展模块,所以据我所知,distutils无法做到这一点。

我发现有一些人也遇到了这个问题:

我知道我可以使用本地方法而不是使用distutils来处理共享库,或者使用我的发行版打包系统。 但我担心这将限制可用性,因为不是每个人都能轻松安装它。

因此,我的问题是:使用distutils分发一个共享库的当前最佳方法是什么,该共享库将由ctypes使用,但是并不是Python扩展模块?

如果您能扩展并说明其中的一个hack,并证明它是最佳方法,请随意回答。如果没有更好的方法,至少所有信息都会在一个地方。

3个回答

6
distutils文档 这里 指出:

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

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

返回共享扩展必须导出的符号列表。 这要么使用“ext.export_symbols”,要么(如果未提供)使用“PyInit_”+ module_name。 仅在Windows上相关,因为.pyd文件(DLL)必须导出模块“PyInit_”函数。

因此,对于普通的共享库,除了Windows之外,应该可以直接使用。但是解决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})

1
由于setuptools已经过时,我该如何实现这个功能? - chmike

3

我已经在这里用ctypes扩展设置了一个最小的Python包,链接如下: https://github.com/himbeles/ctypes-example 它可以在Windows、Mac和Linux上工作。

  • 该方法采用了上述 memeplex 的方法,覆盖了 build_ext.get_export_symbols() 并强制所有操作系统使用相同的库扩展名 (.so)。
  • 此外,c / c++ 源代码中的编译器指令确保在 Windows 和 Unix 上正确导出共享库符号。
  • 额外加分的是,二进制轮廓图会自动由 GitHub Action 编译出适用于所有操作系统的版本 :-)

-2

这里有一些澄清:

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

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

对于实际问题,你可以始终使用自己的自定义distutils命令,实际上,其中一个链接到的讨论就是这样一条命令,OOF2 build_shlib 命令,它可以执行你想要的操作。但在这种情况下,你想要安装一个真正不共享的自定义库,然后我认为你不需要将其安装在 /usr/lib/yourproject 中,而是可以将其与Python文件一起安装到 /usr/lib/python-x.x/site-packages/yourmodule 的包目录中。但我不能百分之百确定,所以你需要尝试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接