修复pyinstaller打包失败的问题
This commit is contained in:
@@ -31,7 +31,7 @@ static int ParsePyinstallerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath,
|
|||||||
{
|
{
|
||||||
if (lpRepoPath != NULL)
|
if (lpRepoPath != NULL)
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: repodir 参数重复: %s\n"), argv[i]);
|
_tprintf(_T("错误: repodir 参数重复: %s\n"), argv[i]);
|
||||||
return 23;
|
return 23;
|
||||||
}
|
}
|
||||||
LPCTSTR lpPath = argv[i] + 8;
|
LPCTSTR lpPath = argv[i] + 8;
|
||||||
@@ -48,18 +48,18 @@ static int ParsePyinstallerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath,
|
|||||||
{
|
{
|
||||||
if (!strExtraArgs.IsEmpty())
|
if (!strExtraArgs.IsEmpty())
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: params 参数重复。\n"));
|
_tprintf(_T("错误: params 参数重复。\n"));
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
CString strVal = strArg.Mid(7);
|
CString strVal = strArg.Mid(7);
|
||||||
// 去掉外层双引号(如 params="--onefile")
|
// 去掉外层双引号(如 params="--onefile")
|
||||||
if (strVal.GetLength() >= 2 && strVal[0] == _T('"') && strVal[strVal.GetLength() - 1] == _T('"'))
|
if (strVal.GetLength() >= 2 && strVal[0] == _T('"') && strVal[strVal.GetLength() - 1] == _T('"'))
|
||||||
strVal = strVal.Mid(1, strVal.GetLength() - 2);
|
strVal = strVal.Mid(1, strVal.GetLength() - 2);
|
||||||
strExtraArgs = strVal;
|
strExtraArgs = strVal;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_tprintf(_T("错误: 未知的参数 %s\n"), argv[i]);
|
_tprintf(_T("错误: 未知的参数 %s\n"), argv[i]);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ static int ParsePyinstallerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析版本字符串 "a.b.c.d" → 四个分量
|
// 解析版本字符串 "a.b.c.d" → 四个分量
|
||||||
static BOOL ParseVersionTuple(LPCTSTR lpVer, UINT& v1, UINT& v2, UINT& v3, UINT& v4)
|
static BOOL ParseVersionTuple(LPCTSTR lpVer, UINT& v1, UINT& v2, UINT& v3, UINT& v4)
|
||||||
{
|
{
|
||||||
CString str(lpVer);
|
CString str(lpVer);
|
||||||
@@ -88,7 +88,7 @@ static BOOL ParseVersionTuple(LPCTSTR lpVer, UINT& v1, UINT& v2, UINT& v3, UINT&
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取 params 中第一个空格分隔的 token(支持双引号括起的路径)
|
// 提取 params 中第一个空格分隔的 token(支持双引号括起的路径)
|
||||||
static CString ExtractFirstToken(const CString& strParams)
|
static CString ExtractFirstToken(const CString& strParams)
|
||||||
{
|
{
|
||||||
CString str = strParams;
|
CString str = strParams;
|
||||||
@@ -105,7 +105,7 @@ static CString ExtractFirstToken(const CString& strParams)
|
|||||||
return str.Left(nSpace);
|
return str.Left(nSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成 version_info.txt 到 lpDir 目录(PyInstaller VSVersionInfo 格式)
|
// 生成 version_info.txt 到 lpDir 目录(PyInstaller VSVersionInfo 格式)
|
||||||
static BOOL WriteVersionInfoFile(LPCTSTR lpDir, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion, CString& strOutPath)
|
static BOOL WriteVersionInfoFile(LPCTSTR lpDir, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion, CString& strOutPath)
|
||||||
{
|
{
|
||||||
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
||||||
@@ -165,13 +165,13 @@ static BOOL WriteVersionInfoFile(LPCTSTR lpDir, LPCTSTR lpProductVersion, LPCTST
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向 .spec 文件注入或更新 version= 参数
|
// 向 .spec 文件注入或更新 version= 参数
|
||||||
// 若已有 version= 则更新其值,否则在 name= 参数后新增一行
|
// 若已有 version= 则更新其值,否则在 name= 参数后新增一行
|
||||||
static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
||||||
{
|
{
|
||||||
if (!PathFileExists(lpSpecPath))
|
if (!PathFileExists(lpSpecPath))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: spec 文件不存在 %s\n"), lpSpecPath);
|
_tprintf(_T("错误: spec 文件不存在 %s\n"), lpSpecPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
|||||||
CFileException fileEx;
|
CFileException fileEx;
|
||||||
if (!myFile.Open(lpSpecPath, CFile::modeReadWrite, &fileEx))
|
if (!myFile.Open(lpSpecPath, CFile::modeReadWrite, &fileEx))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: 无法打开 spec 文件 %s\n"), lpSpecPath);
|
_tprintf(_T("错误: 无法打开 spec 文件 %s\n"), lpSpecPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
|||||||
std::string::size_type nPos = 0;
|
std::string::size_type nPos = 0;
|
||||||
while ((nPos = strContent.find("version=", nPos)) != std::string::npos)
|
while ((nPos = strContent.find("version=", nPos)) != std::string::npos)
|
||||||
{
|
{
|
||||||
// 确保 version= 是独立参数(前驱字符为空白或换行,而非字母/数字)
|
// 确保 version= 是独立参数(前驱字符为空白或换行,而非字母/数字)
|
||||||
bool bIsParam = (nPos == 0
|
bool bIsParam = (nPos == 0
|
||||||
|| strContent[nPos - 1] == '\n'
|
|| strContent[nPos - 1] == '\n'
|
||||||
|| strContent[nPos - 1] == '\r'
|
|| strContent[nPos - 1] == '\r'
|
||||||
@@ -203,19 +203,19 @@ static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
|||||||
|| strContent[nPos - 1] == '\t');
|
|| strContent[nPos - 1] == '\t');
|
||||||
if (bIsParam)
|
if (bIsParam)
|
||||||
{
|
{
|
||||||
// 获取行首(保留缩进)
|
// 获取行首(保留缩进)
|
||||||
std::string::size_type nLineStart = strContent.rfind('\n', nPos);
|
std::string::size_type nLineStart = strContent.rfind('\n', nPos);
|
||||||
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
||||||
std::string strIndent = strContent.substr(nLineStart, nPos - nLineStart);
|
std::string strIndent = strContent.substr(nLineStart, nPos - nLineStart);
|
||||||
|
|
||||||
// 获取行末
|
// 获取行末
|
||||||
std::string::size_type nLineEnd = strContent.find('\n', nPos);
|
std::string::size_type nLineEnd = strContent.find('\n', nPos);
|
||||||
if (nLineEnd == std::string::npos) nLineEnd = strContent.size();
|
if (nLineEnd == std::string::npos) nLineEnd = strContent.size();
|
||||||
|
|
||||||
// 替换整行(保留缩进,统一加尾随逗号)
|
// 替换整行(保留缩进,统一加尾随逗号)
|
||||||
std::string strNewLine = strIndent + strNewValue + ",";
|
std::string strNewLine = strIndent + strNewValue + ",";
|
||||||
strContent.replace(nLineStart, nLineEnd - nLineStart, strNewLine);
|
strContent.replace(nLineStart, nLineEnd - nLineStart, strNewLine);
|
||||||
_tprintf(_T("成功: 已更新 spec 文件 version 字段 -> version_info.txt\n"));
|
_tprintf(_T("成功: 已更新 spec 文件 version 字段 -> version_info.txt\n"));
|
||||||
bFound = true;
|
bFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -224,34 +224,34 @@ static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
|||||||
|
|
||||||
if (!bFound)
|
if (!bFound)
|
||||||
{
|
{
|
||||||
// 未找到 version=,在 name= 参数后插入新行
|
// 未找到 version=,在 name= 参数后插入新行
|
||||||
std::string::size_type nNamePos = strContent.find("name=");
|
std::string::size_type nNamePos = strContent.find("name=");
|
||||||
if (nNamePos != std::string::npos)
|
if (nNamePos != std::string::npos)
|
||||||
{
|
{
|
||||||
// 获取 name= 行的缩进
|
// 获取 name= 行的缩进
|
||||||
std::string::size_type nLineStart = strContent.rfind('\n', nNamePos);
|
std::string::size_type nLineStart = strContent.rfind('\n', nNamePos);
|
||||||
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1;
|
||||||
std::string strIndent = strContent.substr(nLineStart, nNamePos - nLineStart);
|
std::string strIndent = strContent.substr(nLineStart, nNamePos - nLineStart);
|
||||||
|
|
||||||
// 找到 name= 行末
|
// 找到 name= 行末
|
||||||
std::string::size_type nLineEnd = strContent.find('\n', nNamePos);
|
std::string::size_type nLineEnd = strContent.find('\n', nNamePos);
|
||||||
if (nLineEnd == std::string::npos) nLineEnd = strContent.size() - 1;
|
if (nLineEnd == std::string::npos) nLineEnd = strContent.size() - 1;
|
||||||
|
|
||||||
// 在 name= 行后插入 version=
|
// 在 name= 行后插入 version=
|
||||||
std::string strInsert = "\n" + strIndent + strNewValue + ",";
|
std::string strInsert = "\n" + strIndent + strNewValue + ",";
|
||||||
strContent.insert(nLineEnd, strInsert);
|
strContent.insert(nLineEnd, strInsert);
|
||||||
_tprintf(_T("成功: 已向 spec 文件新增 version 字段 -> version_info.txt\n"));
|
_tprintf(_T("成功: 已向 spec 文件新增 version 字段 -> version_info.txt\n"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_tprintf(_T("警告: spec 文件中未找到 version= 或 name= 参数,跳过版本信息注入。\n"));
|
_tprintf(_T("警告: spec 文件中未找到 version= 或 name= 参数,跳过版本信息注入。\n"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写回文件
|
// 写回文件
|
||||||
if (!myFile.Open(lpSpecPath, CFile::modeCreate | CFile::modeWrite, &fileEx))
|
if (!myFile.Open(lpSpecPath, CFile::modeCreate | CFile::modeWrite, &fileEx))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: 无法写入 spec 文件 %s\n"), lpSpecPath);
|
_tprintf(_T("错误: 无法写入 spec 文件 %s\n"), lpSpecPath);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
myFile.Write(strContent.c_str(), (UINT)strContent.size());
|
myFile.Write(strContent.c_str(), (UINT)strContent.size());
|
||||||
@@ -260,8 +260,8 @@ static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 .spec 文件读取 version= 参数的值(单/双引号括起的路径)
|
// 从 .spec 文件读取 version= 参数的值(单/双引号括起的路径)
|
||||||
// 返回 FALSE 表示未找到、值为 None 或值为空
|
// 返回 FALSE 表示未找到、值为 None 或值为空
|
||||||
static BOOL ReadVersionPathFromSpec(LPCTSTR lpSpecPath, CString& strVersionPath)
|
static BOOL ReadVersionPathFromSpec(LPCTSTR lpSpecPath, CString& strVersionPath)
|
||||||
{
|
{
|
||||||
strVersionPath.Empty();
|
strVersionPath.Empty();
|
||||||
@@ -303,14 +303,14 @@ static BOOL ReadVersionPathFromSpec(LPCTSTR lpSpecPath, CString& strVersionPath)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break; // version=None 或空值,视为无
|
break; // version=None 或空值,视为无
|
||||||
}
|
}
|
||||||
nPos += 8;
|
nPos += 8;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新已有 version_info 文件的版本字段;若文件不存在则创建
|
// 更新已有 version_info 文件的版本字段;若文件不存在则创建
|
||||||
static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion)
|
static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion)
|
||||||
{
|
{
|
||||||
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0;
|
||||||
@@ -325,7 +325,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
|
|
||||||
if (!PathFileExists(lpPath))
|
if (!PathFileExists(lpPath))
|
||||||
{
|
{
|
||||||
// 文件不存在,直接创建
|
// 文件不存在,直接创建
|
||||||
FILE* fp = NULL;
|
FILE* fp = NULL;
|
||||||
_tfopen_s(&fp, lpPath, _T("wb"));
|
_tfopen_s(&fp, lpPath, _T("wb"));
|
||||||
if (!fp) return FALSE;
|
if (!fp) return FALSE;
|
||||||
@@ -369,7 +369,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取现有文件并就地更新版本字段
|
// 读取现有文件并就地更新版本字段
|
||||||
CFile myFile;
|
CFile myFile;
|
||||||
CFileException fileEx;
|
CFileException fileEx;
|
||||||
if (!myFile.Open(lpPath, CFile::modeReadWrite, &fileEx)) return FALSE;
|
if (!myFile.Open(lpPath, CFile::modeReadWrite, &fileEx)) return FALSE;
|
||||||
@@ -381,7 +381,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
std::string s(buf.data(), dwLen);
|
std::string s(buf.data(), dwLen);
|
||||||
char szNew[128];
|
char szNew[128];
|
||||||
|
|
||||||
// 更新 filevers 元组
|
// 更新 filevers 元组
|
||||||
{
|
{
|
||||||
const std::string key = "filevers=(";
|
const std::string key = "filevers=(";
|
||||||
auto p = s.find(key);
|
auto p = s.find(key);
|
||||||
@@ -394,7 +394,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新 prodvers 元组
|
// 更新 prodvers 元组
|
||||||
{
|
{
|
||||||
const std::string key = "prodvers=(";
|
const std::string key = "prodvers=(";
|
||||||
auto p = s.find(key);
|
auto p = s.find(key);
|
||||||
@@ -407,7 +407,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新 FileVersion 字符串值
|
// 更新 FileVersion 字符串值
|
||||||
{
|
{
|
||||||
const std::string key = "u'FileVersion', u'";
|
const std::string key = "u'FileVersion', u'";
|
||||||
auto p = s.find(key);
|
auto p = s.find(key);
|
||||||
@@ -418,7 +418,7 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
s.replace(pValStart, pValEnd - pValStart, szFileVer);
|
s.replace(pValStart, pValEnd - pValStart, szFileVer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 更新 ProductVersion 字符串值
|
// 更新 ProductVersion 字符串值
|
||||||
{
|
{
|
||||||
const std::string key = "u'ProductVersion', u'";
|
const std::string key = "u'ProductVersion', u'";
|
||||||
auto p = s.find(key);
|
auto p = s.find(key);
|
||||||
@@ -438,13 +438,16 @@ static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCT
|
|||||||
|
|
||||||
int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
||||||
{
|
{
|
||||||
// 解析 pid(内嵌在 argv[1] 中,如 "pyinstaller=5")
|
#ifdef _DEBUG
|
||||||
// "pyinstaller=" 为 13 个字符
|
Sleep(15000);
|
||||||
CString strPid = CString(argv[1]).Mid(13);
|
#endif
|
||||||
|
// 解析 pid(内嵌在 argv[1] 中,如 "pyinstaller=5")
|
||||||
|
// "pyinstaller=" 为 12 个字符
|
||||||
UINT nPid = 0;
|
UINT nPid = 0;
|
||||||
|
CString strPid = CString(argv[1]).Mid(12);
|
||||||
if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid))
|
if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: pyinstaller= 后的 pid 无效:%s,应为 0-65535 范围的整数。\n"), strPid.GetString());
|
_tprintf(_T("错误: pyinstaller= 后的 pid 无效:%s,应为 0-65535 范围的整数。\n"), strPid.GetString());
|
||||||
return 41;
|
return 41;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,6 +471,7 @@ int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
|||||||
strFileVersion,
|
strFileVersion,
|
||||||
DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER,
|
DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER,
|
||||||
DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER);
|
DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER);
|
||||||
|
|
||||||
if (nVersionRet != 0)
|
if (nVersionRet != 0)
|
||||||
{
|
{
|
||||||
return nVersionRet;
|
return nVersionRet;
|
||||||
@@ -481,32 +485,31 @@ int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
|||||||
{
|
{
|
||||||
strProductVersion = strProductVersion.Left(nDot2 + 1) + _T("0.0");
|
strProductVersion = strProductVersion.Left(nDot2 + 1) + _T("0.0");
|
||||||
}
|
}
|
||||||
_tprintf(_T("[test] 测试版本号: ProductVersion=%s\n"), strProductVersion.GetString());
|
_tprintf(_T("[test] 测试版本号: ProductVersion=%s\n"), strProductVersion.GetString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测是否为 spec 模式,若是则生成 version_info.txt 并注入/更新 spec
|
// 检测是否为 spec 模式,若是则生成 version_info.txt 并注入/更新 spec
|
||||||
CString strFirstToken = ExtractFirstToken(strExtraArgs);
|
CString strFirstToken = ExtractFirstToken(strExtraArgs);
|
||||||
BOOL bIsSpec = (strFirstToken.GetLength() >= 5
|
BOOL bIsSpec = (strFirstToken.GetLength() >= 5 && strFirstToken.Right(5).CompareNoCase(_T(".spec")) == 0);
|
||||||
&& strFirstToken.Right(5).CompareNoCase(_T(".spec")) == 0);
|
|
||||||
if (bIsSpec)
|
if (bIsSpec)
|
||||||
{
|
{
|
||||||
// 解析 spec 文件完整路径
|
// 解析 spec 文件完整路径
|
||||||
CString strSpecPath;
|
CString strSpecPath;
|
||||||
if (PathIsRelative(strFirstToken))
|
if (PathIsRelative(strFirstToken))
|
||||||
strSpecPath.Format(_T("%s\\%s"), lpRepoPath, strFirstToken.GetString());
|
strSpecPath.Format(_T("%s\\%s"), lpRepoPath, strFirstToken.GetString());
|
||||||
else
|
else
|
||||||
strSpecPath = strFirstToken;
|
strSpecPath = strFirstToken;
|
||||||
|
|
||||||
// 获取 spec 所在目录
|
// 获取 spec 所在目录
|
||||||
TCHAR szSpecDir[MAX_PATH] = {};
|
TCHAR szSpecDir[MAX_PATH] = {};
|
||||||
_tcscpy_s(szSpecDir, strSpecPath.GetString());
|
_tcscpy_s(szSpecDir, strSpecPath.GetString());
|
||||||
PathRemoveFileSpec(szSpecDir);
|
PathRemoveFileSpec(szSpecDir);
|
||||||
|
|
||||||
// 检查 spec 是否已指定版本信息文件
|
// 检查 spec 是否已指定版本信息文件
|
||||||
CString strExistingVersionPath;
|
CString strExistingVersionPath;
|
||||||
if (ReadVersionPathFromSpec(strSpecPath, strExistingVersionPath))
|
if (ReadVersionPathFromSpec(strSpecPath, strExistingVersionPath))
|
||||||
{
|
{
|
||||||
// spec 已有 version=,直接更新所指向的文件(不存在则创建)
|
// spec 已有 version=,直接更新所指向的文件(不存在则创建)
|
||||||
CString strVersionInfoFullPath;
|
CString strVersionInfoFullPath;
|
||||||
if (PathIsRelative(strExistingVersionPath))
|
if (PathIsRelative(strExistingVersionPath))
|
||||||
strVersionInfoFullPath.Format(_T("%s\\%s"), szSpecDir, strExistingVersionPath.GetString());
|
strVersionInfoFullPath.Format(_T("%s\\%s"), szSpecDir, strExistingVersionPath.GetString());
|
||||||
@@ -515,45 +518,43 @@ int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[])
|
|||||||
|
|
||||||
if (!UpdateVersionInfoFile(strVersionInfoFullPath, strProductVersion, strFileVersion))
|
if (!UpdateVersionInfoFile(strVersionInfoFullPath, strProductVersion, strFileVersion))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: 无法更新版本信息文件: %s。\n"), strVersionInfoFullPath.GetString());
|
_tprintf(_T("错误: 无法更新版本信息文件: %s。\n"), strVersionInfoFullPath.GetString());
|
||||||
return 45;
|
return 45;
|
||||||
}
|
}
|
||||||
_tprintf(_T("版本信息文件已更新: %s\n"), strVersionInfoFullPath.GetString());
|
_tprintf(_T("版本信息文件已更新: %s\n"), strVersionInfoFullPath.GetString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// spec 未指定 version=,生成 version_info.txt 并注入 spec
|
// spec 未指定 version=,生成 version_info.txt 并注入 spec
|
||||||
CString strVersionInfoPath;
|
CString strVersionInfoPath;
|
||||||
if (!WriteVersionInfoFile(szSpecDir, strProductVersion, strFileVersion, strVersionInfoPath))
|
if (!WriteVersionInfoFile(szSpecDir, strProductVersion, strFileVersion, strVersionInfoPath))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: 无法生成 version_info.txt(目录: %s)。\n"), szSpecDir);
|
_tprintf(_T("错误: 无法生成 version_info.txt(目录: %s)。\n"), szSpecDir);
|
||||||
return 45;
|
return 45;
|
||||||
}
|
}
|
||||||
_tprintf(_T("版本信息文件已生成: %s\n"), strVersionInfoPath.GetString());
|
_tprintf(_T("版本信息文件已生成: %s\n"), strVersionInfoPath.GetString());
|
||||||
|
|
||||||
if (!InjectVersionIntoSpec(strSpecPath))
|
if (!InjectVersionIntoSpec(strSpecPath))
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: 无法修改 spec 文件: %s。\n"), strSpecPath.GetString());
|
_tprintf(_T("错误: 无法修改 spec 文件: %s。\n"), strSpecPath.GetString());
|
||||||
return 46;
|
return 46;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_tprintf(_T("PyInstaller 打包开始..\n"));
|
_tprintf(_T("PyInstaller 打包开始..\n"));
|
||||||
_tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString());
|
_tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString());
|
||||||
_tprintf(_T("FileVersion=%s\n"), strFileVersion.GetString());
|
_tprintf(_T("FileVersion=%s\n"), strFileVersion.GetString());
|
||||||
|
|
||||||
CString strCmd;
|
CString strCmd;
|
||||||
strCmd.Format(
|
strCmd.Format(_T("cmd /c python -m PyInstaller %s"),strExtraArgs.GetString());
|
||||||
_T("cmd /c python -m PyInstaller %s"),
|
|
||||||
strExtraArgs.GetString());
|
|
||||||
|
|
||||||
CString strBuildResult = StartProcess(NULL, strCmd.GetBuffer(), lpRepoPath);
|
CString strBuildResult = StartProcess(NULL, strCmd.GetBuffer(), lpRepoPath);
|
||||||
strCmd.ReleaseBuffer();
|
strCmd.ReleaseBuffer();
|
||||||
|
|
||||||
if (strBuildResult.IsEmpty())
|
if (strBuildResult.IsEmpty())
|
||||||
{
|
{
|
||||||
_tprintf(_T("错误: PyInstaller 打包失败。\n"));
|
_tprintf(_T("错误: PyInstaller 打包失败。\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
93
README.md
93
README.md
@@ -368,6 +368,99 @@ exe = EXE(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**完整 spec 文件示例(`myapp.spec`):**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
block_cipher = None
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['src\\main.py'], # 入口脚本
|
||||||
|
pathex=[],
|
||||||
|
binaries=[],
|
||||||
|
datas=[
|
||||||
|
('assets', 'assets'), # 额外资源目录:源路径, 目标路径
|
||||||
|
],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
win_no_prefer_redirects=False,
|
||||||
|
win_private_assemblies=False,
|
||||||
|
cipher=block_cipher,
|
||||||
|
noarchive=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.zipfiles,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='MyApp',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False, # True=控制台程序,False=GUI程序
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon='assets\\app.ico', # 图标文件路径
|
||||||
|
version='version_info.txt', # Windows 版本信息文件
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**配套的 `version_info.txt` 示例:**
|
||||||
|
|
||||||
|
```python
|
||||||
|
# UTF-8
|
||||||
|
# Windows EXE 版本信息文件
|
||||||
|
# 版本号格式:major, minor, patch, build(均为整数)
|
||||||
|
|
||||||
|
VSVersionInfo(
|
||||||
|
ffi=FixedFileInfo(
|
||||||
|
filevers=(5, 0, 1920, 11), # FileVersion,对应 FileVersion=5.0.1920.11
|
||||||
|
prodvers=(5, 0, 1920, 11), # ProductVersion
|
||||||
|
mask=0x3f,
|
||||||
|
flags=0x0,
|
||||||
|
OS=0x40004,
|
||||||
|
fileType=0x1, # 0x1=EXE, 0x2=DLL
|
||||||
|
subtype=0x0,
|
||||||
|
date=(0, 0),
|
||||||
|
),
|
||||||
|
kids=[
|
||||||
|
StringFileInfo([
|
||||||
|
StringTable(
|
||||||
|
'040904B0', # 语言 0409=英语, 04B0=Unicode
|
||||||
|
[
|
||||||
|
StringStruct('CompanyName', 'MyCompany'),
|
||||||
|
StringStruct('FileDescription', 'MyApp Application'),
|
||||||
|
StringStruct('FileVersion', '5.0.1920.11'),
|
||||||
|
StringStruct('InternalName', 'MyApp'),
|
||||||
|
StringStruct('LegalCopyright', 'Copyright (C) 2026 MyCompany'),
|
||||||
|
StringStruct('OriginalFilename', 'MyApp.exe'),
|
||||||
|
StringStruct('ProductName', 'MyApp'),
|
||||||
|
StringStruct('ProductVersion', '5.0.1920.11'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
VarFileInfo([VarStruct('Translation', [0x0409, 0x04B0])])
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
> `version_info.txt` 中的版本号需与实际构建版本保持一致。如需自动同步,可在构建脚本中先调用 `gitver setver=<pid>` 获取版本,再用脚本替换 `version_info.txt` 中的版本字段,然后执行 `gitver pyinstaller=<pid> params="myapp.spec"`。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 错误码
|
## 错误码
|
||||||
|
|||||||
Reference in New Issue
Block a user