构建基于ctypes的“基于”带有distutils的C库 [英] Building a ctypes-"based" C library with distutils

查看:85
本文介绍了构建基于ctypes的“基于”带有distutils的C库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

按照此建议,我已经写了本机C扩展库,可通过ctypes优化Python模块的一部分。我选择ctypes而不是编写CPython本地库,因为它更快,更容易(仅包含几个函数,内部紧密循环)。

Following this recommendation, I have written a native C extension library to optimise part of a Python module via ctypes. I chose ctypes over writing a CPython-native library because it was quicker and easier (just a few functions with all tight loops inside).

我现在遇到了麻烦。如果我想使用distutils使用 python setup.py install 轻松安装我的工作,则distutils需要能够构建我的共享库并将其安装(大概是 / usr / lib / myproject )。但是,这不是Python扩展模块,据我所知distutils无法做到这一点。

I've now hit a snag. If I want my work to be easily installable using distutils using python setup.py install, then distutils needs to be able to build my shared library and install it (presumably into /usr/lib/myproject). However, this not a Python extension module, and so as far as I can tell, distutils cannot do this.

我找到了一些其他人的参考资料这个问题:

I've found a few references to people other people with this problem:

  • Someone on numpy-discussion with a hack back in 2006.
  • Somebody asking on distutils-sig and not getting an answer.
  • Somebody asking on the main python list and being pointed to the innards of an existing project.

我知道我可以做一些本机操作,而不是将distutils用于共享库,或者确实使用我分销的包装系统。我担心的是,这将限制可用性,因为不是每个人都可以轻松安装它。

I am aware that I can do something native and not use distutils for the shared library, or indeed use my distribution's packaging system. My concern is that this will limit usability as not everyone will be able to install it easily.

所以我的问题是:当前分发共享库的最佳方法是什么?

So my question is: what is the current best way of distributing a shared library with distutils that will be used by ctypes but otherwise is OS-native and not a Python extension module?

如果要使用distutils,它将被ctypes使用,但是不是OS原生的,而是Python扩展模块?

Feel free to answer with one of the hacks linked to above if you can expand on it and justify why that is the best way. If there is nothing better, at least all the information will be in one place.

推荐答案

distutils文档此处指出:

The distutils documentation here states that:


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

A C extension for CPython is a shared library (e.g. a .so file on Linux, .pyd on Windows), which exports an initialization function.

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

So the only difference regarding a plain shared library seems to be the initialization function (besides a sensible file naming convention I don't think you have any problem with). Now, if you take a look at distutils.command.build_ext you will see it defines a get_export_symbols() method that:


返回共享扩展必须导出的符号列表。这要么使用 ext.export_symbols,要么使用 PyInit _ + module_name(如果未提供)。只有在Windows中,.pyd文件(DLL)必须导出模块 PyInit_函数时才相关。

Return the list of symbols that a shared extension has to export. This either uses 'ext.export_symbols' or, if it's not provided, "PyInit_" + module_name. Only relevant on Windows, where the .pyd file (DLL) must export the module "PyInit_" function.

因此将其用于纯文本共享库应该开箱即用,但在
Windows中除外。但是也很容易解决。 get_export_symbols()的返回值传递给 distutils.ccompiler.CCompiler.link(),该文档指出:

So using it for plain shared libraries should work out-of-the-box except in Windows. But it's easy to also fix that. The return value of get_export_symbols() is passed to distutils.ccompiler.CCompiler.link(), which documentation states:


'export_symbols'是共享库将导出的符号列表。 (这似乎只在Windows上才有意义。)

'export_symbols' is a list of symbols that the shared library will export. (This appears to be relevant only on Windows.)

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

So not adding the initialization function to the export symbols will do the trick. For that you just need to trivially override build_ext.get_export_symbols().

此外,您可能希望简化模块名称。以下是 build_ext 子类的完整示例,该子类可以构建ctypes模块以及扩展模块:

Also, you might want to simplify the module name. Here is a complete example of a build_ext subclass that can build ctypes modules as well as extension modules:

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})

这篇关于构建基于ctypes的“基于”带有distutils的C库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆