我需要一些帮助来构建pythonservice.exe(PythonService.cpp https://github.com/kovidgoyal/pywin32/tree/master/win32/src)。
据说(https://github.com/kovidgoyal/pywin32)需要VS2015,所以我下载了社区版本。我打开了一个新的win32控制台项目,并仅将PythonService.cpp导入源文件。
在项目设置中,我有:
包含目录:C:Python27_32bitinclude;C:pywin32-masterwin32src;$(VC_IncludePath);$(WindowsSDK_IncludePath);
库目录:C:Python27Libsite-packageswin32libs;C:Python27_32bitlibs;C:pywin32-masterwin32src;$(LibraryPath);C:pywin32-masterlibx32win32libs;
现在,在构建时,我收到未解决的外部符号错误:
1>PythonService.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) char * __cdecl GetPythonTraceback(struct _object *,struct _object *,struct _object *)" (__imp_?GetPythonTraceback@@YAPADPAU_object@@00@Z)
GetPythonTraceback是在PyWinTypesmodule中定义的.cpp但是当我将其添加到我的项目中时,它给出了其他错误,需要其他未解决的功能。我不想编译整个win32项目。我所需要的只是pythonservices.exe。这可以在不编译整个项目的情况下完成吗? 将不胜感激任何帮助!
谢谢! 阿列克谢
我最终找到了我的问题的解决方案(并非没有@CristiFati的答案的帮助!我下载了 https://github.com/mhammond/pywin32/tree/b222 并使用 setup.py 脚本构建了整个包。此外,我还安装了所需的SDK包(适用于python 2.6+Microsoft Windows SDK for Windows 7和.NET Framework 4(版本7.1))。经过一点挖掘,我发现编译和链接是用Python 9.0的Visual C++完成的,下面是pythonservice.pyd和pythonservice的编译和链接配方.exe(python列出了cmd参数到os.spawnv(os)的调用。P_WAIT,可执行文件,cmd):
对于pythonservice.pyd:
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin\x64\mc.exe"','-h', 'win32/src', '-r', 'build\temp.win-amd64-2.7\Release\win32/src', 'win32/src/PythonServiceMessages.mc']
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin\x64\rc.exe"','/fobuild\temp.win-amd64-2.7\Release\win32/src/PythonServiceMessages.res','build\temp.win-amd64-2.7\Release\win32/src\PythonServiceMessages.rc']
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe"','/c', '/nologo', '/Ox','/W3','/GS', '/DNDEBUG', '/MD', '-DDISTUTILS_BUILD', '-D_CRT_SECURE_NO_WARNINGS','-Icom/win32com/src/include', '-Iwin32/src', '-IC:\Python27\include', '-IC:\Python27\PC','"-IC:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\include"', '/Tpwin32/src/PythonService.cpp','/Fobuild\temp.win-amd64-2.7\Release\win32/src/PythonService.obj', '-DPYSERVICE_BUILD_DLL', '/Zi','/Fdbuild\temp.win-amd64-2.7\Release\servicemanager_vc.pdb', '/EHsc', '/DUNICODE', '/D_UNICODE', '/DWINNT']
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\link.exe"', '/DLL', '/nologo', '/INCREMENTAL:NO', '/LIBPATH:C:\Python27\libs', '/LIBPATH:C:\Python27\PCbuild\amd64', '/LIBPATH:C:\Python27\PC\VS9.0\amd64', '/LIBPATH:build\temp.win-amd64-2.7\Release', '"/LIBPATH:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\lib\x64"', 'user32.lib', 'ole32.lib', 'advapi32.lib', 'shell32.lib', '/EXPORT:initservicemanager', 'build\temp.win-amd64-2.7\Release\win32/src/PythonServiceMessages.res', 'build\temp.win-amd64-2.7\Release\win32/src/PythonService.obj', '/OUT:build\lib.win-amd64-2.7\win32\servicemanager.pyd', '/IMPLIB:build\temp.win-amd64-2.7\Release\win32/src\servicemanager.lib', '/MANIFEST:NO', '/MACHINE:amd64', '/BASE:0x1e7d0000', '/DEBUG', '/PDB:build\temp.win-amd64-2.7\Release\servicemanager.pdb']
对于pythonservice.exe:
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe"','/c', '/nologo', '/Ox', '/W3', '/GS-', '/DNDEBUG', '/MD', '-DDISTUTILS_BUILD', '-D_CRT_SECURE_NO_WARNINGS','-Icom/win32com/src/include', '-Iwin32/src', '-IC:\Python27\include', '-IC:\Python27\PC','"-IC:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\include"','/Tpwin32\src\PythonService.cpp', '/Fobuild\temp.win-amd64-2.7\Release\pythonservice\win32\src\PythonService.obj','/Zi', '/Fdbuild\temp.win-amd64-2.7\Release\pythonservice_vc.pdb', '/EHsc', '/DUNICODE', '/D_UNICODE', '/DWINNT']
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin\x64\rc.exe"','-DDISTUTILS_BUILD', '-D_CRT_SECURE_NO_WARNINGS', '-Icom/win32com/src/include', '-Iwin32/src', '-IC:\Python27\include','-IC:\Python27\PC', '"-IC:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\include"','/fobuild\temp.win-amd64-2.7\Release\pythonservice\win32\src\PythonService.res', 'win32\src\PythonService.rc']
['"C:\Users\username\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\link.exe"','/nologo', '/INCREMENTAL:NO', '/LIBPATH:C:\Python27\libs', '/LIBPATH:C:\Python27\PCbuild\amd64','/LIBPATH:C:\Python27\PC\VS9.0\amd64', '/LIBPATH:build\temp.win-amd64-2.7\Release','"/LIBPATH:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\lib\x64"', 'user32.lib', 'advapi32.lib', 'ole32.lib','shell32.lib', 'build\temp.win-amd64-2.7\Release\pythonservice\win32\src\PythonService.obj','build\temp.win-amd64-2.7\Release\pythonservice\win32\src\PythonService.res','/OUT:build\lib.win-amd64-2.7\win32\pythonservice.exe','/MANIFESTFILE:build\temp.win-amd64-2.7\Release\pythonservice\win32\src\pythonservice.exe.manifest','/SUBSYSTEM:CONSOLE', '/MACHINE:amd64', '/DEBUG', '/PDB:build\temp.win-amd64-2.7\Release\pythonservice.pdb']
['mt.exe', '-nologo', '-manifest','build\temp.win-amd64-2.7\Release\pythonservice\win32\src\pythonservice.exe.manifest.orig','-outputresource:build\lib.win-amd64-2.7\win32\pythonservice.exe;1']
['C:\Python27\python.exe', 'C:\Python27\Lib\site-packages\win32\lib\win32verstamp.py', '--version=2.7.222.1', '--comments=https://github.com/mhammond/pywin32', '--original-filename=pythonservice.exe','--product=PyWin32', '--quiet', 'build\lib.win-amd64-2.7\win32\pythonservice.exe']
我在这里看到的第一件事是结合Python 2.7和VStudio 2015。根据[Python.Wiki]:WindowsCompilers,对于VStudion 2015(或14.0),你应该使用Python3.5或Python 3.6(我有前者)。
检查[SO]:Windows中的Simstring(python)安装(@CristiFati的答案)-(第一部分),关于兼容性和限制:
- 平台
- 工具版本
- 建筑
另外,有关在Win上构建C代码的一些(基本)信息:[SO]:CLR Windows表单中的LNK2005错误(@CristiFati的答案)
- 从以下位置下载原始 PyWin32:[GitHub]: mhammond/pywin32 - (b222) (至pywin32-b222.zip)。">${PYWIN32_SRC_DIR}\win32\src\PythonService.cpp"与您提到的URL中的对应者相同
- 为其创建一个目录和cd(应为空)。这将是%ROOT_DIR%,我将使用的所有路径都将相对于它(当然绝对路径除外),这将是默认目录(未指定时)
-
将下载的.zip解压缩到某处。我们(直接)需要它:
- ">${PYWIN32_SRC_DIR}\win32\src\PythonService.cpp" - 正如你提到的,源代码
- ">${PYWIN32_SRC_DIR}\win32\src\PythonServiceMessages.mc" - 消息文本文件
我将它们复制到一个名为src的目录中:E:WorkDevStackOverflowq048931801>dir /b src E:WorkDevStackOverflowq048931801>dir /b "src" PythonService.cpp PythonServiceMessages.mc
由于构建涉及 - 资源和自定义构建步骤(我不是很擅长),而且它不涉及很多文件,因此我不打算使用IDE
下一个最好的方法是使用Makefiles,但是由于VStudio有一个错误[MS.MSDN]: ntwin32.mak 未找到:
- 它也影响VStudio 2015
- 它需要一次性修复 我在我的机器上
- 进行了修复并且它可以工作,但您很可能没有在您的机器上修复,我不想用此步骤给您带来不必要的负担
我要手动完成所有操作设置虚拟主机环境:
- [女士。文档]:从命令行使用 MSVC 工具集
- 你也可以检查[SO]:如何构建libjpeg 9b的DLL版本?(@CristiFati的回答)(第 1部分)了解有关手动构建的更多详细信息
我正在使用vcvarsall.bat([MS.MSDN]:vcvarsall .bat 文件在哪里?从命令行
E:WorkDevStackOverflowq048931801>"c:Installx86MicrosoftVisual Studio Community2015VCvcvarsall.bat" amd64
- 您(显然)需要提供VStudio安装路径
- amd64是因为我只安装了64 位(x64 或AMD64)版本的Python 3.5
将消息文件编译为资源文件 - 使用mc.exe([MS.文档]:消息编译器(MC.exe))
E:WorkDevStackOverflowq048931801>mc "srcPythonServiceMessages.mc" MC: Compiling srcPythonServiceMessages.mc E:WorkDevStackOverflowq048931801>dir /b MSG00001.bin PythonServiceMessages.h PythonServiceMessages.rc src
如前所述,它生成了 3 个新文件
编译资源文件 - 使用rc.exe([MS.文档]:资源编译器)
E:WorkDevStackOverflowq048931801>rc /NOLOGO /r "PythonServiceMessages.rc" E:WorkDevStackOverflowq048931801>dir /b MSG00001.bin PythonServiceMessages.h PythonServiceMessages.rc PythonServiceMessages.res src
完成资源,转到代码(PythonService.cpp)。正如您已经提到的,它不会编译OOTB。我不打算列出所有失败的尝试,而是列出我采取的步骤,只显示最终(成功)编译。因此,该文件需要来自其他文件的代码。最简单的方法是从其他文件中复制它并将其放在这个文件中。我选择将其粘贴在第#1530行周围(就在">* 入口点"部分之前):
- PyWinTypesModule.cpp-GetPythonTraceback函数(第 1142 - 1235 行)
- PyUnicode.cpp-
PyWin_AutoFreeBstr::PyWin_AutoFreeBstr
,PyWin_AutoFreeBstr::~PyWin_AutoFreeBstr
,PyWin_AutoFreeBstr::SetBstr
(行 204 - 219)
手动应用更改,或保存:
--- PythonService.cpp.orig 2018-01-20 21:43:10.000000000 +0200 +++ PythonService.cpp 2018-02-23 20:02:20.186966800 +0200 @@ -1529,6 +1529,120 @@ } } +// @TODO: cfati - copied from PyUnicode.cpp (lines 204 - 219) +PyWin_AutoFreeBstr::PyWin_AutoFreeBstr( BSTR bstr /*= NULL*/ ) + : m_bstr(bstr) +{ + return; +} + +PyWin_AutoFreeBstr::~PyWin_AutoFreeBstr() +{ + SysFreeString(m_bstr); +} + +void PyWin_AutoFreeBstr::SetBstr( BSTR bstr ) +{ + SysFreeString(m_bstr); + m_bstr = bstr; +} + + +// @TODO: cfati - copied from PyWinTypesModule.cpp (lines 1142 - 1235) +// Function to format a python traceback into a character string. +#define GPEM_ERROR(what) {errorMsg = "<Error getting traceback - " ## what ## ">";goto done;} +char *GetPythonTraceback(PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb) +{ + // Sleep (30000); // Time enough to attach the debugger (barely) + char *result = NULL; + char *errorMsg = NULL; + PyObject *modStringIO = NULL; + PyObject *modTB = NULL; + PyObject *obFuncStringIO = NULL; + PyObject *obStringIO = NULL; + PyObject *obFuncTB = NULL; + PyObject *argsTB = NULL; + PyObject *obResult = NULL; + + /* Import the modules we need - cStringIO and traceback */ +#if (PY_VERSION_HEX < 0x03000000) + modStringIO = PyImport_ImportModule("cStringIO"); +#else + // In py3k, cStringIO is in "io" + modStringIO = PyImport_ImportModule("io"); +#endif + + if (modStringIO==NULL) GPEM_ERROR("cant import cStringIO"); + modTB = PyImport_ImportModule("traceback"); + if (modTB==NULL) GPEM_ERROR("cant import traceback"); + + /* Construct a cStringIO object */ + obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO"); + if (obFuncStringIO==NULL) GPEM_ERROR("cant find cStringIO.StringIO"); + obStringIO = PyObject_CallObject(obFuncStringIO, NULL); + if (obStringIO==NULL) GPEM_ERROR("cStringIO.StringIO() failed"); + + /* Get the traceback.print_exception function, and call it. */ + obFuncTB = PyObject_GetAttrString(modTB, "print_exception"); + if (obFuncTB==NULL) GPEM_ERROR("cant find traceback.print_exception"); + argsTB = Py_BuildValue("OOOOO" +#if (PY_VERSION_HEX >= 0x03000000) + "i" + // Py3k has added an undocumented 'chain' argument which defaults to True + // and causes all kinds of exceptions while trying to print a goddam exception +#endif + , + exc_type ? exc_type : Py_None, + exc_value ? exc_value : Py_None, + exc_tb ? exc_tb : Py_None, + Py_None, // limit + obStringIO +#if (PY_VERSION_HEX >= 0x03000000) + ,0 // Goddam undocumented 'chain' param, which defaults to True +#endif + ); + if (argsTB==NULL) GPEM_ERROR("cant make print_exception arguments"); + + obResult = PyObject_CallObject(obFuncTB, argsTB); + if (obResult==NULL){ + // Chain parameter when True causes traceback.print_exception to fail, leaving no + // way to see what the original problem is, or even what error print_exc raises + // PyObject *t, *v, *tb; + // PyErr_Fetch(&t, &v, &tb); + // PyUnicodeObject *uo=(PyUnicodeObject *)v; + // DebugBreak(); + GPEM_ERROR("traceback.print_exception() failed"); + } + /* Now call the getvalue() method in the StringIO instance */ + Py_DECREF(obFuncStringIO); + obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue"); + if (obFuncStringIO==NULL) GPEM_ERROR("cant find getvalue function"); + Py_DECREF(obResult); + obResult = PyObject_CallObject(obFuncStringIO, NULL); + if (obResult==NULL) GPEM_ERROR("getvalue() failed."); + + /* And it should be a string all ready to go - duplicate it. */ + if (PyString_Check(obResult)) + result = strdup(PyString_AsString(obResult)); +#if (PY_VERSION_HEX >= 0x03000000) + else if (PyUnicode_Check(obResult)) + result = strdup(_PyUnicode_AsString(obResult)); +#endif + else + GPEM_ERROR("getvalue() did not return a string"); + +done: + if (result==NULL && errorMsg != NULL) + result = strdup(errorMsg); + Py_XDECREF(modStringIO); + Py_XDECREF(modTB); + Py_XDECREF(obFuncStringIO); + Py_XDECREF(obStringIO); + Py_XDECREF(obFuncTB); + Py_XDECREF(argsTB); + Py_XDECREF(obResult); + return result; +} /************************************************************************* *
作为">src\PythonService.diff",这是一个差异。参见 [SO]:在 PyCharm 社区版中从鼠标右键单击上下文菜单中运行/调试 Django 应用程序的单元测试?(@CristiFati的回答)(修补utrunner部分)了解如何在Win上应用补丁(基本上,以一个"+"号开头的每一行都进入,以一个"-">符号开头的每一行都出去)。我正在使用Cygwin:
E:WorkDevStackOverflowq048931801>"c:Installx64CygwinCygwinAllVersbinpatch.exe" "srcPythonService.cpp" "srcPythonService.diff" patching file 'srcPythonService.cpp'
编译代码 - 使用cl.exe([MS.文档]:编译 C/C++ 程序)
E:WorkDevStackOverflowq048931801>cl /GS /W1 /Zc:wchar_t /I"." /I"c:Installx64PythonPython3.5include" /I"e:WorkDevFatiWinBuildOPSWpython27srcpywin32-b222win32src" /Gm- /O2 /Zc:inline /fp:precise /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "WIN64" /D "NDEBUG" /D "BUILD_PYWINTYPES" /errorReport:prompt /WX- /Zc:forScope /Gd /MD /c "srcPythonService.cpp" Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved. PythonService.cpp E:WorkDevStackOverflowq048931801>dir /b "*.obj" PythonService.obj
参数是标准参数([MS.Docs]:按字母顺序列出的编译器选项),特定于这种情况:
/D "BUILD_PYWINTYPES"
(宏定义)/D "WIN64"
- 64位- 包括路径(
/I
) - 您必须调整它们以匹配您的路径:- "c:\Install\x64\Python\Python\3.5\include">(Python路径)
- "e:\Work\Dev\Fati\WinBuild\OPSWpython27\src\pywin32-b222\win32\src" (pywin32path)
将所有内容链接在一起 - 使用链接.exe([MS.文档]:链接)
E:WorkDevStackOverflowq048931801>link /NOLOGO /MACHINE:X64 /SUBSYSTEM:CONSOLE /ERRORREPORT:PROMPT /LIBPATH:"c:Installx64PythonPython3.5libs" /NXCOMPAT /DYNAMICBASE "kernel32.lib" "user32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "PythonService.obj" "PythonServiceMessages.res" /OUT:"PythonService.exe" Creating library PythonService.lib and object PythonService.exp E:WorkDevStackOverflowq048931801>dir /b "*.exe" PythonService.exe
同样,参数是标准的([MS.文档]:链接器选项),特定于这种情况:
/MACHINE:X64
- 64位- 库路径(
/LIBPATH
) - 调整它以匹配您的路径:- ">c:\Install\x64\Python\Python\3.5\libs(Pythonpath)
运行服务之前的最后一步。由于它依赖于python35.dll,操作系统必须知道在哪里查找它。最简单的方法是将其路径添加到%PATH%([MS.文档]:动态链接库搜索顺序)
E:WorkDevStackOverflowq048931801>set PATH=%PATH%;c:Installx64PythonPython3.5 E:WorkDevStackOverflowq048931801>PythonService.exe P - Python Service Manager Options: -register - register the EXE - this should generally not be necessary. -debug servicename [parms] - debug the Python service. NOTE: You do not start the service using this program - start the service using Control Panel, or 'net start service_name'