【发布时间】:2020-05-01 16:03:26
【问题描述】:
我在使用 PyInstaller 构建到可执行文件中的脚本遇到问题。该脚本在作为 Python 脚本运行时运行良好,但在作为 PyInstaller 应用程序运行时,遇到路径超过 260 个字符的文件时会失败。
我知道这是由于limitation of Windows 和对更长路径的支持必须在注册表中使用opted into 并使用启用longPathAware 设置的应用程序清单。顺便说一句,这在 Python 本身中起作用的原因是因为 at Python 3.6 the developers enabled this setting 用于 python.exe 和 pythonw.exe。
到目前为止,我已经完成了所有这些工作,如果我将以下清单文件放在构建的 PyInstaller 应用程序旁边(使用 --onefile 模式),它确实可以工作:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
</assembly>
但是,为了使应用程序独立且便于最终用户移植,我试图避免使用外部清单文件,而是让 PyInstaller 将此自定义清单嵌入到可执行文件中。
--manifest option 据称是这样做的——至少从 PyInstaller 3.5 开始,根据 changelog 和 PR #3746:
但是,当指定时,自定义清单文件似乎被忽略了,因为应用程序在没有外部清单文件的情况下继续在长路径上失败,并且在 --onedir 模式下检查捆绑的清单文件,它看起来就像是忽略了自定义的,而是创建了这个:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<dependency>
<dependentAssembly>
<assemblyIdentity language="*" name="Microsoft.Windows.Common-Controls" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" type="win32" version="6.0.0.0"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"/>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>
我做错了什么或理解错了吗? --manifest 选项不符合我的想法吗?这是一个错误吗?
This answer 描述了修改 PyInstaller 源代码以覆盖嵌入式清单创建。这还有必要吗?
我还在 GitHub 上遇到了一个似乎有同样问题的项目; this PR 的作者说:
请注意,PyInstaller 还不理解
longPathAware设置并将其从清单中删除。
我不知道这是否属实,但我认为它确实为这是一个错误提供了一些分量。
我正在使用 PyInstaller 3.6、Python 3.7.2 和 Windows 10 版本 1809。
【问题讨论】:
-
您的程序真的只应该在注册表中启用长 DOS 路径的 Windows 10 系统中的长路径下正常工作吗?也许您应该考虑规范化以使用 "\\?\" 扩展路径,这允许使用长路径一直到 Windows NT 4 (1996)。
-
@ErykSun 是的,我已经阅读了有关该前缀的信息,但它似乎有其自身的兼容性问题(此外,它的目的不是专门用于启用长路径,而是禁用对路径字符串的解析)。在我的例子中,这个程序只能被 Windows 10 电脑使用,我们可以为它使用组策略。但是我也对此感兴趣,因为还有其他有用的东西可以放在 PyInstaller 应该支持的清单中,或者至少允许在不覆盖它们的情况下,例如
dpiAware。至少可以使用外部清单,所以不会太繁琐,只是不太理想。 -
嵌入时,应用程序清单只是一个 PE 资源。您可以在文件中将其替换为后续构建步骤 - 至少在 PyInstaller 得到修复之前。
-
我考虑过,但显然在 PyInstaller 应用程序上使用
mt.exe会破坏它们:stackoverflow.com/a/14654743 -- 你知道另一种方法吗? -
您可以尝试在源可执行文件中嵌入清单,然后将其与压缩应用程序连接。
标签: python windows pyinstaller manifest max-path