构建“基于ctypes”的模型带有 distutils 的 C 库
按照此建议,我编写了一个本机C扩展库通过 ctypes 优化 Python 模块的一部分。我选择 ctypes 而不是编写 CPython 原生库,因为它更快、更容易(只有几个函数,里面有所有紧密的循环)。
我现在遇到了障碍。如果我希望使用 distutils 使用 python setup.py install 轻松安装我的工作,那么 distutils 需要能够构建我的共享库并将其安装(大概到 /usr/lib/ 我的项目)。然而,这不是一个 Python 扩展模块,据我所知,distutils 无法做到这一点。
我发现了一些对其他遇到此问题的人的参考:
我知道我可以做一些本机的事情,而不是使用 distutils 作为共享库,或者确实使用我的发行版的打包系统。我担心这会限制可用性,因为并不是每个人都能轻松安装它。
所以我的问题是:当前使用 distutils 分发共享库的最佳方法是什么,该共享库将由 ctypes 使用,但否则是操作系统本机的,而不是 Python 扩展模块?
如果您可以扩展它并证明为什么这是最好的方法,请随意回答上面链接的黑客之一。如果没有更好的办法,至少所有的信息都会集中在一处。
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).
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.
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?
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
distutils 文档此处指出:
因此,关于普通共享库的唯一区别似乎是初始化函数(除了合理的文件命名约定之外,我认为您没有任何问题)。现在,如果您查看
distutils.command.build_ext
,您将看到它定义了一个get_export_symbols()
方法:因此,将它用于普通共享库应该是开箱即用的,除了在
视窗。但解决这个问题也很容易。
get_export_symbols()
的返回值被传递给distutils.ccompiler.CCompiler.link()
,该文档指出:因此,不将初始化函数添加到导出符号即可解决问题。为此,您只需要简单地重写
build_ext.get_export_symbols()
即可。另外,您可能想简化模块名称。下面是一个
build_ext
子类的完整示例,它可以构建 ctypes 模块以及扩展模块:The distutils documentation here states that:
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 aget_export_symbols()
method that: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 todistutils.ccompiler.CCompiler.link()
, which documentation states: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()
.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:我在这里设置了一个带有 ctypes 扩展的最小工作 python 包:
https://github.com/himbeles/ctypes-example
适用于 Windows、Mac、Linux。
build_ext.get_export_symbols()
并强制库扩展对于所有操作系统都相同 (.so
)。I have setup a minimal working python package with ctypes extension here:
https://github.com/himbeles/ctypes-example
which works on Windows, Mac, Linux.
build_ext.get_export_symbols()
and forcing the library extension to be the same (.so
) for all operating systems.到 2024 年,
distutils
将被弃用,但这个问题仍然与其直接后继者setuptools
相关。setuptools
中的setup
命令有一个选项libraries
用于构建非扩展模块的库。此选项旨在仅构建扩展模块依赖项所需的库(静态链接,不作为库文件包含在二进制发行版中)。但是,可以更改相应的 setuptools 命令类以生成共享库(可通过 ctypes 加载)并将其包含在二进制发行版中。这是setup.py中的相关代码:在
setup
调用中,cmdclass
参数用于覆盖默认的build_clib
代码>命令。libraries
参数声明需要构建的所有库。在 Linux 上,这将生成一个libalgorithm.so
,它与第一个源文件位于同一目录中。In 2024,
distutils
is deprecated, but the question is still relevant for its direct successorsetuptools
. Thesetup
command insetuptools
has an optionlibraries
to build libraries which are not extension modules. This option is designed to only build libraries which are needed as a dependency for extension modules (statically linked and not included as library file in binary distributions). However, the corresponding setuptools command class can be changed to produce shared libraries (which are loadable byctypes
) and include them in binary distributions. This is the relevant code insetup.py
:In the
setup
call thecmdclass
parameter is used to override the defaultbuild_clib
command. Thelibraries
parameter declares all libraries that need to be built. On Linux, this would produce alibalgorithm.so
which is located in the the same directory as the first source file.这里有一些澄清:
它不是一个“基于 ctypes”的库。它只是一个标准的 C 库,你想用 distutils 安装它。如果您使用 C 扩展、ctypes 或 cython 来包装该库,则与问题无关。
由于该库显然不是通用的,而只是包含针对您的应用程序的优化,因此您链接到的建议不适用于您,在您的情况下,编写 C 扩展或使用 Cython 可能更容易,在这种情况下,您的问题就可以避免。
对于实际问题,您始终可以使用自己的自定义 distutils 命令,事实上,与此类命令相关的讨论之一是 OOF2
build_shlib
命令,它可以满足您的需求。在这种情况下,虽然您想要安装一个实际上不共享的自定义库,但我认为您不需要将其安装在 /usr/lib/yourproject 中,但您可以将其安装到 /usr 中的包目录中/lib/python-xx/site-packages/yourmodule,以及您的 python 文件。但我不是 100% 确定,所以你必须尝试一下。Some clarifications here:
It's not a "ctypes based" library. It's just a standard C library, and you want to install it with distutils. If you use a C-extension, ctypes or cython to wrap that library is irrelevant for the question.
Since the library apparently isn't generic, but just contains optimizations for your application, the recommendation you link to doesn't apply to you, in your case it is probably easier to write a C-extension or to use Cython, in which case your problem is avoided.
For the actual question, you can always use your own custom distutils command, and in fact one of the discussions linked to just such a command, the OOF2
build_shlib
command, that does what you want. In this case though you want to install a custom library that really isn't shared, and then I think you don't need to install it in /usr/lib/yourproject, but you can install it into the package directory in /usr/lib/python-x.x/site-packages/yourmodule, together with your python files. But I'm not 100% sure of that so you'll have to try.