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

静态链接Python,但仍支持外部.pyd模块,python,c++,windows,visual-c++,dll,Python,C++,Windows,Visual C++,Dll,我正在研究如何将Python与我的应用程序静态链接。这是因为在一些测试用例中,我看到速度提高了10%。我的应用程序大量使用PythonC-API,整个程序优化似乎能够进行一些很好的优化。我希望配置文件引导的优化也能获得更多。这一切都是在MSVC2015中完成的 到目前为止,我已经将pythoncore项目(python35.dll)重新编译到一个静态库中,并将其与我的应用程序链接(我们称之为myapp.exe)。仅供参考,除了将项目类型更改为静态外,唯一需要做的其他事情是在静态库编译期间以及在编

我正在研究如何将Python与我的应用程序静态链接。这是因为在一些测试用例中,我看到速度提高了10%。我的应用程序大量使用PythonC-API,整个程序优化似乎能够进行一些很好的优化。我希望配置文件引导的优化也能获得更多。这一切都是在MSVC2015中完成的

到目前为止,我已经将pythoncore项目(python35.dll)重新编译到一个静态库中,并将其与我的应用程序链接(我们称之为myapp.exe)。仅供参考,除了将项目类型更改为静态外,唯一需要做的其他事情是在静态库编译期间以及在编译myapp.exe时设置define Py_NO_ENABLE_SHARED。这很好,这就是我如何获得10%速度提升测试结果的原因

因此,下一步是继续支持具有.pyd文件(重命名为.pyd的.dll文件)的外部python模块。这些模块将被编译,以期望与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中的“导入套接字”将导致出现LoadLibrary(“socket.pyd”)。这将隐式加载我的自定义python35.dll。尝试加载python35.dll时发生故障,无法找到其转发的入口点。这似乎是因为myapp.exe不会成为库搜索路径的一部分。我似乎能够通过将myapp.exe复制到myapp.dll来验证这一点。如果我这样做,那么python35.dll加载就可以工作,但是这不是一个解决方案,因为这将导致Python环境的两个副本(一个在myapp.exe中,一个在myapp.dll中)

我也研究了其他可能的途径,但没有找到正确的解决方案:

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

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

  • 手动使用declspec(裸)和jmp语句更显式地包装.dll。我在x64工作,所以我不认为这是可能的了

  • 我可以手动完成整个Python API并手动包装每个函数。如果我能找到一种方法来创建所有导出的函数定义,那么这是可行的,这样就不会需要大量的手工工作


总之,有没有一种方法可以将对.dll的调用重定向/转发到从.exe导出的函数/数据。谢谢

我最终采用了@martineau在评论中建议的解决方案,即将包括Python在内的所有应用程序放在一个.dll中,而不是一个.exe中。那么.exe只是一个简单的文件,它调用.dll而不做其他任何事情。

你难道不能创建一个不同的
myapp.exe
,它(也)使用
python35.dll
实现大部分功能(基本上是旧的重命名的
myapp.exe
)?有趣,你是说将所有python和myapp的所有功能合并到python35.dll中,对吗?是的,这似乎会奏效。。。谢谢你的主意!不过,我想知道是否有更正式的方式来做这件事……是的,这是我建议的解决办法。至于“形式化”的方法,也许有一种方法可以使Python解释器的版本更加“静态”,所有内置模块都静态链接到它,然后您可以构建并利用它(假设它仍然能够动态导入/加载其他未链接的模块)。