我正在尝试编写一个embeddedPython的软件插件。 在Windows上,插件在技术上是一个DLL(这可能是相关的)。 Python Windows FAQ说:
1. 不要直接将Python构build到您的.exe文件中。 在Windows上,Python必须是一个DLL来处理导入本身就是DLL的模块。 (这是第一个关键的无证事实。)而是,链接到pythonNN.dll; 它通常安装在C:\ Windows \ System中。 NN是Python版本,如Python 2.3中的“23”。
我的问题是为什么Python必须是DLL? 如果在我的情况下,主机应用程序不是一个.exe,但也是一个DLL,我可以build立Python到它? 或者,也许,这个说明意味着第三方C扩展依靠pythonN.N.dll
存在,而其他的DLL不会呢? 假设我真的想要一个DLL,我该怎么办?
我看到有dynload_win.c
文件,它似乎是在Windows上导入C扩展的模块,并且据我所见,它扫描扩展文件以find它导入的pythonX.X.dll
; 但我没有经验的Windows,我不太了解所有的代码。
您需要链接到pythonXY.dll
作为DLL,而不是直接将相关代码链接到您的可执行文件中,否则Python运行时无法加载其他 DLL(它依赖的扩展模块)。如果您创建了自己的DLL理论上可以直接链接该DLL中的所有Python代码,因为它不会在可执行文件中结束,而是仍在DLL中。 你必须小心地做正确的链接,但是,几乎没有标准的工具(如distutils)会为你做这个。
但是,不管你如何嵌入Python,你只能使用DLL,也不能只使用任何DLL。 Python版本之间的ABI有所不同,所以如果你使用Python 2.6编译你的代码,你需要python26.dll
; 你不能使用python25.dll
或python27.dll
。 而Python不只是一个DLL; 它也需要它的标准库,其中包括扩展模块(这些扩展模块本身就是DLL,尽管它们具有.pyd
扩展名) dynload_win.c
的代码是用于加载这些 DLL,并且与加载pythonXY.dll
。
简而言之,为了将Python嵌入到您的插件中,您需要将Python与插件一起发布,或者要求已经安装了正确的Python版本。
在* nix上,进程中的所有共享对象(包括可执行文件)将其导出的名称贡献到公共池中; 任何共享对象都可以从池中提取任何名称并按照他们的喜好使用它们。 这允许例如cStringIO.so
在Python库静态链接时从主可执行文件中提取相关的Python库函数。
在Windows上,每个共享对象都有自己独立的可用名称池。 这意味着它必须读取它所需要的相关不同的共享对象。 由于从主可执行文件中获取所有名字需要花费大量的工作,所以Python函数被分离到它们自己的DLL中。
(对不起,我做了一个愚蠢的事情,我先写了这个问题,然后注册了,现在我不能修改它或者对这个回复发表评论,因为StackOverflow的引擎不认为我是作者,我甚至不能正确地感谢那些谁回答:(所以这实际上是对问题和意见的更新。)
感谢所有的建议,这是非常有价值的。 据我了解,我可以将Python静态链接到一个自定义的DLL,只要我自己编译其他动态加载的扩展,并将它们链接到同一个DLL。 (我知道我也需要发布标准库;我的计划是将一个压缩的归档文件附加到DLL文件中,据我所知,我甚至可以从中导入纯Python模块。)
我还在dynload_win.c
找到了一个有趣的地方。 (我知道它加载使用Python C API的动态扩展,例如_ctypes
)。据我所见,它不仅查找init_ctypes
符号或任何扩展名,而且还扫描.pyd
文件的导入表寻找(正则表达式) python\d+\.
然后将找到的符号与已知的pythonNN.
进行比较pythonNN.
字符串来确保扩展是为这个版本的Python编译的。 如果导入表没有这样的符号,或者引用了另一个版本,则会引发错误。
对我来说这意味着:
pythonNN.dll
链接起来,并尝试从包含一个静态链接的Python的自定义DLL中加载它,它将通过检查,但是 – 在这里,我不确定:会因为没有pythonNN.dll
而失败pythonNN.dll
(即使在检查之前)或者它会愉快地加载符号? 我想我可以改写这个作品来满足我的需要…还有其他的地方,我想知道。
Python需要是一个dll(具有标准名称),以便您的应用程序和插件可以使用相同的python实例。
插件DLL已经预计将加载(和使用python)python26.dll(或任何版本) – 如果您的Python是静态嵌入到您的EXE,那么两个不同的Python库实例将管理相同的数据结构。
如果python库根本不使用静态变量,并且编译设置完全相同 ,这应该不成问题。 但是,通常只要确保只使用了一个python解释器的实例就安全得多。