From 8e7c1408f71baf63205ed99f567e3998205d8d25 Mon Sep 17 00:00:00 2001 From: taynpg Date: Tue, 17 Mar 2026 14:21:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8=E6=89=93?= =?UTF-8?q?=E5=8C=85=E8=84=9A=E6=9C=AC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 +- CMakeLists.txt | 16 ++ Tools.h.in | 10 ++ fileUpdater/CMakeLists.txt | 16 -- fileUpdater/fileUpdaterVer.h.in | 7 - fileUpdater/main.cpp | 2 +- script/AutoPack.bat | 28 +++ script/package.py | 292 ++++++++++++++++++++++++++++++++ 8 files changed, 349 insertions(+), 26 deletions(-) create mode 100644 Tools.h.in delete mode 100644 fileUpdater/fileUpdaterVer.h.in create mode 100644 script/AutoPack.bat create mode 100644 script/package.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 850e6b9..67093f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,9 @@ { "files.autoSave": "onFocusChange", "editor.fontSize": 14, - "editor.fontFamily": "'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light'", + "editor.fontFamily": "'Source Code Pro', 'Source Code Pro', 'Source Code Pro'", "editor.wordWrap": "on", - "terminal.integrated.fontFamily": "'Maple Mono NL NF CN Light'", + "terminal.integrated.fontFamily": "'Source Code Pro'", "cmake.configureOnOpen": true, //"C_Cpp.intelliSenseEngine": "disabled", "cmake.debugConfig": { diff --git a/CMakeLists.txt b/CMakeLists.txt index a5f2690..75ab01a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,22 @@ if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() +execute_process( + COMMAND git rev-parse --short HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE VERSION_GIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) +execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE VERSION_GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE +) +configure_file(Tools.h.in Tools.h) +message(STATUS "Version file config to: ${CMAKE_CURRENT_BINARY_DIR}") +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + add_subdirectory(zoost) add_subdirectory(strReplace) add_subdirectory(fileUpdater) \ No newline at end of file diff --git a/Tools.h.in b/Tools.h.in new file mode 100644 index 0000000..9dca34d --- /dev/null +++ b/Tools.h.in @@ -0,0 +1,10 @@ +#ifndef FILEUPDATER_VERSION_H +#define FILEUPDATER_VERSION_H + +#define PROJECT_NAME "@PROJECT_NAME@" +#define VERSION_GIT_COMMIT "@VERSION_GIT_HASH@" +#define VERSION_GIT_BRANCH "@VERSION_GIT_BRANCH@" +#define CMAKE_RUNTIME_OUTPUT_DIRECTORY "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@" +#define LIBRARY_OUTPUT_PATH "@LIBRARY_OUTPUT_PATH@" + +#endif // FILEUPDATER_VERSION_H \ No newline at end of file diff --git a/fileUpdater/CMakeLists.txt b/fileUpdater/CMakeLists.txt index 769b632..550b0b9 100644 --- a/fileUpdater/CMakeLists.txt +++ b/fileUpdater/CMakeLists.txt @@ -10,22 +10,6 @@ if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() -execute_process( - COMMAND git rev-parse --short HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE VERSION_GIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE -) -execute_process( - COMMAND git rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE VERSION_GIT_BRANCH - OUTPUT_STRIP_TRAILING_WHITESPACE -) -configure_file(fileUpdaterVer.h.in fileUpdaterVer.h) -message(STATUS "Version file config to: ${CMAKE_CURRENT_BINARY_DIR}") -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - find_package(fmt REQUIRED) find_package(tinyxml2 REQUIRED) find_package(CLI11 REQUIRED) diff --git a/fileUpdater/fileUpdaterVer.h.in b/fileUpdater/fileUpdaterVer.h.in deleted file mode 100644 index 806c929..0000000 --- a/fileUpdater/fileUpdaterVer.h.in +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef FILEUPDATER_VERSION_H -#define FILEUPDATER_VERSION_H - -#define VERSION_GIT_COMMIT "@VERSION_GIT_HASH@" -#define VERSION_GIT_BRANCH "@VERSION_GIT_BRANCH@" - -#endif // FILEUPDATER_VERSION_H \ No newline at end of file diff --git a/fileUpdater/main.cpp b/fileUpdater/main.cpp index 69b6d0d..a581182 100644 --- a/fileUpdater/main.cpp +++ b/fileUpdater/main.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/script/AutoPack.bat b/script/AutoPack.bat new file mode 100644 index 0000000..13b379b --- /dev/null +++ b/script/AutoPack.bat @@ -0,0 +1,28 @@ +@echo off + +echo Config CMake... +cmake -B..\build -S..\ -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="%VCPKG_DIR%\scripts\buildsystems\vcpkg.cmake" -A x64 +if errorlevel 1 ( + echo CMake Failed. + pause + exit /b 1 +) + +echo Building... +cmake --build ..\build --config Release +if errorlevel 1 ( + echo Build Failed. + pause + exit /b 1 +) + +echo Packing... +python package.py ..\build\Tools.h +if errorlevel 1 ( + echo Pack Failed. + pause + exit /b 1 +) + +echo Done. +pause \ No newline at end of file diff --git a/script/package.py b/script/package.py new file mode 100644 index 0000000..e7ce1e1 --- /dev/null +++ b/script/package.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +""" +解析版本头文件并打包二进制文件的脚本 +用法: python package_binaries.py +""" + +import os +import sys +import re +import zipfile +import tarfile +import platform + +def parse_version_header(file_path): + """ + 解析版本头文件,提取路径信息 + 返回字典包含解析结果 + """ + if not os.path.exists(file_path): + raise FileNotFoundError(f"文件不存在: {file_path}") + + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # 使用正则表达式提取信息 + patterns = { + 'PROJECT_NAME': r'#define\s+PROJECT_NAME\s+"([^"]+)"', + 'VERSION_GIT_COMMIT': r'#define\s+VERSION_GIT_COMMIT\s+"([^"]+)"', + 'VERSION_GIT_BRANCH': r'#define\s+VERSION_GIT_BRANCH\s+"([^"]+)"', + 'CMAKE_RUNTIME_OUTPUT_DIRECTORY': r'#define\s+CMAKE_RUNTIME_OUTPUT_DIRECTORY\s+"([^"]+)"', + 'LIBRARY_OUTPUT_PATH': r'#define\s+LIBRARY_OUTPUT_PATH\s+"([^"]+)"', + } + + result = {} + for key, pattern in patterns.items(): + match = re.search(pattern, content) + if match: + result[key] = match.group(1) + else: + # 尝试无引号的情况 + pattern_no_quotes = pattern.replace(r'"([^"]+)"', r'(\S+)') + match = re.search(pattern_no_quotes, content) + if match: + result[key] = match.group(1) + else: + print(f"警告: 未找到 {key} 定义") + result[key] = "" + + # 验证必要字段 + required_fields = ['PROJECT_NAME', 'VERSION_GIT_COMMIT', 'VERSION_GIT_BRANCH'] + for field in required_fields: + if not result.get(field): + raise ValueError(f"缺少必要字段: {field}") + + return result + +def normalize_path(path_str): + """标准化路径,处理Windows/Unix路径差异""" + if not path_str: + return "" + + # 替换反斜杠为正斜杠 + path_str = path_str.replace('\\', '/') + + # 移除可能的尾部斜杠 + path_str = path_str.rstrip('/') + + return path_str + +def collect_binary_files(runtime_dir, library_dir): + """ + 收集指定目录下的二进制文件 + 返回文件路径列表 + """ + binary_files = [] + dirs_to_search = [] + + if runtime_dir and os.path.exists(runtime_dir): + dirs_to_search.append(runtime_dir) + print(f"搜索运行时目录: {runtime_dir}") + + if library_dir and os.path.exists(library_dir): + dirs_to_search.append(library_dir) + print(f"搜索库目录: {library_dir}") + + # 支持的二进制文件扩展名 + binary_extensions = { + 'windows': ['.exe', '.dll', '.pdb', '.lib'], + 'linux': ['', '.so', '.so.*', '.a'], + 'darwin': ['', '.dylib', '.a', '.bundle'] + } + + current_os = platform.system().lower() + if 'windows' in current_os: + extensions = binary_extensions['windows'] + elif 'linux' in current_os: + extensions = binary_extensions['linux'] + elif 'darwin' in current_os: + extensions = binary_extensions['darwin'] + else: + extensions = binary_extensions['linux'] # 默认 + + for search_dir in dirs_to_search: + if not os.path.exists(search_dir): + print(f"警告: 目录不存在: {search_dir}") + continue + + for root, dirs, files in os.walk(search_dir): + for file in files: + file_path = os.path.join(root, file) + + # 检查文件扩展名 + should_include = False + for ext in extensions: + if ext.endswith('*'): + # 通配符匹配 + if file.endswith(ext.rstrip('*')): + should_include = True + break + elif ext == '': + # 无扩展名文件(Linux可执行文件) + if not os.path.splitext(file)[1]: + should_include = True + break + else: + # 普通扩展名匹配 + if file.lower().endswith(ext.lower()): + should_include = True + break + + if should_include: + binary_files.append(file_path) + print(f" 找到: {os.path.relpath(file_path, search_dir)}") + + return binary_files + +def create_zip_package(files, output_filename, base_dirs): + """ + 创建ZIP压缩包 + """ + print(f"创建ZIP包: {output_filename}") + + with zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: + for file_path in files: + # 确定在ZIP中的相对路径 + arcname = None + + # 尝试找到最合适的基目录 + for base_dir in base_dirs: + if base_dir and file_path.startswith(base_dir): + # 使用相对于基目录的路径 + rel_path = os.path.relpath(file_path, base_dir) + # 保持目录结构 + arcname = rel_path + break + + # 如果没有找到合适的基目录,只使用文件名 + if not arcname: + arcname = os.path.basename(file_path) + + # 确保路径使用正斜杠 + arcname = arcname.replace('\\', '/') + + zipf.write(file_path, arcname) + print(f" 添加: {arcname}") + + print(f"ZIP包创建完成: {output_filename}") + print(f"包含文件数: {len(files)}") + +def create_tar_gz_package(files, output_filename, base_dirs): + """ + 创建tar.gz压缩包 + """ + print(f"创建tar.gz包: {output_filename}") + + with tarfile.open(output_filename, "w:gz") as tar: + for file_path in files: + # 确定在tar中的相对路径 + arcname = None + + # 尝试找到最合适的基目录 + for base_dir in base_dirs: + if base_dir and file_path.startswith(base_dir): + # 使用相对于基目录的路径 + rel_path = os.path.relpath(file_path, base_dir) + # 保持目录结构 + arcname = rel_path + break + + # 如果没有找到合适的基目录,只使用文件名 + if not arcname: + arcname = os.path.basename(file_path) + + tar.add(file_path, arcname=arcname, recursive=False) + print(f" 添加: {arcname}") + + print(f"tar.gz包创建完成: {output_filename}") + print(f"包含文件数: {len(files)}") + +def main(): + """主函数""" + if len(sys.argv) != 2: + print("用法: python package_binaries.py ") + print("示例: python package_binaries.py Tools.h") + sys.exit(1) + + header_file = sys.argv[1] + + try: + # 1. 解析版本头文件 + print(f"解析文件: {header_file}") + info = parse_version_header(header_file) + + project_name = info['PROJECT_NAME'] + git_commit = info['VERSION_GIT_COMMIT'] + git_branch = info['VERSION_GIT_BRANCH'] + runtime_dir = normalize_path(info.get('CMAKE_RUNTIME_OUTPUT_DIRECTORY', '')) + library_dir = normalize_path(info.get('LIBRARY_OUTPUT_PATH', '')) + + print(f"项目: {project_name}") + print(f"分支: {git_branch}") + print(f"提交: {git_commit}") + print(f"运行时目录: {runtime_dir}") + print(f"库目录: {library_dir}") + + # 2. 收集二进制文件 + print("\n收集二进制文件...") + binary_files = collect_binary_files(runtime_dir, library_dir) + + if not binary_files: + print("错误: 未找到任何二进制文件") + print(f"请检查以下目录:") + if runtime_dir: + print(f" - {runtime_dir}") + if library_dir: + print(f" - {library_dir}") + sys.exit(1) + + print(f"找到 {len(binary_files)} 个二进制文件") + + # 3. 创建输出文件名 + # 清理分支名(替换特殊字符) + safe_branch = re.sub(r'[\\/*?:"<>|]', "_", git_branch) + output_basename = f"{project_name}-{safe_branch}-{git_commit}" + + # 4. 根据操作系统选择压缩格式 + current_os = platform.system().lower() + + # 确定要搜索的基目录(用于保持相对路径) + base_dirs = [] + if runtime_dir: + base_dirs.append(runtime_dir) + if library_dir: + base_dirs.append(library_dir) + + if 'windows' in current_os: + output_file = f"{output_basename}.zip" + print(f"\n在Windows系统,创建ZIP包...") + create_zip_package(binary_files, output_file, base_dirs) + else: + output_file = f"{output_basename}.tar.gz" + print(f"\n在{current_os.capitalize()}系统,创建tar.gz包...") + create_tar_gz_package(binary_files, output_file, base_dirs) + + # 5. 输出结果 + file_size = os.path.getsize(output_file) / (1024 * 1024) # MB + print(f"\n✓ 打包完成!") + print(f"输出文件: {output_file}") + print(f"文件大小: {file_size:.2f} MB") + print(f"包含文件: {len(binary_files)} 个") + + # 显示文件列表 + print("\n文件列表:") + for i, file_path in enumerate(binary_files, 1): + # 显示相对于工作目录的路径 + rel_path = os.path.relpath(file_path) + print(f" {i:3d}. {rel_path}") + + except FileNotFoundError as e: + print(f"错误: {e}", file=sys.stderr) + sys.exit(1) + except ValueError as e: + print(f"错误: {e}", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"未知错误: {e}", file=sys.stderr) + import traceback + traceback.print_exc() + sys.exit(1) + +if __name__ == "__main__": + main() \ No newline at end of file