尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

虚幻引擎项目构建与测试自动化:使用uet统一命令行工具

虚幻引擎项目构建与测试自动化:使用uet统一命令行工具 1. 项目概述为什么我们需要uet如果你是一名虚幻引擎Unreal Engine开发者尤其是参与过中大型项目那么下面这个场景你一定不陌生项目组新来了一位同事你让他把项目从源码库拉下来然后告诉他“用引擎版本5.3.2编译一下再运行一下自动化测试看看”。接下来你可能会听到一连串的问题“编译选项怎么配用Development还是Shipping测试怎么跑是直接在编辑器里点那个按钮吗测试报告在哪看我本地没装那个Python包怎么办” 光是搭建一个能构建、能测试的本地环境可能就要花掉半天甚至更久的时间。这还只是个人开发。到了持续集成CI环节问题会指数级放大。Jenkins、GitLab CI或者GitHub Actions上的构建脚本往往是一堆错综复杂的批处理、PowerShell和Python脚本的缝合怪。它们硬编码了引擎路径、平台工具链的调用方式以及各种脆弱的文件路径。一旦引擎版本升级、项目结构变动或者需要在新的平台上比如从Windows换到Linux进行构建这套脚本就可能直接崩溃排查起来如同大海捞针。uet的出现正是为了解决这些痛点。它不是一个全新的构建系统而是一个基于Python的、面向虚幻引擎项目的统一命令行接口和自动化工作流工具。你可以把它想象成虚幻引擎领域的make或cmake但它更懂UE项目的“规矩”。它的核心目标是标准化和简化从项目生成、编译、打包、测试到部署的整个生命周期让开发者能用一个简单、一致的命令在不同的机器、不同的平台上获得可重复、可靠的结果。简单来说uet试图把那些隐藏在编辑器UI背后、散落在各种文档角落、以及存在于资深开发者“肌肉记忆”里的构建与测试知识封装成一套清晰的、可脚本化的工具链。无论你是想快速验证一次代码提交还是为团队搭建一套企业级的CI/CD流水线uet都试图提供一个更优雅的起点。2.uet的核心设计理念与架构拆解2.1 从混沌到秩序uet解决的问题域在深入uet之前我们先看看传统的UE项目工作流有多“混沌”。一个典型的UE C项目其构建和测试涉及多个层次和工具项目文件生成需要调用UnrealBuildTool来生成.sln或.xcodeproj文件。源码编译调用UnrealBuildTool或平台原生编译器如MSBuild、clang来编译引擎和游戏模块。内容构建调用UnrealEditor-Cmd.exe进行Cook内容烹饪、Pak打包等。测试执行单元测试、功能测试、自动化测试可能分散在多个地方——有基于Google Test的C单元测试有在编辑器内运行的Functional Testing还有使用Gauntlet或自定义Python脚本的端到端测试。环境管理需要正确设置引擎路径、.uproject文件路径、各种SDK路径如Android NDK, iOS Provisioning Profile。这些步骤每一个都有自己的一套参数、调用方式和潜在的坑。uet的设计理念就是用一个“动词-名词”结构的命令行接口将这些步骤统一起来。例如uet build 处理所有编译相关的事情。uet test 处理所有测试相关的事情。uet cook 处理内容烹饪。uet package 处理最终的游戏打包。2.2 架构分层插件化与可扩展性uet没有试图重新发明轮子而是扮演了一个“胶水”和“调度器”的角色。它的架构大致可以分为三层核心层Core提供基础框架包括命令行解析、配置管理、日志系统、插件加载机制。它定义了一套抽象的“命令”接口任何具体功能都以插件形式实现。内置插件层Built-in Pluginsuet自带了一系列实现核心功能的插件。例如build插件封装了对UnrealBuildTool的调用处理不同配置Debug, Development, Shipping和平台Win64, Linux, Android的编译。test插件整合了运行各种测试的流程可能是调用引擎的自动化测试工具也可能是执行项目自定义的测试脚本。project插件用于创建、初始化和管理.uproject文件。自定义/第三方插件层这是uet强大扩展性的体现。团队或个人可以编写自己的uet插件来封装项目特有的构建步骤。比如你的项目在打包后需要自动上传到内部分发平台或者需要执行一套特定的资源后处理流程都可以写成一个独立的uet插件命令。这种插件化架构意味着uet本身是轻量的它的功能边界可以由使用者自由定义。官方提供“开箱即用”的基础能力复杂项目则可以通过自定义插件来满足特定需求而无需污染或魔改核心工具链。注意评估一个构建工具不仅要看它现在能做什么更要看它是否易于扩展来适配你未来的需求。uet的插件化设计在这方面提供了很好的基础。2.3 配置即代码.uet.toml的威力uet强烈推荐使用配置文件来管理项目设置。通常你会在项目根目录创建一个名为.uet.toml的文件。这个文件是uet的“唯一真相源”它定义了项目使用的引擎版本和路径或引擎标识符。项目本身的路径。为不同命令预设的选项和参数。自定义插件的位置和配置。# .uet.toml 示例 [project] name MyAwesomeGame path D:/Projects/MyAwesomeGame/MyAwesomeGame.uproject [engine] version 5.3 # 可以是本地路径 location D:/UE_5.3 # 或者使用 Epic 的版本标识符 # identifier “5.3” [commands.build] configuration Development platform Win64 target MyAwesomeGameEditor [commands.test] type functional # 可以是 unit, functional, gauntlet 等 report_format junit # 输出 JUnit 格式的报告便于 CI 集成通过配置文件你将原本需要每次在命令行输入的一长串参数固化下来。在CI环境中这尤其重要——你只需要确保CI机器上存在这个配置文件或者通过环境变量动态生成它就能保证每次构建的环境和参数完全一致实现了真正的“配置即代码”。3. 核心功能深度解析与实操要点3.1 构建Build不止是编译uet build命令是使用频率最高的命令之一。它的工作远不止调用编译器那么简单。典型工作流# 1. 生成项目文件如果不存在或引擎版本变更 uet generate # 2. 编译项目使用 .uet.toml 中的默认配置 uet build # 3. 编译特定配置和平台 uet build --configuration Shipping --platform Android # 4. 编译多个目标如同时编译Game和Editor uet build --target MyGame MyGameEditor背后原理与细节环境探测uet首先会解析.uet.toml和系统环境变量确定要使用的UnrealBuildTool的准确路径。它知道不同引擎版本下UBT的位置可能不同。参数转换与传递uet会将你提供的友好参数如--configuration Shipping转换为UBT能识别的参数如-configurationShipping。同时它会帮你处理一些繁琐的细节比如自动添加-project参数指向你的.uproject文件。并行与日志uet可以控制编译的并行度-j参数并重定向UBT的输出。一个重要的功能是解析编译错误和警告。原生的UBT输出信息量巨大uet可以对其进行过滤和格式化高亮显示错误行让开发者更快定位问题。增量构建支持uet尊重UBT的增量构建系统。它会检查时间戳和依赖关系只编译发生变化的模块大幅提升日常开发中的编译速度。实操心得在团队中建议将--configuration Development --platform Win64这类常用组合写入.uet.toml的预设中。这样新成员只需uet build即可开始避免了参数记忆负担。对于CI则显式指定Shipping等配置确保产出一致。3.2 测试Test统一测试入口的挑战与实现测试是uet的另一个核心也是传统上最分散的环节。uet test命令的目标是提供一个统一的入口来运行所有类型的测试。支持的测试类型单元测试基于Google Test的C单元测试。uet会定位到编译生成的.exe测试运行器通常位于Binaries/[Platform]下执行它并收集结果。功能测试在编辑器内运行的自动化测试。这是最复杂的一种因为uet需要以“命令行模式”启动UnrealEditor-Cmd.exe加载指定的测试地图或测试套件执行测试然后安全退出并返回结果。Gauntlet 测试用于多客户端/服务器端到端测试的框架。uet可以调用Gauntlet的Python脚本设置测试会话如1个服务器2个客户端运行测试并生成报告。一个运行功能测试的示例# 运行项目中所有的功能测试 uet test --type functional --all # 运行特定的测试地图 uet test --type functional --map “/Game/Tests/MyFunctionalTestMap” # 指定报告输出路径和格式 uet test --type functional --all --report-dir “./TestResults” --report-format junit实现难点与uet的解决方案编辑器进程管理运行功能测试需要启动一个无界面的编辑器进程。uet必须妥善处理这个进程的生命周期——启动、监控其输出包括测试日志和可能的崩溃信息、在测试完成后终止它。这里涉及到超时设置、信号处理等复杂逻辑。结果解析编辑器测试的输出是结构化的日志通常包含LogFunctionalTest: Warning/Error等标签。uet需要从海量日志中精准提取测试通过/失败的信息并将其转换为标准的测试报告格式如JUnit XML以便被Jenkins、GitLab等CI系统识别。资源清理测试过程中可能会产生临时文件或修改配置。uet需要在测试前后确保环境的一致性或者在测试后执行清理操作。注意事项功能测试非常依赖项目内容。确保你的测试地图和相关的资产蓝图、材质等已经正确烹饪Cook并随项目打包。在CI中通常需要先执行uet cook和uet package或至少是-cook阶段然后再运行uet test。3.3 项目与引擎管理除了构建和测试uet还提供了一些提升开发体验的辅助命令。uet project可以快速创建新的UE项目模板或者将现有文件夹初始化为一个uet管理的项目创建.uet.toml。uet engine如果你通过Epic Games Launcher安装了多个版本的引擎这个命令可以帮助你列出、切换或链接到特定的引擎版本。这对于需要同时维护多个使用不同UE版本的项目非常有用。4. 集成到CI/CD流水线从理论到实践uet的真正威力在于自动化。下面我们以 GitHub Actions 为例展示如何构建一个完整的UE项目CI流水线。4.1 环境准备与缓存策略UE项目构建是资源密集型任务尤其是引擎源码的编译。在CI中每次都从头编译引擎是不现实的。常见的策略是使用预编译的引擎版本从Epic的服务器下载特定版本的已编译引擎。缓存引擎和中间文件利用CI系统的缓存功能将编译好的引擎和项目的中间文件IntermediateSaved下的部分目录缓存起来下次构建时复用。uet本身不提供下载引擎的功能但可以很好地与现有的引擎管理工具如自己编写的脚本或第三方工具协同工作。在CI脚本中我们通常先准备好引擎再调用uet。# .github/workflows/ci.yml 片段 name: UE Project CI on: [push, pull_request] jobs: build-and-test: runs-on: windows-latest # 或 macos-latest, ubuntu-latest steps: - name: Checkout Code uses: actions/checkoutv4 with: submodules: recursive # 如果引擎是git子模块 - name: Cache UE Engine uses: actions/cachev3 id: cache-engine with: path: D:/UE_5.3 # 假设引擎安装在此路径 key: ${{ runner.os }}-ue-5.3-${{ hashFiles(**/.ueversion) }} # 用文件内容哈希作为缓存键 - name: Setup UE Engine (if not cached) if: steps.cache-engine.outputs.cache-hit ! true run: | # 这里调用你自己的引擎安装脚本 # 例如使用 PowerShell 调用 Epic 的安装程序 API或解压预下载的引擎包 ./scripts/setup_engine.ps1 -Version 5.3 -InstallPath “D:/UE_5.3” - name: Install Python and uet run: | python -m pip install --upgrade pip pip install uet # 从 PyPI 安装 uet - name: Generate Project Files run: uet generate env: UE_PATH: “D:/UE_5.3” # uet 可以通过环境变量识别引擎路径 - name: Build Project run: uet build --configuration Development --platform Win64 - name: Run Unit Tests run: uet test --type unit --report-dir ./TestResults --report-format junit continue-on-error: true # 测试失败不应立即终止以便上传报告 - name: Upload Test Results if: always() # 无论成功失败都上传报告 uses: actions/upload-artifactv3 with: name: test-results path: ./TestResults/4.2 多平台构建矩阵对于需要发布到多个平台Windows, Linux, Consoles, Mobile的项目可以利用CI的矩阵构建功能。jobs: build-matrix: strategy: matrix: platform: [Win64, Linux, Android] include: - platform: Android sdk-setup: true runs-on: ${{ matrix.platform Win64 windows-latest || matrix.platform Linux ubuntu-latest || macos-latest }} # Android 构建通常也在 Windows 或 Linux 上进行 steps: - ... - name: Setup Android SDK (if needed) if: matrix.sdk-setup run: ./scripts/setup_android_sdk.ps1 - name: Build run: uet build --platform ${{ matrix.platform }}4.3 制品管理与发布构建和测试通过后最后一步通常是生成可发布的包Package。- name: Package for Distribution run: | uet cook --platform Win64 uet package --configuration Shipping --platform Win64 env: # 打包可能需要额外的签名证书等环境变量 SIGNING_CERTIFICATE: ${{ secrets.SIGNING_CERTIFICATE }} - name: Upload Build Artifact uses: actions/upload-artifactv3 with: name: MyGame-Win64-Shipping path: | ./Build/Win64/Shipping/MyGame/ !**/*.pdb # 排除符号文件 !**/Intermediate/5. 常见问题、排查技巧与进阶用法5.1 安装与配置问题问题1pip install uet失败或安装后uet命令找不到。排查首先确认Python建议3.8已正确安装并已添加到系统PATH。使用python --version和pip --version检查。在Windows上安装后可能需要重启终端或者手动将Python的Scripts目录如C:\Users\用户名\AppData\Local\Programs\Python\Python39\Scripts添加到PATH。解决尝试使用python -m uet来代替uet命令。如果还是不行检查是否有多个Python版本冲突。问题2uet找不到Unreal Engine。排查uet会按以下顺序查找引擎1).uet.toml中的engine.location2) 环境变量UE_PATH3) 常见的默认安装路径4) Epic Games Launcher的清单文件。解决最可靠的方法是在项目根目录的.uet.toml中明确指定引擎路径。或者在运行uet命令前设置UE_PATH环境变量。5.2 构建与编译问题问题3编译失败报错Missing UnrealBuildTool或UnrealBuildTool版本不匹配。排查这通常意味着uet找到了引擎目录但目录结构不对例如指向了包含多个版本引擎的根目录而非具体的UE_5.3目录或者该引擎版本未完整安装缺少源码或开发文件。解决检查.uet.toml中的路径是否精确指向了类似D:/UE_5.3/Engine这样的具体引擎版本目录。对于从Epic Games Launcher安装的引擎确保安装了对应版本的“引擎源码”。问题4增量构建失效每次都全量编译。排查检查Intermediate和Saved目录的权限确保构建进程有写入权限。有时杀毒软件或云同步软件如OneDrive会锁定这些目录下的文件导致时间戳更新异常。解决尝试执行一次uet clean如果uet提供了该命令或插件来清理中间文件然后重新构建。在CI环境中为了绝对干净通常建议每次构建前都清理Binaries和Intermediate目录。5.3 测试执行问题问题5功能测试超时或无响应。排查功能测试启动编辑器进程可能因为加载大型地图、执行复杂蓝图逻辑而耗时过长。也可能是测试本身存在死循环或崩溃导致进程无法正常退出。解决为uet test命令增加--timeout 300单位秒参数设置一个合理的超时时间。同时检查编辑器的日志输出uet通常会将其重定向到控制台或文件看是否有加载错误或断言失败。对于不稳定的测试考虑将其标记为“不稳定”或拆分。问题6测试报告为空或格式错误。排查uet的测试报告生成依赖于正确解析编辑器或测试运行器的输出。如果测试本身没有按照预期格式输出日志报告就会为空。解决首先确保测试本身能正常运行并输出日志。可以手动运行一次测试观察控制台输出。对于自定义的测试类型可能需要编写或调整uet的测试结果解析器这涉及到自定义插件开发。5.4 进阶用法编写自定义uet插件当内置命令无法满足需求时编写自定义插件是终极解决方案。一个最简单的插件只需要定义一个Python类并注册一个命令。# 文件my_project/plugins/my_custom_plugin.py from uet.core.commands import command, BaseCommand command(“upload”, “将打包好的游戏上传到内部服务器”) class UploadCommand(BaseCommand): def setup_arguments(self, parser): parser.add_argument(“--version”, requiredTrue, help“版本号”) parser.add_argument(“--platform”, default“Win64”, help“目标平台”) def execute(self, args, unknown_args): # 你的业务逻辑 build_path f“./Build/{args.platform}/Shipping” version args.version print(f“准备上传 {build_path} 的版本 {version}...”) # 调用上传脚本或API # ... print(“上传完成”) # 在 .uet.toml 中注册插件 # [plugins] # paths [“./plugins”]然后你就可以像使用内置命令一样使用它uet upload --version 1.2.3 --platform Win64。这让你能将项目特有的部署、后处理、资源管理等流程无缝集成到统一的uet工作流中。5.5 性能调优与最佳实践善用缓存在CI中缓存DerivedDataCache可以极大加速材质的Shader编译和资源的派生数据生成。将Engine/DerivedDataCache和项目下的Saved/DerivedDataCache加入缓存策略。分布式构建对于超大型项目可以考虑使用Distributed Compilation工具如 Incredibuild 或 SN-DBS。uet build命令可以通过传递-j参数来利用这些工具但具体的集成需要在构建机器上预先配置好环境。配置文件分环境可以创建多个.uet.toml文件如.uet.ci.toml、.uet.dev.toml通过环境变量UET_CONFIG_FILE来指定使用哪个。这样可以为开发、测试、生产环境配置不同的默认参数。日志分级使用--verbosity参数控制uet的输出详细程度。在CI中通常使用verbose或veryverbose以便排查问题在本地快速构建时使用quiet或minimal减少干扰。uet的价值在于它通过约定大于配置的方式将虚幻引擎项目复杂的构建与测试流程标准化、自动化。它降低了新成员的上手成本提升了团队协作的效率并为稳健的CI/CD实践打下了坚实的基础。虽然初期需要一些学习和配置投入但长远来看这份投资对于任何严肃的虚幻引擎项目团队都是值得的。
返回列表