静态链接Python,但仍支持外部.pyd模块

时间:2016-12-13 18:19:16

标签: python c++ windows visual-c++ dll

我正在寻找将Python与我的应用程序静态链接。原因是因为在某些测试案例中我看到了10%的速度提升。我的应用程序大量使用Python C-API,似乎整个程序优化能够做一些很好的优化。我希望Profile Guided Optimizations也会获得更多。这一切都在MSVC2015中完成

到目前为止,我已经将pythoncore项目(python35.dll)重新编译为静态库,并将其与我的应用程序(我们称之为myapp.exe)相关联。除了将项目类型更改为静态之外,唯一需要做的是在静态lib编译期间和编译myapp.exe时设置定义Py_NO_ENABLE_SHARED。这很好,这就是我能够获得10%速度改进测试结果的方法。

所以下一步是继续支持具有.pyd文件的外部python模块(.dll文件重命名为.pyd)。这些模块将被编译为期望与python35.dll动态链接,因此我需要为该要求提供一种解决方法,因为所有python函数现在都嵌入到myapp.exe中。

首先,我使用.def文件从myapp.exe导出所有公共Python函数。这很好。

缺少的部分是如何创建python35.dll,它将所有调用重定向到从myapp.exe导出的函数。

我的第一次尝试是使用DLL转发。我制作了一个自定义的python35.dll,它有一个.def文件,其中包含以下行:

PyArg_Parse=myapp.PyArg_Parse

从理论上讲,这是有效的。如果我在socket.pyd上使用Dependency Walker,它会正确打开我的python35.dll并显示所有调用都被转发到myapp.exe。

但是,当实际运行myapp.exe并尝试导入套接字时,它无法从myapp.exe加载所需的入口点。 Python中的“import socket”将导致LoadLibrary(“socket.pyd”)发生。这将隐式加载我的自定义python35.dll。尝试加载python35.dll时发生故障,它无法找到它前进的入口点。这似乎是因为myapp.exe不会成为库搜索路径的一部分。我似乎能够通过将myapp.exe复制到myapp.dll来验证这一点。如果我这样做,那么python35.dll加载工作,但这不是一个解决方案,因为这将导致2个Python环境副本(一个在myapp.exe中,一个在myapp.dll中)

我可能已经研究过可能的其他途径但未找到适合的解决方案:

  • 以某种方式将.exe文件作为库搜索路径的一部分

  • 使用Windows清单/配置以某种方式重定向库

  • 手动使用declspec(裸)和jmp语句来更明确地包装.dll。我在x64工作,所以我认为不再可能了吗?

  • 我可以手动执行整个Python API并手动包装每个函数。如果我能找到一种方法来创建所有导出的函数定义,这是可行的,因此这不是一个疯狂的手工工作量。

总之,有没有办法将.dll的调用重定向/转发到从.exe导出的函数/数据。谢谢!

1 个答案:

答案 0 :(得分:0)

我最终选择了@martineau在评论中建议的解决方案,即将我的所有应用程序(包括Python)放入单个.dll而不是.exe。然后.exe只是一个调用.dll的简单文件而没有其他任何操作。