简体   繁体   English

动态链接Python扩展(.pyd)到另一个扩展

[英]Dynamically Linking Python Extension (.pyd) to Another Extension

Python Extension modules are just dynamic libraries, so I assume it's possible to dynamically link a Python extension to another. Python扩展模块只是动态库,因此我假设可以将Python扩展动态链接到另一个。 The problem is on Windows Python Extensions are are given the .pyd extension instead of .dll , so I can't get distutils to link to them when I run the setup script. 问题是在Windows上,Python Extensions被赋予.pyd扩展名而不是.dll ,所以当我运行安装脚本时,我无法让distutils链接到它们。 (I don't think this is a problem on UNIX because Python extensions use the .so file extension.) (我不认为这是UNIX上的问题,因为Python扩展使用.so文件扩展名。)

Assume I have an extension bar.pyd which needs to link to foo.pyd . 假设我有一个扩展名bar.pyd ,需要链接到foo.pyd Basically, what I did in the setup script was: 基本上,我在安装脚本中所做的是:

from distutils.core import setup, Extension

foo = Extension("foo", sources=["foo.c"])
bar = Extension("bar", libraries=["foo"], sources=["bar.c"])
setup(ext_modules=[foo, bar])

So far this isn't working. 到目前为止,这是行不通的。 Is this even possible? 这甚至可能吗? I assume it is, but I haven't been able to find anything online. 我认为是,但我无法在网上找到任何东西。 I'm using MinGW on Windows, but I would like this to work with different MSVC++ and on other systems as well. 我在Windows上使用MinGW,但我希望这可以使用不同的MSVC ++以及其他系统。

Edit: Previously, I solved this problem by passing the object file ( foo.o ) created when foo was compiled to the extra_objects option in the extension (this would only work if I defined prototypes of all foo symbols in bar ): 编辑:以前,我通过将编译foo时创建的目标文件( foo.o )传递给扩展中的extra_objects选项解决了这个问题(这只有在我在bar定义所有foo符号的原型时才有效):

bar = Extension("bar", sources=["bar.c"], extra_objects=["build/.../foo.o"]

This didn't seem to be the right solution, but it worked. 这似乎不是正确的解决方案,但它确实有效。 I don't understand dynamic linking that well, so this may be the right way to do it. 我不明白动态链接,所以这可能是正确的方法。 It feels very wrong, though. 但是感觉非常错误。

Then, I tried passing some explicit arguments to gcc to make it compile an import library: 然后,我尝试将一些显式参数传递给gcc,以使其编译导入库:

foo = Extension("foo", sources=["foo.c"], extra_compile_args=["-Wl,--out-implib,foo.lib,--export-all-symbols"])

And then I linked bar to the new import library: 然后我将bar链接到新的导入库:

bar = Extension("bar", libraries=["foo"], sources=["bar.c"])

This compiled without complaint, but there were some issues with some of the symbols (specifically, I had a few global PyTypeObject s in foo that seemed to be redefined in bar . I need the PyTypeObject s in both modules refer to the same definition.). 这个编译没有抱怨,但是有一些符号存在一些问题(具体来说,我在foo中有一些全局PyTypeObject似乎在bar重新定义。我需要两个模块中的PyTypeObject引用相同的定义。) 。

Edit 2: So, I singled out the problem. 编辑2:所以,我挑出了问题。 Function symbols were exporting correctly after I built and linked against the import libraries, but the PyTypeObject s were getting redeclared. 在我构建并链接到导入库之后,函数符号正确导出,但PyTypeObject正在重新声明。 Assume there was a PyTypeOject Foo_Type in foo . 假设foo有一个PyTypeOject Foo_Type I declared it in foo.h , which was included in both foo.c and bar.c : 我在foo.h声明了它,它包含在foo.cbar.c

PyTypeObject Foo_Type;

I took that out, and put this near the top of foo.c : 我拿出来,把它放在foo.c的顶部附近:

PyTypeObject __declspec(dllexport) Foo_Type;

and this near the top of bar.c : 这靠近bar.c的顶部:

PyTypeObject __declspec(dllimport) Foo_Type;

That fixed the problem. 这解决了问题。 I could then use Foo_Type in both foo and bar and it referred to the same definition of Foo_Type. 然后我可以在foobar使用Foo_Type,它引用了与Foo_Type相同的定义。 The problem is, this isn't going to work on non-Windows systems. 问题是,这不适用于非Windows系统。 I assume if I just take the __declspec s out, it'll work fine on other systems. 我假设如果我只是把__declspec拿出来,它在其他系统上工作正常。

If you're using the normal Python import mechanisms then there's no need to link against the other extension. 如果您使用的是普通的Python 导入机制,则无需链接其他扩展。 If you're calling functions within the other extension, presumably because you have gotten a hold on the header file, then you'll need to generate an import lib from the DLL before you can link against it. 如果您在另一个扩展中调用函数,可能是因为您已经保留了头文件,那么您需要先从DLL生成一个导入库,然后才能链接它。

from distutils.core import Extension as cExtension
from pyd.support import setup, Extension

module1 = Extension("x", sources = ['xclass.c'])
module2 = Extension("y", sources = ['hello.d'], build_deimos=True)

setup(
    name = "x",
    version = '1.0',
    description = "eat a taco",
    ext_modules = [
        module1,
        module2
    ]
);

from : http://pyd.readthedocs.io/en/latest/distutils.html 来自: http//pyd.readthedocs.io/en/latest/distutils.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM