我在Windows 10上运行Python 3.5,我想将我的Python代码编译成单个可执行文件,以便与一些最终用户共享。我使用Cython 0.25.2试图完成这项工作。
我通过使用Cython --embed标志获得了一个HelloWorld程序。从Windows命令提示符Cython生成一个.c文件:
# (myVirtualEnv) > cd (pathToSourceCode)
# (myVirtualEnv) > py (pathToVirtualEnv)\Scripts\cython.exe helloWorld.pyx --embed
这给了我一个HelloWorld.c文件。然后我打开MSVC ++ 2015 x86本机命令提示符并将HelloWorld.c文件编译成Windows exe:
# > cd (pathToSourceCode)
# > cl.exe /nologo /Ox /MD /W3 /GS- /DNDEBUG -I(pathToVirtualEnv)\Include -I(pathToVirtualEnv)\PC /TchelloWorld.c /link /OUT:"helloTest.exe" /SUBSYSTEM:CONSOLE /MACHINE:X86 /LIBPATH:(pathToVirtualEnv)\Lib /LIBPATH:C:\Python35\libs
这很有效。从Windows命令提示符运行时,我的新helloTest.exe程序将打印到命令行。我需要弄清楚如何将第一组命令(从常规命令提示符)转换为distutils安装脚本,我还没有完成。也许我可以将windows编译器命令变成make文件或批处理文件等。
这里的缺点是我希望能够将许多模块和软件包组合在一起,而且我也不想确保最终用户拥有所有依赖项(Python 3.5和所有必需的模块) )到位。
我还没有弄清楚如何构建多个Cython文件,然后将它们链接到最终的Windows .exe文件中。但是,看看我也想要包含Python本身和任何包含的python模块,除了一些预编译处理之外,我还需要一个冻结工具。
Cython有一个cython_freeze的演示文件夹。这看起来很完美。它说它将所有包含的模块(包括Python本身)拉入一个c文件进行编译。示例文件包含自述文件和gcc的make文件。我不完全理解这里发生了什么,因为我使用MSCV cl.exe,我认为正确的做法是找到/修改它以适用于cl.exe。我缺乏这样做的技能。事实上,因为我在Windows上,我从pre-compiled wheels得到了cython,我甚至不确定我的virtualenv中是否存在cython_freeze(我进行了搜索并没有提出任何问题) )。同样地," cython冻结"网络搜索也空了。到目前为止,我已经使用了cython -embed HelloWorld程序,并且我已经从GitHub下载了cython源代码来查看cython_freeze自述文件和制作文件。
所以,我的问题:
我绝对愿意接受其他非cython_freeze方式。但是,我应该注意到,我已经看过其他一些看起来不太有希望的选择:
除了windows10和Python 3.5之外,我还使用pip和virtualenv来管理我的包并创建我的virtualenv。我没有使用蚂蚁或康茄舞。 Cython和我的其他大多数软件包都是从预编译的轮子安装的,如上所述。
更新:
我的问题的精神实际上是为没有安装Python的用户打包Python。 Matt提供了一种很好的方法(以及编译Python的良好教育)。 Biswa_9937和S.Moncayo正确地指出Py2Exe(Python版本3.4及更早版本)和PyInstaller(适用于Python 3.5)也可以实现这一目标。这些都是很好的答案,非常有帮助。
然而,我的问题的细节是关于让Cython_freeze在Windows上运行。没有人尝试过,所以我没有回答这个问题,希望Cython大师可以权衡。
答案 0 :(得分:1)
我不会(直接)回答你的问题,但会得到我认为你想要的结果。相反,我将为您提供安装了NumPy SciPy Pandas的预编译Python 3.5 x64 Windows构建嵌入式副本的链接,您只需下载并将从Python / libs / site-packages /导入的每个库添加到extension_modules中/目录并仅使用.py脚本即插即用。 https://stackoverflow.com/a/44610044/6037118您可能需要滚动到我的答案。除了我的理解冻结之外,无论如何你都要把所有内容放到exe中,你仍然需要带有导入库的子文件夹。
https://www.dropbox.com/sh/2smbgen2i9ilf2e/AADI8A3pCAFU-EqNLTbOiUwJa?dl=0
而不是将其重新编译为x32,我将教你如何捕鱼本身。这是Visual Studio项目call_function.c
文件:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr, "Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_SetPath(L"python35.zip;extension_modules//;); //all your libraries from site-packages must be installed under extension_modules directory like \extension_modules\numpy\
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyLong_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr, "Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
以下是您可以保存为embedpython.sln
的Visual Studio解决方案文件:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "embedpython", "embedpython.vcxproj", "{51062161-3FE4-42F2-9B89-BEB15E8F7590}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Debug|x64.ActiveCfg = Debug|x64
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Debug|x64.Build.0 = Debug|x64
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Debug|x86.ActiveCfg = Debug|Win32
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Debug|x86.Build.0 = Debug|Win32
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Release|x64.ActiveCfg = Release|x64
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Release|x64.Build.0 = Release|x64
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Release|x86.ActiveCfg = Release|Win32
{51062161-3FE4-42F2-9B89-BEB15E8F7590}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
现在您必须下载可嵌入的zip文件(32位一个在这里):https://www.python.org/ftp/python/3.5.1/python-3.5.1-embed-win32.zip并将其解压缩并放在带有内置EXE文件的目录中。此外,您不需要随附的python.exe或wpython.exe,并将所有PYD文件复制到\ extension_modules \目录中。请注意,您还需要在链接器中添加任何链接库.lib文件:
这里是embedpython.vsxproj
文件:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{51062161-3FE4-42F2-9B89-BEB15E8F7590}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Python3;C:\Python3\include;</IncludePath>## Heading ##
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>python35.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>python35.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\Python3\libs;</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="call_function.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
确保上述所有目录都指向您的实际Python3安装(此处假设\ Python3 \是安装目录)。然后只需打开解决方案文件并构建x32或x64或您喜欢的任何内容。你必须玩一下才能找到你的包所需的一切。例如,Numpy需要链接到\ Python3 \ Lib \ site-packages \ numpy \ core \ lib \ npymath.lib。任何你自己编译的PYD Cython程序都可以直接放在\ extension_modules \中。对于我在Windows上的构建,我还必须在带有EXE的目录中包含msvcp140_app.dll(奇怪的是\ Program Files(x86)\ Microsoft Visual Studio 14.0 \重命名VC \ redist \ x64 \ Microsoft.VC140.CRT \ msvcp140.dll,或者32位的\ x86 \目录。)
出于所有这些奇怪的原因,我注意到,这就是为什么我建议下载预建版本才能开始 - 至少它会告诉你必须如何打包才能使它工作。
享受。
答案 1 :(得分:0)
你应该试试py2exe,我认为这是从python代码制作.exe的最简单方法。我理解你想要的东西,但很容易用py2exe创建一个.exe,用C复制文件夹,然后创建一个快捷方式。