如何将 Python 包编译为 dll
Posted
技术标签:
【中文标题】如何将 Python 包编译为 dll【英文标题】:How to compile a Python package to a dll 【发布时间】:2012-06-07 05:33:10 【问题描述】:嗯,我有一个 Python 包。在以易于导入的方式分发之前,我需要将其编译为 dll。 如何?您可以建议*.pyc
。但我在某处读到任何*.pyc
都可以轻松反编译!
更新: 遵循这些: 1)我写了一个python包 2) 想要分发它 3) 不想分发源 4) *.pyc 是可反编译的>>源码可以提取! 5)dll是标准的
【问题讨论】:
所有 .pyc 都是编译为字节码的 python 脚本,因此它可以更快地加载到解释器中。它不是可执行文件。为什么需要python包“编译为dll”? 问题中已经给出了你所有的答案!与 *.pyc 相比,dll 不能反编译为源代码,对吧? 【参考方案1】:在 Cython 中写入你想要隐藏的所有内容,并将其编译为 pyd
。这与制作已编译的 python 代码一样接近。
另外,dll 不是标准,在 Python 世界中也不是。它们也不便携。
【讨论】:
你知道,我有一个用 Python 编写的模块。如果我在另一个脚本中导入它,将会有一个 *.pyc。所以这很简单,但是人们可以将 *.pyc 转换为我不想让他们使用的源代码。在 Cython 中重写模块应该不是一件容易的事,对吗?顺便说一句,在 Windows 中 dll 是严格的标准,我的客户端只使用 Windows。 你知道如何使用 Python 中的 dll 吗? 棘手的问题!我知道那里有困难。哦,我的天哪,我只需要不提供源代码。怎么做!?我知道 *.pyc 刚刚准备好导入,不用头疼。我可以想象现在成为一个 dll 会有多么困难。 使用 py2exe 之类的东西不会使逆向工程比仅仅发送一个 .pyc 文件更难 但是 dll 在 Windows 世界中是标准的。【参考方案2】:您可以embed python inside C。真正的技巧是在 C 值和 Python 值之间进行转换。但是,一旦你完成了这些,创建一个 DLL 就是pretty straightforward。
但是,为什么需要制作 dll?你需要在非 python 程序中使用它吗?
【讨论】:
在问题中给出:1) dll 是可移植的,2) 没有分发源代码。 这个想法,第一部分看起来不太容易。是否有任何应用程序可以自动嵌入我的 Python 模块并为我提供可导入的 dll? “可导入”dll 是什么意思?从哪里进口? C++? Python? INTERCAL? 感谢您的链接。有趣的!我问了完全相同的问题。这里有 118 个赞成票 -3!真是有趣的世界。【参考方案3】:现在有一个简单的解决方案:使用 Nuitka 编译器作为described in Nuitka User Manual
用例 2 - 扩展模块编译 如果你想编译单个扩展模块,你所要做的就是:
python -m nuitka --module some_module.py然后可以使用生成的文件 some_module.so 代替 some_module.py。
你需要为你想要支持的每个平台编译并编写一些初始化代码来导入so/pyd文件~~适合给定平台/python版本等~~
[EDIT 2021-12]:实际上在 python 3 中,正确的 so/dll 是根据文件名自动确定的(如果它包括 python 版本和平台 - 目前找不到此功能的 PEP,但 Nuitka 创建编译模块的专有名称)。因此,对于 python 2.7,库名称将是 something.pyd 或 something.so,而对于 python 3,这将更改为 something.cp36-win32.pyd 或 something.cpython-36m-x86_64-linux-gnu.so(对于 32 位 python 3.6在 x86 上)。
结果不是请求的 DLL,而是 Python 原生编译的二进制格式(它不是 pyc 文件中的字节码;so/pyd 格式不容易反编译 - Nuitka 通过 C++ 翻译编译为机器码)
EDIT [2020-01]:编译后的模块倾向于使用 python 标准机制的评估方法——例如它可以作为任何其他模块导入并列出其方法等。为了保护实现不被暴露,除了编译为二进制模块之外,还有更多工作要做。
【讨论】:
哇!那是宝石!!非常感谢【参考方案4】:您可以使用py2exe.org 将python 脚本转换为Windows 可执行文件。当然,这仅适用于 Windows,但总比没有好。
【讨论】:
from package 我的意思是一个包(模块),这意味着我可以分发一些 Python 代码,但对于某些模块,我只想分发 dll 文件。 我可能是错的,所以不要引用我的话,但是.exe 文件可以像 dll 模块一样使用。所以使用 py2exe 创建 .exe,然后将其重命名为 .dll,这样您的用户就不会尝试“运行”包。 我觉得你的想法值得一试。谢谢 不幸的是,exe 文件不是 DLL,它们是不同的东西。在 C/C++ 编码 DLL 文件中缺少main()
函数
DLL 具有处理进程和线程附加和分离事件的 DllMain。如果你编译成一个 EXE,你将无法连接到那些。【参考方案5】:
Python embedding is supported in CFFI version 1.5,您可以创建一个可供 Windows C 应用程序使用的.dll
文件。
【讨论】:
如果你有一个DllMain,你可以将它声明为“CFFI_DLLEXPORT int __stdcall DllMain(void* hinstDLL, unsigned long fdwReason, void* lpvReserved);”在你的头文件中。【参考方案6】:我也会使用Cython 来生成pyd
文件,就像Dikei 写的那样。
但是如果你真的想保护你的代码,你最好用 C++ 编写重要的东西。最好将 C++ 和 Python 结合起来。这个想法:你可以让 python 代码打开以进行调整,这样你就不必一遍又一遍地编译所有东西。这意味着,您将用 C++ 编写“核心”(这是当今最安全的解决方案),并在您的 python 代码中使用那些 dll
文件。这实际上取决于您正在构建什么样的工具或程序以及您希望如何执行它。完成工具或程序后,我主要创建一个执行文件(exe
,app
),但这更多是针对最终用户的。这可以通过py2exe
和py2app
(均兼容64 位)来完成。如果您实现解释器,则最终用户的机器不必在系统上安装 python。
pyd
文件与dll
相同,并且在 python 中完全支持。所以你可以正常导入你的模块。你可以找到更多关于它的信息here。
使用和生成pyd
文件是创建安全且可移植的python 代码的最快、最简单的方法。
您还可以在C++ 中编写真正的dll
文件,然后使用ctypes
导入它们以使用它们(这里是一个很好的post,这里是python description,它是如何工作的)
【讨论】:
【参考方案7】:扩展 Nick ODell 的答案
您必须在 Windows 上运行 DLL,它们不可移植。
但是,下面的代码是跨平台的,所有平台都支持运行时,因此可以为您需要它工作的每个平台重新编译。
Python(还)没有提供创建 dll 的简单工具,但是您可以在 C/C++ 中完成
首先,您需要一个编译器(Windows 默认没有),特别是 Cygwin、MinGW 或 Visual Studio。
C 的基本知识也是必要的(因为我们将主要使用 C 进行编码)。
你还需要包含必要的标题,我会跳过这个,这样它就不会变得太长,并假设一切都设置正确。
对于这个演示,我将打印一个传统的 hello world:
我们将转换为 DLL 的 Python 代码:
def foo(): print("hello world")
C 代码:
#include "Python.h" // Includes everything to use the Python-C API
int foo(void); // Declare foo
int foo(void) // Name of our function in our DLL
Py_Initialize(); // Initialise Python
PyRun_SimpleString("print('hello world')"); // Run the Python commands
return 0; // Finish execution
这是用于嵌入 Python 的 tutorial。这里应该添加一些额外的东西,但为简洁起见,我将它们省略了。
编译它,你应该有一个 DLL。 :)
这还不是全部。您将需要分发所需的任何依赖项,这意味着 python36.dll
运行时和一些其他组件来运行 Python 脚本。
我的 C 代码并不完美,所以如果有人发现任何改进,请发表评论,我会尽力修复它。
这个答案How do I call a specific Method from a Python Script in C#? 在 C# 中也有可能,因为 C# 可以创建 DLL,并且您可以从 C# 调用 Python 函数。
【讨论】:
【参考方案8】:您可以使用pyinstaller 将 .py 文件转换为可执行文件,并将所有必需的包转换为 .dll 格式。
步骤 1. pip install pyinstaller,
步骤 2. 新建 python 文件,我们将其命名为 code.py 。
步骤 3. 编写一些代码行,即 print("Hello World")
步骤 4. 在同一位置打开命令提示符并编写 pyinstaller code.py 回车。最后一步在同一位置看到两个文件夹名称 build,dist 将被创建。在 dist 文件夹内有文件夹代码,在该文件夹内有一个 exe 文件 code.exe 以及所需的 .dll 文件。
【讨论】:
很有趣 - 你能提供一些代码来展示它是如何完成的吗? 第 1 步。pip install pyinstaller
,第 2 步。 新的 Python 文件,我们将其命名为 code.py
。 第 3 步。 编写几行代码,即 print("Hello World")
第 4 步。 在同一位置打开命令提示符并输入 pyinstaller code.py
回车。 最后一步在同一位置看到两个文件夹名称build, dist
将被创建。在 dist 文件夹内有文件夹 code
,在该文件夹内有一个 exe 文件 code.exe
以及所需的 .dll 文件。
那个创建的是exe而不是DLL,DLL是用来运行exe的【参考方案9】:
这是我的想法,它可能会奏效。我不知道这是否有效。
1.创建您的*.py
文件。
2.重命名为*.pyx
3.使用 Cython 将它们转换为 *.c
文件
4.将*.c
编译成*.dll
文件。
但我不推荐你,因为它不能在 Windows 以外的任何其他平台上运行。
【讨论】:
【参考方案10】:使用 Visual Studio Express 和 IronPython 并这样做?不过,您将进入 Python 2.7.6 世界。
【讨论】:
以上是关于如何将 Python 包编译为 dll的主要内容,如果未能解决你的问题,请参考以下文章
如何将用 python 编写的函数编译为 JavaScript (emscripten)?