“版本文件”是什么样的?

53 投票
6 回答
54165 浏览
提问于 2025-04-17 14:18

我在网上搜索这个问题已经很久了,但一直没有找到答案。PyInstaller 的手册上说:

--version-file=FILE
    add a version resource from FILE to the exe

听起来不错。我想在我的可执行文件中加入版本信息。问题是我根本不知道“版本文件”长什么样,也找不到一个可以用的例子。我认为一个版本文件的例子可以算是这个问题的一个合适答案。


我尝试过的

手册上还提到:

版本
仅适用于 Windows NT 系列。version='myversion.txt'。使用 GrabVersion.py 从一个可执行文件中提取版本资源,然后编辑输出以创建你自己的版本文件。(版本资源的语法非常复杂,我不建议从头开始写一个。)

我已经尝试过用我系统中的无数个可执行文件来做这个了。结果我一直收到这些错误:

Traceback (most recent call last):
  File "C:\pyinstaller-2.0\utils\GrabVersion.py", line 42, in 
    vs  = versioninfo.decode(sys.argv[1])
  File "C:\pyinstaller-2.0\PyInstaller\utils\versioninfo.py", line 33, in decode
    nm = win32api.EnumResourceNames(h, RT_VERSION)[0]
IndexError: list index out of range

在没有版本信息的可执行文件上,以及:

Traceback (most recent call last):
  File "C:\pyinstaller-2.0\utils\GrabVersion.py", line 43, in 
    print vs
  File "C:\pyinstaller-2.0\PyInstaller\utils\versioninfo.py", line 147, in __repr__
    % (indent, self.ffi.__repr__(indent), indent,
  File "C:\pyinstaller-2.0\PyInstaller\utils\versioninfo.py", line 251, in __repr__
    "filevers=%s," % fv,
TypeError: not all arguments converted during string formatting

在其他文件上。

6 个回答

9

首先,按照之前的回答创建一个版本文件,并把它保存为 version.rc

然后找到 filename.spec 这个文件并打开它。在这个脚本中,找到以下内容:

exe = EXE(pyz,...)

在这一整段的最后,添加这段代码,这样就可以自动把版本信息嵌入到你的exe文件里。

version='version.rc'

保存文件后,再次启动pyinstaller,这次用以下代码运行安装程序:

pyinstaller filename.spec 

这样不仅会生成exe文件,还会把你的版本信息也包含进去。

如果你还没想到这一点,记得把 filename 替换成你程序的文件名。

37

我可能在之前的回答中漏掉了这一点,或者也许自从那些回答发布以来,PyInstaller已经更新了,但现在的PyInstaller文档提供了一种相当简单的方法,可以通过命令行工具来实现这个功能(虽然我第一次查看文档时错过了这一部分)。

你只需要把这个工具指向你系统中的一个.exe文件,这个文件的版本信息要“好看”,然后它会生成一个人类可读的、带注释的、可编辑的版本资源文件,你可以用它作为起点。

pyi-grab_version executable_with_version_resource

默认情况下,它会在当前工作目录下写入一个名为file_version_info.txt的文件。

在我本地的svn.exe上运行上述命令,得到的结果是:

# UTF-8
#
# For more details about fixed file info 'ffi' see:
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
VSVersionInfo(
  ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0.
filevers=(1, 9, 7, 30920),
prodvers=(1, 9, 7, 30920),
# Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file.
flags=0x0,
# The operating system for which this file was designed.
# 0x4 - NT and there is no need to change it.
OS=0x4,
# The general type of file.
# 0x1 - the file is an application.
fileType=0x1,
# The function of the file.
# 0x0 - the function is not defined for this fileType
subtype=0x0,
# Creation date and time stamp.
date=(0, 0)
),
  kids=[
StringFileInfo(
  [
  StringTable(
    u'040904B0',
    [StringStruct(u'CompanyName', u'Apache Software Foundation'),
    StringStruct(u'FileDescription', u'svn'),
    StringStruct(u'FileVersion', u'1.9.7'),
    StringStruct(u'InternalName', u'SVN'),
    StringStruct(u'LegalCopyright', u'Copyright (c) The Apache Software Foundation'),
    StringStruct(u'OriginalFilename', u'svn.exe'),
    StringStruct(u'ProductName', u'Subversion'),
    StringStruct(u'ProductVersion', u'1.9.7 (r1800392)')])
  ]), 
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
  ]
)

你可以根据自己的需要编辑这个文件,然后将它作为--version-file传回给PyInstaller,比如:

pyinstaller [options] myscript.py --version-file file_version_info.txt
49

我刚看了一下源代码。看起来版本文件应该是Python的源代码,因为提供的版本文件会被读取,然后用eval来执行。

你已经发现GrabVersion.py脚本会产生错误,所以我修改了FixedFileInfo__repr__函数,让它可以手动把元组参数转换成字符串。

Windows的cmd.exe里嵌入了一个Windows版本资源,这里是GrabVersion.py的输出,你可以把它保存到一个文件里,然后提供给PyInstaller。

VSVersionInfo(
  ffi=FixedFileInfo(
    filevers=(6, 1, 7601, 17514),
    prodvers=(6, 1, 7601, 17514),
    mask=0x3f,
    flags=0x0,
    OS=0x40004,
    fileType=0x1,
    subtype=0x0,
    date=(0, 0)
    ),
  kids=[
    StringFileInfo(
      [
      StringTable(
        u'040904B0',
        [StringStruct(u'CompanyName', u'Microsoft Corporation'),
        StringStruct(u'FileDescription', u'Windows Command Processor'),
        StringStruct(u'FileVersion', u'6.1.7601.17514 (win7sp1_rtm.101119-1850)'),
        StringStruct(u'InternalName', u'cmd'),
        StringStruct(u'LegalCopyright', u'\xa9 Microsoft Corporation. All rights reserved.'),
        StringStruct(u'OriginalFilename', u'Cmd.Exe'),
        StringStruct(u'ProductName', u'Microsoft\xae Windows\xae Operating System'),
        StringStruct(u'ProductVersion', u'6.1.7601.17514')])
      ]), 
    VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
  ]
)

我还没有尝试用PyInstaller设置版本资源,所以不确定这样是否有效,期待你的反馈。

撰写回答