From d36618d1015fbe864cb35d67b769f086d2ae1ea1 Mon Sep 17 00:00:00 2001 From: Jeff <632006142@qq.com> Date: Wed, 20 May 2026 15:59:51 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E6=94=AF=E6=8C=81pyinstaller?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=96=B9=E5=BC=8F=202=E3=80=81=E5=B0=86pytho?= =?UTF-8?q?n=E6=89=93=E5=8C=85=E5=85=B6=E4=BB=96=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=83=BD=E6=94=BE=E5=85=A5params=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GitVer/GitVer.cpp | 54 +++- GitVer/GitVer.vcxproj | 2 + GitVer/GitVer.vcxproj.filters | 6 + GitVer/GitVer_nuitka.cpp | 28 +- GitVer/GitVer_pyinstaller.cpp | 560 ++++++++++++++++++++++++++++++++++ GitVer/GitVer_pyinstaller.h | 3 + README.md | 235 ++++++++++++-- 7 files changed, 829 insertions(+), 59 deletions(-) create mode 100644 GitVer/GitVer_pyinstaller.cpp create mode 100644 GitVer/GitVer_pyinstaller.h diff --git a/GitVer/GitVer.cpp b/GitVer/GitVer.cpp index d5f5d45..acaf85b 100644 --- a/GitVer/GitVer.cpp +++ b/GitVer/GitVer.cpp @@ -7,6 +7,7 @@ #include "gitver_common.h" #include "gitver_cli.h" #include "gitver_nuitka.h" +#include "gitver_pyinstaller.h" #include "gitver_process.h" #include "gitver_rewrite.h" #include "gitver_tag.h" @@ -350,8 +351,9 @@ void PrintFullUsageExamples() _T(" gitver (显示帮助后进入当前分支创建 tag 流程)\n") _T(" gitver rewrite [PEType可选] [-f可选]\n") _T(" gitver setver= [repodir=可选] [-test可选]\n") - _T(" gitver nuitkabuild= [repodir=可选] [-test可选] [params=\"\"可选]\n") - _T(" gitver nuitkapydbuild= [repodir=可选] [-test可选] [params=\"\"可选]\n") + _T(" gitver nuitkabuild= [repodir=可选] [-test可选] [params=\" \"可选]\n") + _T(" gitver nuitkapydbuild= [repodir=可选] [-test可选] [params=\" \"可选]\n") + _T(" gitver pyinstaller= [repodir=可选] [-test可选] [params=\" \"可选]\n") _T(" gitver -setup=0|1 [pid] [repodir=可选] [-test可选]\n") _T(" -setup=0: 使用 Inno Setup 脚本 (setup.iss)\n") _T(" -setup=1: 使用 NSIS 脚本 (setup.nsh)\n") @@ -363,15 +365,21 @@ void PrintFullUsageExamples() _T(" gitver setver=5 repodir=E:\\Code\\OTH\\gitver\n") _T(" gitver setver=5\n") _T(" gitver setver=5 -test\n") - _T(" gitver nuitkabuild=5 main.py\n") - _T(" gitver nuitkabuild=5 main.py -test\n") - _T(" gitver nuitkabuild=5 src\\app.py repodir=E:\\Code\\MyPyProj params=\"--standalone --output-dir=dist\"\n") - _T(" gitver nuitkapydbuild=5 module.py\n") - _T(" gitver nuitkapydbuild=5 module.py -test\n") - _T(" gitver nuitkapydbuild=5 src\\core.py repodir=E:\\Code\\MyPyProj params=\"--output-dir=dist\"\n") + _T(" gitver nuitkabuild=5 params=\"main.py\"\n") + _T(" gitver nuitkabuild=5 -test params=\"main.py\"\n") + _T(" gitver nuitkabuild=5 repodir=E:\\Code\\MyPyProj params=\"src\\\\app.py --standalone --output-dir=dist\"\n") + _T(" gitver nuitkapydbuild=5 params=\"module.py\"\n") + _T(" gitver nuitkapydbuild=5 -test params=\"module.py\"\n") + _T(" gitver nuitkapydbuild=5 repodir=E:\\Code\\MyPyProj params=\"src\\\\core.py --output-dir=dist\"\n") + _T(" gitver pyinstaller=5 params=\"main.py\"\n") + _T(" gitver pyinstaller=5 -test params=\"main.py\"\n") + _T(" gitver pyinstaller=5 repodir=E:\\Code\\MyPyProj params=\"src\\\\app.py --onefile --name=MyApp\"\n") + _T(" gitver pyinstaller=5 params=\"myapp.spec\"\n") + _T(" gitver pyinstaller=5 -test params=\"myapp.spec\"\n") + _T(" gitver pyinstaller=5 repodir=E:\\Code\\MyPyProj params=\"myapp.spec\"\n") _T(" gitver -setup=0 5\n") _T(" gitver -setup=1 5 repodir=E:\\Code\\MyProj\n") - _T("params: 传递给 Nuitka 的额外参数,用双引号括起来,如 params=\"--standalone --output-dir=dist\"。\n") + _T("params: 传递给 Nuitka/PyInstaller 的参数(含入口文件),用双引号括起来,如 params=\"main.py --standalone --output-dir=dist\"。\n") _T("-test: 将产品版本号的 major 和 minor 都置为 0(用于测试版本构建)。\n") _T("无参数时会读取当前分支最近三次 tag,并提示选择 major 加 1 或 minor 加 1,然后创建新 tag。\n") _T("未找到当前分支 tag 时自动使用默认版本 1.0。\n"); @@ -386,8 +394,9 @@ void PrintShortCommandUsage() { _tprintf(_T("请使用:gitver rewrite [PE类型可选]\n")); _tprintf(_T("请使用:gitver setver= [repodir=可选]\n")); - _tprintf(_T("或:gitver nuitkabuild= [repodir=可选] [params=\"\"可选]\n")); - _tprintf(_T("或:gitver nuitkapydbuild= [repodir=可选] [params=\"\"可选]\n")); + _tprintf(_T("或:gitver nuitkabuild= [repodir=可选] [params=\" \"可选]\n")); + _tprintf(_T("或:gitver nuitkapydbuild= [repodir=可选] [params=\" \"可选]\n")); + _tprintf(_T("或:gitver pyinstaller= [repodir=可选] [params=\" \"可选]\n")); } /// @@ -482,6 +491,20 @@ LPCTSTR GetExitCodeHint(int nRetCode) return _T("setup: modify setup script failed"); case 39: return _T("setup: compiler not found"); + case 40: + return _T("pyinstaller: missing args"); + case 41: + return _T("pyinstaller: invalid pid"); + case 42: + return _T("pyinstaller: get branch or bid failed"); + case 43: + return _T("pyinstaller: get tag failed"); + case 44: + return _T("pyinstaller: get today commit count failed"); + case 45: + return _T("pyinstaller: write version_info.txt failed"); + case 46: + return _T("pyinstaller: inject version into spec file failed"); default: return _T(""); } @@ -891,6 +914,15 @@ int main(int argc, TCHAR* argv[], TCHAR* envp[]) return nCmdRet; } + if (argc >= 2 && _tcsnicmp(argv[1], _T("pyinstaller="), 12) == 0) + { + DWORD dwStartTick = LogCommandStart(_T("pyinstaller")); + int nCmdRet = HandlePyinstallerBuildCommand(argc, argv); + LogCommandEnd(_T("pyinstaller"), dwStartTick, nCmdRet); + PrintCommandFailedWithCode(_T("pyinstaller"), nCmdRet); + return nCmdRet; + } + if (argc >= 2 && _tcsnicmp(argv[1], _T("-setup="), 7) == 0) { DWORD dwStartTick = LogCommandStart(_T("-setup")); diff --git a/GitVer/GitVer.vcxproj b/GitVer/GitVer.vcxproj index 6ff3fcc..ab2fac7 100644 --- a/GitVer/GitVer.vcxproj +++ b/GitVer/GitVer.vcxproj @@ -149,6 +149,7 @@ + @@ -164,6 +165,7 @@ + diff --git a/GitVer/GitVer.vcxproj.filters b/GitVer/GitVer.vcxproj.filters index cc8cf05..ca3691f 100644 --- a/GitVer/GitVer.vcxproj.filters +++ b/GitVer/GitVer.vcxproj.filters @@ -39,6 +39,9 @@ 澶存枃浠 + + 澶存枃浠 + 澶存枃浠 @@ -71,6 +74,9 @@ 婧愭枃浠 + + 婧愭枃浠 + 婧愭枃浠 diff --git a/GitVer/GitVer_nuitka.cpp b/GitVer/GitVer_nuitka.cpp index f49f8e5..02fa5e9 100644 --- a/GitVer/GitVer_nuitka.cpp +++ b/GitVer/GitVer_nuitka.cpp @@ -8,8 +8,6 @@ extern TCHAR g_szCurModuleDir[MAX_PATH]; -void PrintCommandUsageAndExamples(LPCTSTR lpCommand, LPCTSTR lpRequiredArgs, LPCTSTR lpEntryExample); - const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_NUITKA = 1; const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_NUITKA = 0; @@ -19,7 +17,7 @@ static int ParseNuitkaOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, CStr strExtraArgs.Empty(); bTestMode = FALSE; - for (int i = 3; i < argc; ++i) + for (int i = 2; i < argc; ++i) { CString strArg = argv[i]; @@ -95,8 +93,6 @@ static int HandleNuitkaBuildCommandCore( BOOL bBuildModule, LPCTSTR lpStartMessage, LPCTSTR lpUsageName, - LPCTSTR lpEntryArgName, - int nArgLackErrorCode, int nPidErrorCode, int nBidErrorCode, int nTagErrorCode, @@ -111,14 +107,6 @@ static int HandleNuitkaBuildCommandCore( return nPidErrorCode; } - if (argc < 3) - { - _tprintf(_T("错误: 参数不足,缺少 %s。\n"), lpEntryArgName); - _tprintf(_T("用法:gitver %s= <%s> [repodir=可选] [-test可选] [params=\"\"\u53ef选]\n"), lpUsageName, lpEntryArgName); - return nArgLackErrorCode; - } - - CString strMainOrModulePy = argv[2]; LPCTSTR lpRepoPath = NULL; CString strExtraArgs; BOOL bTestMode = FALSE; @@ -159,20 +147,18 @@ static int HandleNuitkaBuildCommandCore( if (bBuildModule) { strNuitkaCmd.Format( - _T("cmd /c python -m nuitka --module --windows-product-version=%s --windows-file-version=%s %s %s"), + _T("cmd /c python -m nuitka --module --windows-product-version=%s --windows-file-version=%s %s"), strProductVersion.GetString(), strFileVersion.GetString(), - strExtraArgs.GetString(), - QuoteCmdArg(strMainOrModulePy).GetString()); + strExtraArgs.GetString()); } else { strNuitkaCmd.Format( - _T("cmd /c python -m nuitka --windows-product-version=%s --windows-file-version=%s %s %s"), + _T("cmd /c python -m nuitka --windows-product-version=%s --windows-file-version=%s %s"), strProductVersion.GetString(), strFileVersion.GetString(), - strExtraArgs.GetString(), - QuoteCmdArg(strMainOrModulePy).GetString()); + strExtraArgs.GetString()); } RunNuitkaBuild(lpStartMessage, strNuitkaCmd, strProductVersion, strFileVersion, lpRepoPath); @@ -188,8 +174,6 @@ int HandleNuitkaBuildCommand(int argc, TCHAR* argv[]) FALSE, _T("Nuitka 打包开始.."), _T("nuitkabuild"), - _T("mainPy"), - 17, 18, 19, 20, @@ -205,8 +189,6 @@ int HandleNuitkaPydBuildCommand(int argc, TCHAR* argv[]) TRUE, _T("Nuitka pyd 打包开始.."), _T("nuitkapydbuild"), - _T("modulePy"), - 24, 25, 26, 27, diff --git a/GitVer/GitVer_pyinstaller.cpp b/GitVer/GitVer_pyinstaller.cpp new file mode 100644 index 0000000..1570135 --- /dev/null +++ b/GitVer/GitVer_pyinstaller.cpp @@ -0,0 +1,560 @@ +#include "pch.h" +#include "gitver.h" +#include "gitver_cli.h" +#include "gitver_common.h" +#include "gitver_process.h" +#include "gitver_version.h" +#include "gitver_pyinstaller.h" + +extern TCHAR g_szCurModuleDir[MAX_PATH]; + +const UINT DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER = 1; +const UINT DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER = 0; + +static int ParsePyinstallerOptions(int argc, TCHAR* argv[], LPCTSTR& lpRepoPath, CString& strExtraArgs, BOOL& bTestMode) +{ + lpRepoPath = NULL; + strExtraArgs.Empty(); + bTestMode = FALSE; + + for (int i = 2; i < argc; ++i) + { + CString strArg = argv[i]; + + if (strArg.CompareNoCase(_T("-test")) == 0) + { + bTestMode = TRUE; + continue; + } + + if (strArg.GetLength() > 8 && strArg.Left(8).CompareNoCase(_T("repodir=")) == 0) + { + if (lpRepoPath != NULL) + { + _tprintf(_T("閿欒: repodir 鍙傛暟閲嶅: %s\n"), argv[i]); + return 23; + } + LPCTSTR lpPath = argv[i] + 8; + if (!PathIsDirectory(lpPath)) + { + PrintInvalidRepoPathError(lpPath); + return 23; + } + lpRepoPath = lpPath; + continue; + } + + if (strArg.GetLength() > 7 && strArg.Left(7).CompareNoCase(_T("params=")) == 0) + { + if (!strExtraArgs.IsEmpty()) + { + _tprintf(_T("閿欒: params 鍙傛暟閲嶅銆俓n")); + return 3; + } + CString strVal = strArg.Mid(7); + // 鍘绘帀澶栧眰鍙屽紩鍙凤紙濡 params="--onefile"锛 + if (strVal.GetLength() >= 2 && strVal[0] == _T('"') && strVal[strVal.GetLength() - 1] == _T('"')) + strVal = strVal.Mid(1, strVal.GetLength() - 2); + strExtraArgs = strVal; + continue; + } + + _tprintf(_T("閿欒: 鏈煡鐨勫弬鏁 %s\n"), argv[i]); + return 3; + } + + if (lpRepoPath == NULL) + { + lpRepoPath = g_szCurModuleDir; + } + + return 0; +} + +// 瑙f瀽鐗堟湰瀛楃涓 "a.b.c.d" 鈫 鍥涗釜鍒嗛噺 +static BOOL ParseVersionTuple(LPCTSTR lpVer, UINT& v1, UINT& v2, UINT& v3, UINT& v4) +{ + CString str(lpVer); + int p1 = str.Find(_T('.')); + if (p1 < 0) return FALSE; + int p2 = str.Find(_T('.'), p1 + 1); + if (p2 < 0) return FALSE; + int p3 = str.Find(_T('.'), p2 + 1); + if (p3 < 0) return FALSE; + v1 = (UINT)_ttoi(str.Left(p1)); + v2 = (UINT)_ttoi(str.Mid(p1 + 1, p2 - p1 - 1)); + v3 = (UINT)_ttoi(str.Mid(p2 + 1, p3 - p2 - 1)); + v4 = (UINT)_ttoi(str.Mid(p3 + 1)); + return TRUE; +} + +// 鎻愬彇 params 涓涓涓┖鏍煎垎闅旂殑 token锛堟敮鎸佸弻寮曞彿鎷捣鐨勮矾寰勶級 +static CString ExtractFirstToken(const CString& strParams) +{ + CString str = strParams; + str.TrimLeft(); + if (str.IsEmpty()) return _T(""); + if (str[0] == _T('"')) + { + int nEnd = str.Find(_T('"'), 1); + if (nEnd < 0) return str.Mid(1); + return str.Mid(1, nEnd - 1); + } + int nSpace = str.Find(_T(' ')); + if (nSpace < 0) return str; + return str.Left(nSpace); +} + +// 鐢熸垚 version_info.txt 鍒 lpDir 鐩綍锛圥yInstaller VSVersionInfo 鏍煎紡锛 +static BOOL WriteVersionInfoFile(LPCTSTR lpDir, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion, CString& strOutPath) +{ + UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0; + UINT fv1 = 0, fv2 = 0, fv3 = 0, fv4 = 0; + if (!ParseVersionTuple(lpProductVersion, pv1, pv2, pv3, pv4)) return FALSE; + if (!ParseVersionTuple(lpFileVersion, fv1, fv2, fv3, fv4)) return FALSE; + + CStringA strProdVerA(lpProductVersion); + CStringA strFileVerA(lpFileVersion); + const char* szProdVer = strProdVerA; + const char* szFileVer = strFileVerA; + + strOutPath.Format(_T("%s\\version_info.txt"), lpDir); + + FILE* fp = NULL; + _tfopen_s(&fp, strOutPath.GetString(), _T("wb")); + if (!fp) return FALSE; + + fprintf(fp, + "# UTF-8\n" + "VSVersionInfo(\n" + " ffi=FixedFileInfo(\n" + " filevers=(%u, %u, %u, %u),\n" + " prodvers=(%u, %u, %u, %u),\n" + " mask=0x3f,\n" + " flags=0x0,\n" + " OS=0x40004,\n" + " fileType=0x1,\n" + " subtype=0x0,\n" + " date=(0, 0)\n" + " ),\n" + " kids=[\n" + " StringFileInfo([\n" + " StringTable(\n" + " u'040904B0',\n" + " [StringStruct(u'CompanyName', u''),\n" + " StringStruct(u'FileDescription', u''),\n" + " StringStruct(u'FileVersion', u'%s'),\n" + " StringStruct(u'InternalName', u''),\n" + " StringStruct(u'LegalCopyright', u''),\n" + " StringStruct(u'OriginalFilename', u''),\n" + " StringStruct(u'ProductName', u''),\n" + " StringStruct(u'ProductVersion', u'%s'),\n" + " StringStruct(u'Comments', u''),\n" + " StringStruct(u'LegalTrademarks', u''),\n" + " ])\n" + " ]),\n" + " VarFileInfo([VarStruct(u'Translation', [0x0409, 1200])])\n" + " ]\n" + ")\n", + fv1, fv2, fv3, fv4, + pv1, pv2, pv3, pv4, + szFileVer, + szProdVer); + + fclose(fp); + return TRUE; +} + +// 鍚 .spec 鏂囦欢娉ㄥ叆鎴栨洿鏂 version= 鍙傛暟 +// 鑻ュ凡鏈 version= 鍒欐洿鏂板叾鍊硷紝鍚﹀垯鍦 name= 鍙傛暟鍚庢柊澧炰竴琛 +static BOOL InjectVersionIntoSpec(LPCTSTR lpSpecPath) +{ + if (!PathFileExists(lpSpecPath)) + { + _tprintf(_T("閿欒: spec 鏂囦欢涓嶅瓨鍦 %s\n"), lpSpecPath); + return FALSE; + } + + CFile myFile; + CFileException fileEx; + if (!myFile.Open(lpSpecPath, CFile::modeReadWrite, &fileEx)) + { + _tprintf(_T("閿欒: 鏃犳硶鎵撳紑 spec 鏂囦欢 %s\n"), lpSpecPath); + return FALSE; + } + + DWORD dwLen = (DWORD)myFile.GetLength(); + std::vector buf(dwLen + 1, 0); + myFile.Read(buf.data(), dwLen); + myFile.Close(); + + std::string strContent(buf.data(), dwLen); + const std::string strNewValue = "version='version_info.txt'"; + + bool bFound = false; + std::string::size_type nPos = 0; + while ((nPos = strContent.find("version=", nPos)) != std::string::npos) + { + // 纭繚 version= 鏄嫭绔嬪弬鏁帮紙鍓嶉┍瀛楃涓虹┖鐧芥垨鎹㈣锛岃岄潪瀛楁瘝/鏁板瓧锛 + bool bIsParam = (nPos == 0 + || strContent[nPos - 1] == '\n' + || strContent[nPos - 1] == '\r' + || strContent[nPos - 1] == ' ' + || strContent[nPos - 1] == '\t'); + if (bIsParam) + { + // 鑾峰彇琛岄锛堜繚鐣欑缉杩涳級 + std::string::size_type nLineStart = strContent.rfind('\n', nPos); + nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1; + std::string strIndent = strContent.substr(nLineStart, nPos - nLineStart); + + // 鑾峰彇琛屾湯 + std::string::size_type nLineEnd = strContent.find('\n', nPos); + if (nLineEnd == std::string::npos) nLineEnd = strContent.size(); + + // 鏇挎崲鏁磋锛堜繚鐣欑缉杩涳紝缁熶竴鍔犲熬闅忛楀彿锛 + std::string strNewLine = strIndent + strNewValue + ","; + strContent.replace(nLineStart, nLineEnd - nLineStart, strNewLine); + _tprintf(_T("鎴愬姛: 宸叉洿鏂 spec 鏂囦欢 version 瀛楁 -> version_info.txt\n")); + bFound = true; + break; + } + nPos += 8; // len("version=") + } + + if (!bFound) + { + // 鏈壘鍒 version=锛屽湪 name= 鍙傛暟鍚庢彃鍏ユ柊琛 + std::string::size_type nNamePos = strContent.find("name="); + if (nNamePos != std::string::npos) + { + // 鑾峰彇 name= 琛岀殑缂╄繘 + std::string::size_type nLineStart = strContent.rfind('\n', nNamePos); + nLineStart = (nLineStart == std::string::npos) ? 0 : nLineStart + 1; + std::string strIndent = strContent.substr(nLineStart, nNamePos - nLineStart); + + // 鎵惧埌 name= 琛屾湯 + std::string::size_type nLineEnd = strContent.find('\n', nNamePos); + if (nLineEnd == std::string::npos) nLineEnd = strContent.size() - 1; + + // 鍦 name= 琛屽悗鎻掑叆 version= + std::string strInsert = "\n" + strIndent + strNewValue + ","; + strContent.insert(nLineEnd, strInsert); + _tprintf(_T("鎴愬姛: 宸插悜 spec 鏂囦欢鏂板 version 瀛楁 -> version_info.txt\n")); + } + else + { + _tprintf(_T("璀﹀憡: spec 鏂囦欢涓湭鎵惧埌 version= 鎴 name= 鍙傛暟锛岃烦杩囩増鏈俊鎭敞鍏ャ俓n")); + } + } + + // 鍐欏洖鏂囦欢 + if (!myFile.Open(lpSpecPath, CFile::modeCreate | CFile::modeWrite, &fileEx)) + { + _tprintf(_T("閿欒: 鏃犳硶鍐欏叆 spec 鏂囦欢 %s\n"), lpSpecPath); + return FALSE; + } + myFile.Write(strContent.c_str(), (UINT)strContent.size()); + myFile.Close(); + + return TRUE; +} + +// 浠 .spec 鏂囦欢璇诲彇 version= 鍙傛暟鐨勫硷紙鍗/鍙屽紩鍙锋嫭璧风殑璺緞锛 +// 杩斿洖 FALSE 琛ㄧず鏈壘鍒般佸间负 None 鎴栧间负绌 +static BOOL ReadVersionPathFromSpec(LPCTSTR lpSpecPath, CString& strVersionPath) +{ + strVersionPath.Empty(); + if (!PathFileExists(lpSpecPath)) return FALSE; + + CFile myFile; + CFileException fileEx; + if (!myFile.Open(lpSpecPath, CFile::modeRead, &fileEx)) return FALSE; + + DWORD dwLen = (DWORD)myFile.GetLength(); + std::vector buf(dwLen + 1, 0); + myFile.Read(buf.data(), dwLen); + myFile.Close(); + + std::string strContent(buf.data(), dwLen); + + std::string::size_type nPos = 0; + while ((nPos = strContent.find("version=", nPos)) != std::string::npos) + { + bool bIsParam = (nPos == 0 + || strContent[nPos - 1] == '\n' + || strContent[nPos - 1] == '\r' + || strContent[nPos - 1] == ' ' + || strContent[nPos - 1] == '\t'); + if (bIsParam) + { + std::string::size_type nValStart = nPos + 8; // skip "version=" + while (nValStart < strContent.size() && strContent[nValStart] == ' ') + nValStart++; + if (nValStart >= strContent.size()) break; + + char cQuote = strContent[nValStart]; + if (cQuote == '\'' || cQuote == '"') + { + std::string::size_type nValEnd = strContent.find(cQuote, nValStart + 1); + if (nValEnd != std::string::npos && nValEnd > nValStart + 1) + { + strVersionPath = strContent.substr(nValStart + 1, nValEnd - nValStart - 1).c_str(); + return TRUE; + } + } + break; // version=None 鎴栫┖鍊硷紝瑙嗕负鏃 + } + nPos += 8; + } + return FALSE; +} + +// 鏇存柊宸叉湁 version_info 鏂囦欢鐨勭増鏈瓧娈碉紱鑻ユ枃浠朵笉瀛樺湪鍒欏垱寤 +static BOOL UpdateVersionInfoFile(LPCTSTR lpPath, LPCTSTR lpProductVersion, LPCTSTR lpFileVersion) +{ + UINT pv1 = 0, pv2 = 0, pv3 = 0, pv4 = 0; + UINT fv1 = 0, fv2 = 0, fv3 = 0, fv4 = 0; + if (!ParseVersionTuple(lpProductVersion, pv1, pv2, pv3, pv4)) return FALSE; + if (!ParseVersionTuple(lpFileVersion, fv1, fv2, fv3, fv4)) return FALSE; + + CStringA strProdVerA(lpProductVersion); + CStringA strFileVerA(lpFileVersion); + const char* szProdVer = strProdVerA; + const char* szFileVer = strFileVerA; + + if (!PathFileExists(lpPath)) + { + // 鏂囦欢涓嶅瓨鍦紝鐩存帴鍒涘缓 + FILE* fp = NULL; + _tfopen_s(&fp, lpPath, _T("wb")); + if (!fp) return FALSE; + fprintf(fp, + "# UTF-8\n" + "VSVersionInfo(\n" + " ffi=FixedFileInfo(\n" + " filevers=(%u, %u, %u, %u),\n" + " prodvers=(%u, %u, %u, %u),\n" + " mask=0x3f,\n" + " flags=0x0,\n" + " OS=0x40004,\n" + " fileType=0x1,\n" + " subtype=0x0,\n" + " date=(0, 0)\n" + " ),\n" + " kids=[\n" + " StringFileInfo([\n" + " StringTable(\n" + " u'040904B0',\n" + " [StringStruct(u'CompanyName', u''),\n" + " StringStruct(u'FileDescription', u''),\n" + " StringStruct(u'FileVersion', u'%s'),\n" + " StringStruct(u'InternalName', u''),\n" + " StringStruct(u'LegalCopyright', u''),\n" + " StringStruct(u'OriginalFilename', u''),\n" + " StringStruct(u'ProductName', u''),\n" + " StringStruct(u'ProductVersion', u'%s'),\n" + " StringStruct(u'Comments', u''),\n" + " StringStruct(u'LegalTrademarks', u''),\n" + " ])\n" + " ]),\n" + " VarFileInfo([VarStruct(u'Translation', [0x0409, 1200])])\n" + " ]\n" + ")\n", + fv1, fv2, fv3, fv4, + pv1, pv2, pv3, pv4, + szFileVer, + szProdVer); + fclose(fp); + return TRUE; + } + + // 璇诲彇鐜版湁鏂囦欢骞跺氨鍦版洿鏂扮増鏈瓧娈 + CFile myFile; + CFileException fileEx; + if (!myFile.Open(lpPath, CFile::modeReadWrite, &fileEx)) return FALSE; + DWORD dwLen = (DWORD)myFile.GetLength(); + std::vector buf(dwLen + 1, 0); + myFile.Read(buf.data(), dwLen); + myFile.Close(); + + std::string s(buf.data(), dwLen); + char szNew[128]; + + // 鏇存柊 filevers 鍏冪粍 + { + const std::string key = "filevers=("; + auto p = s.find(key); + if (p != std::string::npos) { + auto pValStart = p + key.size(); + auto pValEnd = s.find(')', pValStart); + if (pValEnd != std::string::npos) { + snprintf(szNew, sizeof(szNew), "%u, %u, %u, %u", fv1, fv2, fv3, fv4); + s.replace(pValStart, pValEnd - pValStart, szNew); + } + } + } + // 鏇存柊 prodvers 鍏冪粍 + { + const std::string key = "prodvers=("; + auto p = s.find(key); + if (p != std::string::npos) { + auto pValStart = p + key.size(); + auto pValEnd = s.find(')', pValStart); + if (pValEnd != std::string::npos) { + snprintf(szNew, sizeof(szNew), "%u, %u, %u, %u", pv1, pv2, pv3, pv4); + s.replace(pValStart, pValEnd - pValStart, szNew); + } + } + } + // 鏇存柊 FileVersion 瀛楃涓插 + { + const std::string key = "u'FileVersion', u'"; + auto p = s.find(key); + if (p != std::string::npos) { + auto pValStart = p + key.size(); + auto pValEnd = s.find('\'', pValStart); + if (pValEnd != std::string::npos) + s.replace(pValStart, pValEnd - pValStart, szFileVer); + } + } + // 鏇存柊 ProductVersion 瀛楃涓插 + { + const std::string key = "u'ProductVersion', u'"; + auto p = s.find(key); + if (p != std::string::npos) { + auto pValStart = p + key.size(); + auto pValEnd = s.find('\'', pValStart); + if (pValEnd != std::string::npos) + s.replace(pValStart, pValEnd - pValStart, szProdVer); + } + } + + if (!myFile.Open(lpPath, CFile::modeCreate | CFile::modeWrite, &fileEx)) return FALSE; + myFile.Write(s.c_str(), (UINT)s.size()); + myFile.Close(); + return TRUE; +} + +int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[]) +{ + // 瑙f瀽 pid锛堝唴宓屽湪 argv[1] 涓紝濡 "pyinstaller=5"锛 + // "pyinstaller=" 涓 13 涓瓧绗 + CString strPid = CString(argv[1]).Mid(13); + UINT nPid = 0; + if (strPid.IsEmpty() || !TryParseUInt16(strPid, nPid)) + { + _tprintf(_T("閿欒: pyinstaller= 鍚庣殑 pid 鏃犳晥锛%s锛屽簲涓 0-65535 鑼冨洿鐨勬暣鏁般俓n"), strPid.GetString()); + return 41; + } + + LPCTSTR lpRepoPath = NULL; + CString strExtraArgs; + BOOL bTestMode = FALSE; + int nRepoArgRet = ParsePyinstallerOptions(argc, argv, lpRepoPath, strExtraArgs, bTestMode); + if (nRepoArgRet != 0) + { + return nRepoArgRet; + } + + CString strProductVersion; + CString strFileVersion; + VersionBuildErrorCodes errorCodes = { 42, 43, 44 }; + int nVersionRet = BuildVersionsFromRepo( + lpRepoPath, + nPid, + errorCodes, + strProductVersion, + strFileVersion, + DEFAULT_MAJOR_WHEN_NO_TAG_FOR_PYINSTALLER, + DEFAULT_MINOR_WHEN_NO_TAG_FOR_PYINSTALLER); + if (nVersionRet != 0) + { + return nVersionRet; + } + + if (bTestMode) + { + int nDot1 = strProductVersion.Find(_T('.')); + int nDot2 = (nDot1 >= 0) ? strProductVersion.Find(_T('.'), nDot1 + 1) : -1; + if (nDot2 > nDot1) + { + strProductVersion = strProductVersion.Left(nDot2 + 1) + _T("0.0"); + } + _tprintf(_T("[test] 娴嬭瘯鐗堟湰鍙: ProductVersion=%s\n"), strProductVersion.GetString()); + } + + // 妫娴嬫槸鍚︿负 spec 妯″紡锛岃嫢鏄垯鐢熸垚 version_info.txt 骞舵敞鍏/鏇存柊 spec + CString strFirstToken = ExtractFirstToken(strExtraArgs); + BOOL bIsSpec = (strFirstToken.GetLength() >= 5 + && strFirstToken.Right(5).CompareNoCase(_T(".spec")) == 0); + if (bIsSpec) + { + // 瑙f瀽 spec 鏂囦欢瀹屾暣璺緞 + CString strSpecPath; + if (PathIsRelative(strFirstToken)) + strSpecPath.Format(_T("%s\\%s"), lpRepoPath, strFirstToken.GetString()); + else + strSpecPath = strFirstToken; + + // 鑾峰彇 spec 鎵鍦ㄧ洰褰 + TCHAR szSpecDir[MAX_PATH] = {}; + _tcscpy_s(szSpecDir, strSpecPath.GetString()); + PathRemoveFileSpec(szSpecDir); + + // 妫鏌 spec 鏄惁宸叉寚瀹氱増鏈俊鎭枃浠 + CString strExistingVersionPath; + if (ReadVersionPathFromSpec(strSpecPath, strExistingVersionPath)) + { + // spec 宸叉湁 version=锛岀洿鎺ユ洿鏂版墍鎸囧悜鐨勬枃浠讹紙涓嶅瓨鍦ㄥ垯鍒涘缓锛 + CString strVersionInfoFullPath; + if (PathIsRelative(strExistingVersionPath)) + strVersionInfoFullPath.Format(_T("%s\\%s"), szSpecDir, strExistingVersionPath.GetString()); + else + strVersionInfoFullPath = strExistingVersionPath; + + if (!UpdateVersionInfoFile(strVersionInfoFullPath, strProductVersion, strFileVersion)) + { + _tprintf(_T("閿欒: 鏃犳硶鏇存柊鐗堟湰淇℃伅鏂囦欢: %s銆俓n"), strVersionInfoFullPath.GetString()); + return 45; + } + _tprintf(_T("鐗堟湰淇℃伅鏂囦欢宸叉洿鏂: %s\n"), strVersionInfoFullPath.GetString()); + } + else + { + // spec 鏈寚瀹 version=锛岀敓鎴 version_info.txt 骞舵敞鍏 spec + CString strVersionInfoPath; + if (!WriteVersionInfoFile(szSpecDir, strProductVersion, strFileVersion, strVersionInfoPath)) + { + _tprintf(_T("閿欒: 鏃犳硶鐢熸垚 version_info.txt锛堢洰褰: %s锛夈俓n"), szSpecDir); + return 45; + } + _tprintf(_T("鐗堟湰淇℃伅鏂囦欢宸茬敓鎴: %s\n"), strVersionInfoPath.GetString()); + + if (!InjectVersionIntoSpec(strSpecPath)) + { + _tprintf(_T("閿欒: 鏃犳硶淇敼 spec 鏂囦欢: %s銆俓n"), strSpecPath.GetString()); + return 46; + } + } + } + + _tprintf(_T("PyInstaller 鎵撳寘寮濮..\n")); + _tprintf(_T("ProductVersion=%s\n"), strProductVersion.GetString()); + _tprintf(_T("FileVersion=%s\n"), strFileVersion.GetString()); + + CString strCmd; + strCmd.Format( + _T("cmd /c python -m PyInstaller %s"), + strExtraArgs.GetString()); + + CString strBuildResult = StartProcess(NULL, strCmd.GetBuffer(), lpRepoPath); + strCmd.ReleaseBuffer(); + + if (strBuildResult.IsEmpty()) + { + _tprintf(_T("閿欒: PyInstaller 鎵撳寘澶辫触銆俓n")); + } + + return 0; +} diff --git a/GitVer/GitVer_pyinstaller.h b/GitVer/GitVer_pyinstaller.h new file mode 100644 index 0000000..dc792a1 --- /dev/null +++ b/GitVer/GitVer_pyinstaller.h @@ -0,0 +1,3 @@ +#pragma once + +int HandlePyinstallerBuildCommand(int argc, TCHAR* argv[]); diff --git a/README.md b/README.md index 164f301..67bf7de 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,9 @@ gitver gitver rewrite [PEType] [-f] gitver setver= [repodir=] [-test] [-setup=0|1] -gitver nuitkabuild= [repodir=] [-test] [params=""] -gitver nuitkapydbuild= [repodir=] [-test] [params=""] +gitver nuitkabuild= [repodir=] [-test] [params=" "] +gitver nuitkapydbuild= [repodir=] [-test] [params=" "] +gitver pyinstaller= [repodir=] [-test] [params=" "] gitver -setup=0|1 [repodir=] [-test] ``` @@ -22,7 +23,7 @@ gitver -setup=0|1 [repodir=] [-test] | `pid` | 浜у搧 ID锛屾暣鏁帮紝鑼冨洿 0-65535锛屽唴宓屽湪鍛戒护鍚嶄腑锛堝 `setver=5`锛 | | `repodir=` | Git 浠撳簱鐩綍锛岀己鐪佷娇鐢ㄥ綋鍓嶈繍琛岀洰褰 | | `-test` | 灏嗕骇鍝佺増鏈彿鐨 major/minor 缃负 0锛堟祴璇曠増鏈瀯寤猴級 | -| `params="..."` | 浼犻掔粰 Nuitka 鐨勯澶栧弬鏁帮紝鐢ㄥ弻寮曞彿鎷捣鏉 | +| `params="..."` | 浼犻掔粰 Nuitka 鎴 PyInstaller 鐨勫弬鏁帮紙**鍚叆鍙f枃浠跺悕**锛夛紝鐢ㄥ弻寮曞彿鎷捣鏉 | **BID 瑙勫垯锛** `main`/`master` 鍒嗘敮鍥哄畾 `bid=0`锛涘叾浠栧垎鏀牸寮忛』涓 `<鎻忚堪>.<鏁板瓧>`锛岃嚜鍔ㄨ鍙栨湯灏炬暟瀛椾綔涓 `bid`銆 @@ -145,21 +146,21 @@ FileVersion=5.26.0519.3 鐢熸垚鐗堟湰鍙峰苟璋冪敤 Nuitka 鎵撳寘 Python 绋嬪簭锛圗XE 妯″紡锛夈 ``` -gitver nuitkabuild= [repodir=] [-test] [params=""] +gitver nuitkabuild= [repodir=] [-test] [params=" "] ``` 鑷姩璋冪敤锛 ``` -python -m nuitka --windows-product-version=<鐗堟湰> --windows-file-version=<鐗堟湰> +python -m nuitka --windows-product-version=<鐗堟湰> --windows-file-version=<鐗堟湰> ``` **绀轰緥锛** ``` -gitver nuitkabuild=5 main.py -gitver nuitkabuild=5 main.py -test -gitver nuitkabuild=5 src\app.py repodir=E:\Code\MyPyProj params="--standalone --output-dir=dist" +gitver nuitkabuild=5 params="main.py" +gitver nuitkabuild=5 -test params="main.py" +gitver nuitkabuild=5 repodir=E:\Code\MyPyProj params="src\\app.py --standalone --output-dir=dist" ``` **杈撳嚭绀轰緥锛** @@ -179,27 +180,73 @@ FileVersion=5.26.0519.3 鐢熸垚鐗堟湰鍙峰苟璋冪敤 Nuitka 鎵撳寘 Python 妯″潡锛坧yd/DLL 妯″紡锛夈 ``` -gitver nuitkapydbuild= [repodir=] [-test] [params=""] +gitver nuitkapydbuild= [repodir=] [-test] [params=" "] ``` 鑷姩璋冪敤锛 ``` -python -m nuitka --module --windows-product-version=<鐗堟湰> --windows-file-version=<鐗堟湰> +python -m nuitka --module --windows-product-version=<鐗堟湰> --windows-file-version=<鐗堟湰> ``` **绀轰緥锛** ``` -gitver nuitkapydbuild=5 module.py -gitver nuitkapydbuild=5 module.py -test -gitver nuitkapydbuild=5 src\core.py repodir=E:\Code\MyPyProj params="--output-dir=dist" +gitver nuitkapydbuild=5 params="module.py" +gitver nuitkapydbuild=5 -test params="module.py" +gitver nuitkapydbuild=5 repodir=E:\Code\MyPyProj params="src\\core.py --output-dir=dist" ``` > 闇瑕佸綋鍓嶇幆澧冨凡瀹夎 Nuitka锛堝彲閫氳繃 `python -m nuitka --version` 楠岃瘉锛夈 --- +### `gitver pyinstaller=` + +鐢熸垚鐗堟湰鍙峰苟璋冪敤 PyInstaller 鎵撳寘 Python 绋嬪簭锛屾敮鎸佺洿鎺ヤ紶鍏 `.py` 鍏ュ彛鑴氭湰鎴 `.spec` 鏋勫缓閰嶇疆鏂囦欢銆 + +``` +gitver pyinstaller= [repodir=] [-test] [params=" "] +``` + +鑷姩璋冪敤锛 + +``` +python -m PyInstaller +``` + +鐗堟湰鍙风収甯镐粠 Git tag 璁$畻骞惰緭鍑猴紝浣 PyInstaller 鏈韩涓嶆帴鍙 `--windows-product-version` 绛夊懡浠よ鍙傛暟銆傚闇灏嗙増鏈俊鎭祵鍏 EXE锛屽缓璁湪 `.spec` 鏂囦欢涓氳繃 `version=` 瀛楁鎴栧閮 version resource 鏂囦欢瀹炵幇銆 + +**涓ょ鎵撳寘妯″紡锛** + +| 妯″紡 | 鍙傛暟绀轰緥 | 璇存槑 | +|---|---|---| +| 鑴氭湰妯″紡 | `params="main.py"` | 鐢 PyInstaller 鑷姩鐢熸垚 spec 骞舵墦鍖 | +| spec 妯″紡 | `params="myapp.spec"` | 浣跨敤宸叉湁 spec 鏂囦欢锛屾墦鍖呴厤缃畬鍏ㄧ敱 spec 鎺у埗锛宍params=` 浠呴傜敤浜庤矾寰勭被杩愯鏃堕夐」锛坄--distpath` 绛夛級 | + +**绀轰緥锛** + +``` +gitver pyinstaller=5 params="main.py" +gitver pyinstaller=5 -test params="main.py" +gitver pyinstaller=5 repodir=E:\Code\MyPyProj params="src\\app.py --onefile --name=MyApp" +gitver pyinstaller=5 params="myapp.spec" +gitver pyinstaller=5 -test params="myapp.spec" +gitver pyinstaller=5 repodir=E:\Code\MyPyProj params="myapp.spec" +``` + +**杈撳嚭绀轰緥锛** + +``` +PyInstaller 鎵撳寘寮濮.. (main.py) +ProductVersion=5.0.1920.11 +FileVersion=5.26.0519.3 +``` + +> 闇瑕佸綋鍓嶇幆澧冨凡瀹夎 PyInstaller锛堝彲閫氳繃 `python -m PyInstaller --version` 楠岃瘉锛夈 + +--- + ### `gitver -setup=0|1`锛堢嫭绔嬫墦鍖呭懡浠わ級 鐙珛璋冪敤瀹夎鑴氭湰鎵撳寘锛屼笉渚濊禆 `setver=` 鍛戒护銆 @@ -217,6 +264,112 @@ gitver -setup=1 5 repodir=E:\Code\MyProj --- +## Nuitka 涓 PyInstaller 甯哥敤鍙傛暟閫熸煡 + +### Nuitka 甯哥敤鍙傛暟 + +閫氳繃 `params="..."` 浼犻掔粰 `gitver nuitkabuild=` / `nuitkapydbuild=`銆 + +| 鍙傛暟 | 璇存槑 | +|---|---| +| `--standalone` | 鐙珛妯″紡锛氬皢鎵鏈変緷璧栨墦鍖呰繘杈撳嚭鐩綍锛屽彲鍗曠嫭鍒嗗彂 | +| `--onefile` | 鍗曟枃浠舵ā寮忥細灏嗙嫭绔嬪寘鍘嬬缉涓哄崟涓 EXE锛堥渶閰嶅悎 `--standalone`锛 | +| `--output-dir=` | 鎸囧畾杈撳嚭鐩綍锛屽 `--output-dir=dist` | +| `--windows-icon-from-ico=` | 璁剧疆 EXE 鍥炬爣 | +| `--windows-company-name=` | 璁剧疆鍏徃鍚嶏紙鍐欏叆鏂囦欢灞炴э級 | +| `--windows-product-name=` | 璁剧疆浜у搧鍚 | +| `--enable-plugin=` | 鍚敤鎻掍欢锛屽 `pyside6`銆乣tk-inter`銆乣numpy` | +| `--follow-imports` | 璺熻釜鎵鏈夐殣寮忓鍏ワ紙鎵撳寘鏇村畬鏁达紝浣撶Н涔熸洿澶э級 | +| `--nofollow-import-to=` | 鎺掗櫎鎸囧畾妯″潡涓嶅睍寮锛屽 `--nofollow-import-to=tests` | +| `--include-package=` | 寮哄埗鍖呭惈鎸囧畾鍖 | +| `--include-data-files==` | 鎵撳寘棰濆鏁版嵁鏂囦欢 | +| `--remove-output` | 鎵撳寘鍓嶅厛娓呯悊涓婃杈撳嚭 | +| `--lto=yes` | 鍚敤閾炬帴鏃朵紭鍖栵紙Release 鏋勫缓鎺ㄨ崘锛 | +| `--jobs=` | 骞惰缂栬瘧绾跨▼鏁帮紝濡 `--jobs=4` | + +**鍏稿瀷鐢ㄦ硶绀轰緥锛** + +```bash +# 鏈灏忓崟鏂囦欢 EXE +gitver nuitkabuild=5 params="main.py --standalone --onefile --output-dir=dist" + +# 甯﹀浘鏍囥佸叕鍙稿悕鐨勭嫭绔嬪寘 +gitver nuitkabuild=5 params="main.py --standalone --windows-icon-from-ico=app.ico --windows-company-name=MyCompany --output-dir=dist" + +# PySide6 GUI 搴旂敤 +gitver nuitkabuild=5 params="main.py --standalone --enable-plugin=pyside6 --output-dir=dist" + +# 鎵撳寘 pyd 妯″潡 +gitver nuitkapydbuild=5 params="core.py --output-dir=dist" + +# 寮傚湴浠撳簱 +gitver nuitkabuild=5 repodir=E:\Code\MyProj params="main.py --standalone --onefile --output-dir=dist" +``` + +--- + +### PyInstaller 甯哥敤鍙傛暟 + +閫氳繃 `params="..."` 浼犻掔粰 `gitver pyinstaller=`銆 + +| 鍙傛暟 | 璇存槑 | +|---|---| +| `--onefile` / `-F` | 鍗曟枃浠舵ā寮忥細鎵撳寘鎴愬崟涓 EXE | +| `--onedir` / `-D` | 鍗曠洰褰曟ā寮忥紙榛樿锛 | +| `--name=` / `-n` | 鎸囧畾杈撳嚭鏂囦欢鍚嶏紙涓嶅惈鍚庣紑锛 | +| `--icon=` / `-i` | 璁剧疆 EXE 鍥炬爣 | +| `--distpath=` | 鎸囧畾杈撳嚭鐩綍锛岄粯璁 `dist` | +| `--workpath=` | 涓棿鏂囦欢鐩綍锛岄粯璁 `build` | +| `--specpath=` | spec 鏂囦欢鐢熸垚浣嶇疆锛岄粯璁ゅ綋鍓嶇洰褰 | +| `--noconsole` / `-w` | 涓嶆樉绀烘帶鍒跺彴绐楀彛锛圙UI 搴旂敤锛 | +| `--hidden-import=` | 鎵嬪姩鎸囧畾闅愬紡瀵煎叆鐨勬ā鍧 | +| `--add-data=;` | 鎵撳寘棰濆鏁版嵁鏂囦欢锛學indows 鍒嗛殧绗︿负 `;`锛孡inux/macOS 涓 `:` | +| `--version-file=` | 浠庢枃浠惰鍏 Windows 鐗堟湰淇℃伅宓屽叆 EXE | +| `--uac-admin` | 璇锋眰绠$悊鍛樻潈闄愯繍琛 | +| `--clean` | 鏋勫缓鍓嶆竻鐞嗙紦瀛 | +| `--log-level=WARN` | 鍑忓皯鏋勫缓杈撳嚭鍣煶锛屽彲閫 `DEBUG`銆乣INFO`銆乣WARN`銆乣ERROR` | + +**鍏稿瀷鐢ㄦ硶绀轰緥锛** + +```bash +# 鏈灏忓崟鏂囦欢 EXE +gitver pyinstaller=5 params="main.py --onefile --name=MyApp" + +# GUI 搴旂敤锛堝叧鎸囨帶鍒跺彴锛 +gitver pyinstaller=5 params="main.py --onefile --noconsole --icon=app.ico --name=MyApp" + +# 鍖呭惈璧勬簮鏂囦欢 +gitver pyinstaller=5 params="main.py --onefile --add-data=assets;assets --name=MyApp" + +# 鎸囧畾杈撳嚭鐩綍 +gitver pyinstaller=5 params="main.py --onefile --distpath=dist --workpath=build --name=MyApp" + +# 浣跨敤 spec 鏂囦欢锛堥厤缃潎鍦 spec 涓紝涓嶉渶瑕佸叾浠 params锛 +gitver pyinstaller=5 params="myapp.spec" + +# 浣跨敤 spec 骞惰鐩栬緭鍑鸿矾寰 +gitver pyinstaller=5 params="myapp.spec --distpath=release" + +# 寮傚湴浠撳簱 +gitver pyinstaller=5 repodir=E:\Code\MyProj params="main.py --onefile --name=MyApp" +``` + +**spec 鏂囦欢宓屽叆鐗堟湰淇℃伅锛堟帹鑽愭柟寮忥級锛** + +PyInstaller 涓嶆敮鎸佸懡浠よ鐗堟湰鍙傛暟銆傞渶灏嗙増鏈彿宓屽叆 EXE 鏃讹紝寤鸿鍏堢敤 `gitver setver=` 鐢熸垚鐗堟湰鍙凤紝鍐嶅湪 spec 鏂囦欢涓缃 `version_file` 瀛楁锛 + +```python +# myapp.spec 鐗囨 +exe = EXE( + pyz, + ..., + version='version_info.txt', # Windows 鐗堟湰淇℃伅鏂囦欢 + name='MyApp', +) +``` + +--- + ## 閿欒鐮 | 鐮 | 鍚箟 | @@ -249,6 +402,11 @@ gitver -setup=1 5 repodir=E:\Code\MyProj | 37 | 鏈壘鍒板畨瑁呰剼鏈紙setup.iss / setup.nsi锛 | | 38 | 淇敼瀹夎鑴氭湰澶辫触 | | 39 | 鏈壘鍒板畨瑁呯紪璇戝櫒锛圛SCC.exe / makensis.exe锛 | +| 40 | `pyinstaller=` 鍙傛暟涓嶈冻锛堢己灏 mainPy 鎴 specFile锛 | +| 41 | `pyinstaller=` 鐨 pid 闈炴硶 | +| 42 | `pyinstaller=` 鏃犳硶鏍规嵁鍒嗘敮鍚嶈绠 bid | +| 43 | `pyinstaller=` 璇诲彇 tag 澶辫触 | +| 44 | `pyinstaller=` 鑾峰彇褰撳ぉ鍒嗘敮鎻愪氦娆℃暟澶辫触 | --- @@ -304,13 +462,27 @@ gitver setver=5 -test ### 楠岃瘉 `nuitkabuild=` ```bash -gitver nuitkabuild=5 main.py +gitver nuitkabuild=5 params="main.py" # 棰勬湡: 璋冪敤 python -m nuitka锛屾敞鍏ョ増鏈彿鍙傛暟 -gitver nuitkabuild=5 src\app.py params="--standalone --output-dir=dist" +gitver nuitkabuild=5 params="src\\app.py --standalone --output-dir=dist" # 棰勬湡: 棰濆鍙傛暟浼犻掔粰 Nuitka ``` +### 楠岃瘉 `pyinstaller=` + +```bash +gitver pyinstaller=5 params="main.py" +# 棰勬湡: 璋冪敤 python -m PyInstaller main.py +# 杈撳嚭 ProductVersion / FileVersion + +gitver pyinstaller=5 params="myapp.spec" +# 棰勬湡: 璋冪敤 python -m PyInstaller myapp.spec锛坰pec 妯″紡锛 + +gitver pyinstaller=5 params="main.py --onefile --name=MyApp" +# 棰勬湡: 棰濆鍙傛暟浼犻掔粰 PyInstaller +``` + ### 楠岃瘉 `-setup=` ```bash @@ -347,21 +519,34 @@ gitver setver=5 -setup=0 | 鍛戒护 | 棰勬湡杩斿洖鐮 | |---|---| -| `gitver nuitkabuild=5 main.py` | 0 / 19 / 21 | -| `gitver nuitkabuild=5 main.py -test` | 0 | -| `gitver nuitkabuild=5 main.py params="--standalone"` | 0 | -| `gitver nuitkabuild=5 main.py repodir=E:\NotExists` | 23 | -| `gitver nuitkabuild=5` | 17 | +| `gitver nuitkabuild=5 params="main.py"` | 0 / 19 / 21 | +| `gitver nuitkabuild=5 -test params="main.py"` | 0 | +| `gitver nuitkabuild=5 params="main.py --standalone"` | 0 | +| `gitver nuitkabuild=5 repodir=E:\NotExists params="main.py"` | 23 | +| `gitver nuitkabuild=5` | 0 | ### nuitkapydbuild= 缁 | 鍛戒护 | 棰勬湡杩斿洖鐮 | |---|---| -| `gitver nuitkapydbuild=5 module.py` | 0 / 26 / 28 | -| `gitver nuitkapydbuild=5 module.py -test` | 0 | -| `gitver nuitkapydbuild=5 module.py params="--output-dir=dist"` | 0 | -| `gitver nuitkapydbuild=5 module.py repodir=E:\NotExists` | 23 | -| `gitver nuitkapydbuild=5` | 24 | +| `gitver nuitkapydbuild=5 params="module.py"` | 0 / 26 / 28 | +| `gitver nuitkapydbuild=5 -test params="module.py"` | 0 | +| `gitver nuitkapydbuild=5 params="module.py --output-dir=dist"` | 0 | +| `gitver nuitkapydbuild=5 repodir=E:\NotExists params="module.py"` | 23 | +| `gitver nuitkapydbuild=5` | 0 | + +### pyinstaller= 缁 + +| 鍛戒护 | 棰勬湡杩斿洖鐮 | +|---|---| +| `gitver pyinstaller=5 params="main.py"` | 0 / 42 / 44 | +| `gitver pyinstaller=5 -test params="main.py"` | 0 | +| `gitver pyinstaller=5 params="main.py --onefile"` | 0 | +| `gitver pyinstaller=5 params="myapp.spec"` | 0 | +| `gitver pyinstaller=5 -test params="myapp.spec"` | 0 | +| `gitver pyinstaller=5 repodir=E:\NotExists params="main.py"` | 23 | +| `gitver pyinstaller=5` | 0 | +| `gitver pyinstaller=abc params="main.py"` | 41 | > **娉ㄦ剰**锛氬鏋滄墦鍖呮椂鎻愮ず鈥滄湭鎵惧埌瀹夎缂栬瘧鍣紙ISCC.exe / makensis.exe锛夆濓紝璇锋墜鍔ㄤ笅杞藉畨瑁呭搴斿伐鍏凤紝骞跺皢鍏跺彲鎵ц鏂囦欢璺緞锛堝 `ISCC.exe` 鎴 `makensis.exe` 鎵鍦ㄧ洰褰曪級娣诲姞鍒扮郴缁熺幆澧冨彉閲 `PATH`銆傚父瑙佷笅杞藉湴鍧锛 >