ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用批处理脚本实现Keil多工程自动化编译的完整指南

用批处理脚本实现Keil多工程自动化编译的完整指南 多工程、多版本、发版频繁手动编译到崩溃——这是我写这套批处理脚本的最原始动机。当时手里五块板子五个独立 Keil MDK 工程每次发布测试固件都要逐个打开 μVision 点 Rebuild再等编译条跑完五个工程顺利也要十几分钟中途切错工程、忘编译某个模块、忘记记录版本问题是常事。后来我花了一个下午研究 UV4.exe 的命令行能力写了一组 Windows 批处理脚本把遍历工程、自动编译、保存日志、汇总报告全部串起来。这篇文章就把这套方案的完整链路讲透命令行参数原理、第一版骨架、路径与日志的健壮性处理、编译失败快速定位以及定时触发和并行编译的进阶玩法最后给出可直接套用的完整脚本和踩坑清单。1. 为什么我要给 Keil 工程写批量编译脚本1.1 先从手动编译的痛点说起手动逐个编译 Keil 工程的痛不是慢一个字能概括的。第一是重复劳动五个工程每次发版都要走一遍打开、点击、等待、关闭的流程动作一模一样纯粹浪费注意力第二是容易漏工程一多或者中间被微信、电话打断经常出现某一个板子忘了重新编译带着旧固件进了联调第三是没记录编译成功还是失败、有没有警告全靠当时眼睛看一眼没有留痕出问题回溯时完全抓瞎。1.2 什么场景值得自动化什么场景不值得不是所有工程都值得上脚本。我的判断标准很简单如果这个工程一周要手点编译三次以上或者同一批次要编译的工程数量超过三个就值得写自动化。反之如果是随手建的 demo 工程一个月都不一定编译一次没必要折腾GUI 里点一下更直接。自动化批量编译真正划算的场景我总结了三条多工程发版一个产品多个板卡各自独立工程发版时要求全部产出最新固件。多版本维护同一个产品线有多个分支每个分支的工程文件不同需要各自编译验证。频繁回归验证公共代码改动后需要快速验证所有下游工程能不能编过。如果你正好落在这些场景里那么这套批处理脚本能帮你把原本半小时的重复劳动压缩到一条命令而且每次编译都会留下完整记录。2. 先看核心UV4.exe 的命令行参数和返回码2.1 藏在安装目录里的命令行工具Keil MDK 安装完成后IDE 的主程序是 UV4.exe通常位于C:\Keil_v5\UV4\UV4.exe或C:\Keil\UV4\UV4.exe。它表面上是个图形界面程序实际上一直支持命令行编译模式官方叫法是 µVision CommandLine 模式。很多嵌入式工程师用了几年 Keil可能都没注意到这一点因为 GUI 里根本没有入口文档也藏得深。命令行编译的基本语法是UV4.exe -b 工程文件.uvprojx -o 输出日志.txt-b表示执行编译Build-o指定编译过程输出到一个日志文件。如果你需要全量重编用-r代替-bRebuild 所有文件。2.2 我实际用到的几个参数和它们的含义我把日常批量编译脚本中最常用的参数整理成一张表方便直接对照参数作用实战说明-bBuild只编译修改过的文件日常验证用-rRebuild强制全部重新编译发版、怀疑增量缓存异常时用-j0让 UV4.exe 进程等待编译结束再退出批处理拿返回码的核心少它不行-o 文件编译信息输出到指定日志文件日志路径建议用绝对路径-t Target名编译指定 Target工程有多个 Target 时用缺省编 active target-j0是最容易被忽略但影响最大的参数。不带它时UV4.exe 启动后会立刻把控制权交还给命令行批处理还没拿到结果进程就结束了。加上-j0后UV4.exe 会一直等到编译结束才退出退出码才是真正有意义的编译结果。2.3 返回码的含义UV4 命令行编译的返回码ERRORLEVEL定义如下返回码含义0编译成功无错误无警告1编译成功但有警告2编译有错误3编译存在致命错误批处理脚本就是靠%errorlevel%或者延迟变量!errorlevel!拿到这个值然后判断每个工程的结果。2.4 动手测一条编译命令在写完整脚本之前我建议你先在命令行里手动跑一次确认环境是通的C:\Keil_v5\UV4\UV4.exe -j0 -b D:\Projects\Board_A\Board_A.uvprojx -o D:\Projects\Board_A\build_test.log跑完后用echo %errorlevel%看返回码同时打开日志文件看内容。如果日志长这样说明基础命令没问题Rebuild target Target 1 compiling main.c... linking... Program Size: Code12288 RO-data720 RW-data32 ZI-data1536 .\output\Board_A.axf - 0 Error(s), 2 Warning(s).我踩过一个小坑有些电脑装了老版本 Keil工程却是用新版 Keil 保存的命令行编译时 UV4 会在日志里提示工程版本过高返回码变成 1 或者 2。这个后面在踩坑清单里细说。3. 第一版批量编译脚本先让流程能跑通3.1 脚本要做的事情拆成五步写脚本之前先明确流程。批量编译这件事拆开就五步遍历指定根目录下所有.uvprojx工程文件。对每一个工程调用 UV4.exe 进行命令行编译。编译日志统一保存到独立目录避免污染工程目录。根据返回码判断成功/失败/有警告。输出一份汇总报告记录每个工程的结果。对应到批处理语法第一步用for /r递归遍历目录第二步调用 UV4 并传递参数第三到第五步用set /a累加统计和echo写报告。3.2 第一版骨架代码下面这个骨架已经可以实际使用我保留了必要注释方便你对照理解echo off setlocal enabledelayedexpansion :: 配置区 set UV4C:\Keil_v5\UV4\UV4.exe set ROOT%~1 if %ROOT% set ROOT%CD% set LOG_DIR%ROOT%\_build_logs set REPORT%ROOT%\_build_report.txt :: :: 清空旧报告 if exist %REPORT% del %REPORT% if not exist %LOG_DIR% mkdir %LOG_DIR% echo Build Report - %date% %time% %REPORT% echo. %REPORT% set /a total0, ok0, warn0, fail0 for /r %ROOT% %%f in (*.uvprojx) do ( set /a total1 set log%LOG_DIR%\%%~nf_build.log echo. echo echo [!total!] %%~nxf echo :: 编译前清掉上次日志避免混淆 if exist !log! del !log! :: 调用 UV4 编译 %UV4% -j0 -b %%f -o !log! set ret!errorlevel! :: 判断返回码 if !ret!0 ( set /a ok1 echo Result: echo [!time!] %%f ^| OK %REPORT% ) else if !ret!1 ( set /a warn1 echo Result: OK WITH WARNINGS echo [!time!] %%f ^| OK_WITH_WARNINGS %REPORT% ) else ( set /a fail1 echo Result: FAILED echo [!time!] %%f ^| FAILED %REPORT% ) ) echo. echo echo Done: total!total! ok!ok! warn!warn! fail!fail! echo echo Report: %REPORT%第一版里有两个细节值得注意。第一个是setlocal enabledelayedexpansion这行决定了在for循环内部能否用!变量!获取实时值。批处理里%变量%在循环体被解析时就已经展开成旧值如果不在开头启用延迟变量扩展!total!、!log!、!ret!这些循环里会变化的值全都拿不到最新结果脚本会出一堆莫名其妙的问题。不用记原理直接记住要在循环中读写变量就必须写这一行。第二个是日志文件命名。第一版直接用%%~nf取工程文件名作为日志名这个写法在工程都在同一层目录的时候没问题但工程允许分布在不同子目录里一旦有两个同名工程文件后编译的那个会把前一个的日志覆盖掉。这个我在下一节专门改进。4. 从能跑到好用路径、工作目录和日志命名4.1 pushd 到工程目录看不见但救命的细节第一版脚本能编译但我在实际使用中很快遇到一个问题少数工程编译时报出一堆奇怪的找不到文件错误。排查后确认问题出在 UV4 的工作目录上。Keil 工程文件.uvprojx内部记录了大量相对路径比如源文件路径、输出目录、链接脚本路径。这些相对路径在绝大多数情况下是相对于工程文件所在目录解析的但 UV4 在某些版本、某些配置下会受启动时工作目录的影响。批处理脚本从任意目录执行时UV4 继承的当前工作目录不是工程目录就可能解析错路径。解决办法是在调用 UV4 之前用pushd切到工程文件所在目录编译完再popd切回来for /r %ROOT% %%f in (*.uvprojx) do ( pushd %%~dpf %UV4% -j0 -b %%~nxf -o !log! set ret!errorlevel! popd )%%~dpf是 for 变量展开语法取的是当前文件路径的盘符目录部分等于拿到工程所在文件夹。%%~nxf是文件名扩展名。这样 UV4 的工作目录就是工程目录本身路径解析和 GUI 里点编译完全一致。我强烈建议你从第一版就加上这个写法不然后面会被奇怪的路径问题折磨。4.2 路径带空格、中文和特殊字符的防御Windows 下很多工程路径喜欢带空格比如D:\My Projects\Board A\。批处理脚本一旦涉及带空格的路径引号必须包好否则路径会被拆成多个参数。我在脚本里统一采用双引号包裹所有路径变量引用的策略调用 UV4 时%UV4% -j0 -b %%f -o !log!。pushd 时pushd %%~dpf。写报告时echo ... %REPORT%。中文路径在纯批处理里一般没问题但前提是脚本文件本身保存为 ANSI/GBK 编码如果保存成 UTF-8 带 BOM批处理解析第一行命令时可能直接乱码。我后来索性把脚本里的 echo 提示全部改成英文避免各种代码页坑。还有一个容易被忽略的特殊字符是and 符号。它在批处理里是命令分隔符即使路径用引号包起来在for展开和set赋值时仍然可能被解释成执行另一个命令。如果工程路径里出现了脚本表现会非常诡异。我的建议是源头解决Keil 工程路径和文件名里尽量不要用、^、( )这些特殊字符或者至少不要放在脚本要遍历的目录里。4.3 日志命名改进按相对路径生成回到同一个问题同名工程日志互相覆盖。我的改进方案是让日志文件名带上工程相对于根目录的路径把反斜杠替换成下划线比如set rel%%f set rel!rel:%ROOT%! set rel!rel:\_! set log%LOG_DIR%_!rel!.log第一行set rel%%f拿到完整工程路径第二行把根目录前缀去掉得到相对路径比如Sensors\Board_A\Board_A.uvprojx第三行把所有反斜杠替换成下划线最后拼上.log后缀。这样即使根目录下有几百个工程日志也不会互相覆盖。这个字符串替换技巧是批处理里非常实用的操作!变量:被替换替换值!一定要掌握。4.4 自动定位 UV4.exe脚本写好后换一台电脑用UV4 安装路径可能不一样。如果把路径硬编码在脚本开头换机器就得改脚本很麻烦。我在最终脚本里做了一步自动探测set UV4 if exist C:\Keil_v5\UV4\UV4.exe set UV4C:\Keil_v5\UV4\UV4.exe if exist C:\Keil\UV4\UV4.exe set UV4C:\Keil\UV4\UV4.exe if not defined UV4 ( echo [ERROR] UV4.exe not found in common paths. echo Please set UV4 path manually. exit /b 127 )先检查两个最常见的安装路径找不到就直接报错退出避免后续所有编译白跑。如果公司内部有统一的 Keil 部署路径可以在脚本开头通过set UV4...直接改。更正规的做法是读注册表或环境变量但实测下来这个常见路径探测手动兜底的方案已经够用而且代码直观好维护。5. 编译失败快速定位报告和日志里怎么找有效信息5.1 UV4 日志的基本结构UV4 编译生成的日志文件内容大致分几段先是Rebuild target Target 1这一行下面是每个源文件的compiling xxx.c...然后是链接信息和最终统计行Rebuild target Target 1 compiling main.c... compiling uart.c... main.c(23): error: #20: identifier config is undefined uart.c(11): warning: #177-D: variable len was declared but never referenced linking... .\output\Board_A.axf - 1 Error(s), 1 Warning(s).可以看出错误行有固定的特征文件名(行号): error:或者文件名(行号): warning:。5.2 用 findstr 过滤错误和警告批处理里过滤文本行最稳的就是findstr。我可以把每个工程的日志过滤出错误行和警告行写入独立的精简报告这样打开汇总文件就能一眼看到所有问题不用逐个翻完整日志。set errLog%LOG_DIR%\_errors_!rel!.txt findstr /i /c:: error: /c:: warning: !log! !errLog!这里我用了/i忽略大小写匹配模式是: error:和: warning:注意冒号前面有个空格这是为了对齐编译器的真实输出格式。为什么不直接匹配error而不加冒号因为日志最后一行- 1 Error(s)也会匹配 error导致把总体统计行误当成单条错误统计数量就失真了。加上冒号和空格后Error(s)不会命中只有真正的代码错误行才会被过滤出来。统计数量和写入报告set /a errCnt0 for /f %%i in (findstr /i /c:: error: !log! ^| find /c /v ) do set errCnt%%i这个写法先findstr过滤所有错误行再通过find /c /v 统计行数。如果错误数为 0find返回的计数就是 0循环正常赋值。注意|管道符在for /f的括号里要转义成^|否则会被解析成命令分隔符这个细节很容易忽略。5.3 报告信息设计完整报告我设计成三块汇总表工程名、编译结果、错误数、警告数、耗时。失败工程清单只要编译失败的工程路径。错误详情索引指向每个工程对应的精简错误日志文件。报告里每行写一个工程格式如下[2025-01-12 14:33:01] D:\Projects\Board_A\Board_A.uvprojx | FAILED | ERR1 WARN1 | 00:01:23 [2025-01-12 14:35:40] D:\Projects\Board_B\Board_B.uvprojx | OK_WITH_WARNINGS | ERR0 WARN2 | 00:02:10 [2025-01-12 14:40:22] D:\Projects\Board_C\Board_C.uvprojx | OK | ERR0 WARN0 | 00:01:45手动编译时最恼火的就是编译失败了但不知道错在哪这个设计把失败工程和错误数量直接推到眼前。需要看具体哪一行打开对应错误日志就能定位到源码行号。5.4 批处理里的耗时要小心跨午夜批处理里计算编译耗时最朴素的做法是用%time%取开始和结束时间再转成秒做差。但如果你在晚上十一点多触发编译真编译到凌晨直接做差会出现负数当年我就被这个坑过一次。处理办法是判断差值如果是负数加一天的总秒数:CalcOffset for /f tokens1-2 delims:. %%a in (%~1) do set h%%a set m%%b ... goto :eof实际上完整的时间转秒逻辑要处理小时、分钟、秒、百分秒四个字段批处理写起来有点啰嗦我不建议在纯批处理里做得太精细够用就行。我在最终脚本里只到秒级精度for /f tokens1-3 delims:., %%a in (%startTime%) do set /a s1%%a*3600%%b*60%%c for /f tokens1-3 delims:., %%a in (%endTime%) do set /a s2%%a*3600%%b*60%%c set /a elapseds2-s1 if !elapsed! lss 0 set /a elapsed86400delims:.,表示同时用冒号、点、逗号做分隔符。注意%startTime%在普通脚本里可以直接用%包裹但如果这段代码放在括号代码块里就要用!startTime!延迟扩展否则拿到的还是解析时的旧值。6. 再进一步定时编译、增量编译与并行编译6.1 用 Windows 任务计划程序定时编译脚本写好后我最常做的一件事就是配合 Windows 任务计划程序让它在每天下班后自动编译一次全量工程。以 Windows 10/11 为例打开任务计划程序新建任务触发器选每天并设置固定时间操作里启动程序选cmd.exe参数填/c D:\tools\keil_build_all.bat D:\Projects\MyProduct有两个细节必须注意一是任务计划里要勾选使用最高权限运行因为 Keil 工程如果放在 Program Files 这类受保护目录下普通权限可能没有写权限二是 Windows 在睡眠/休眠状态下任务会被错过我一般把唤醒计算机以运行此任务也勾上确保定时触发有效。实测下来这个组合等于给团队加了一个夜间自动回归第二天早上直接看报告就行。6.2 简单增量编译按文件修改时间判断批处理里做完整的增量编译意义不大因为 Keil 自身的-b已经带了增量能力只编译修改过的源文件。这里我想说的增量是对工程粒度做跳过如果某个工程最近都没改过源码跳过它省下完整的编译时间。借助forfiles可以判断一个目录里是否存在比指定日期更新的文件forfiles /P %projDir% /M *.c /D %dateStr% /C cmd /c exit 0 nul 21 if !errorlevel!0 ( echo No source changes, skip... goto :next )实际调试时%date%在不同系统区域设置下格式不一样解析很容易出问题。所以我的建议是这个增量判断只作为锦上添花不要把它做成核心逻辑。优先级永远是该编译的必须编译跳过逻辑写复杂了反而可能漏编译。我现在用的方案是提供一个手动参数脚本接收all或quickall全部重编quick只编译指定清单里的工程把增量判断交给使用者自己控制简单可靠。6.3 并行编译可以试但别一开始就试串行编译五个工程每个两分钟一共十分钟能接受。但如果团队做大中型固件单工程编译都要五分钟五个工程串行就是二十五分钟这时候自然会想并行。批处理里并行启动多个进程的常见写法是start /b cmd /c %UV4% -j0 -b Project_A.uvprojx -o A.log start /b cmd /c %UV4% -j0 -b Project_B.uvprojx -o B.log或者用start /wait等待单个进程配合多个start模拟并发。但我在实际使用中对并行编译的态度是可以试但别一上来就全量并行原因有两个一是 Keil 的编译器进程armcc/armclang对 CPU 和磁盘 IO 压力很大多个 UV4 同时编译在同一块机械硬盘上速度不但没提升反而会因为磁盘争抢变得很慢。SSD 会好很多。二是许可证和工程依赖问题我在一台机器上并行编译过两个工程其中一个偶尔会弹许可证错误或者输出文件被另一个进程占用。多工程共用同一个 Output 目录时并行基本必炸。如果你确实想并行我建议先拿两个独立工程试跑确认没问题再逐步加并发数。脚本层面我会在并行前预留一个简单的信号量逻辑比如最多同时跑两个 UV4 进程用 PowerShell 辅助等待$ps () $ps Start-Process -FilePath C:\Keil_v5\UV4\UV4.exe -ArgumentList -j0,-b,Project_A.uvprojx,-o,A.log -PassThru $ps Start-Process -FilePath C:\Keil_v5\UV4\UV4.exe -ArgumentList -j0,-b,Project_B.uvprojx,-o,B.log -PassThru $ps | Wait-Process这样至少等两个都跑完再继续。不过说实话目前我的主力方案还是串行加定时触发稳定性优先。6.4 未来接 CI批处理是最小闭环如果团队要做持续集成批处理脚本可以作为最小闭环。无论 Jenkins、GitLab CI 还是 Codex 类的 AI 辅助环境Windows 节点上执行拉代码 - 跑批处理 - 收集报告这条链路并不复杂。脚本只需保证退出码有意义全部编译通过返回 0任何一个工程失败返回 1。这样 CI 平台可以精确判断构建是否成功。我在脚本最后设置退出码if %fail% gtr 0 ( exit /b 1 ) else ( exit /b 0 )这一步看似简单但如果你直接把脚本交给 CI 平台没有设置退出码CI 会认为即使编译失败任务也是成功的那么这个自动化就白做了。7. 最终脚本全文与实战踩坑清单7.1 最终脚本把前面所有改进合到一起就是我目前在用的完整版本。脚本保存为.bat文件建议用 ANSI/GBK 编码保存调用方式build_all.bat D:\Projects\MyProduct脚本默认遍历指定根目录下所有.uvprojx编译日志存到根目录的_build_logs文件夹报告文件是_build_report_当前日期.txt。echo off setlocal enabledelayedexpansion :: Config set UV4 if exist C:\Keil_v5\UV4\UV4.exe set UV4C:\Keil_v5\UV4\UV4.exe if exist C:\Keil\UV4\UV4.exe set UV4C:\Keil\UV4\UV4.exe if not defined UV4 ( echo [ERROR] UV4.exe not found. echo Please set UV4 path in script. exit /b 127 ) set ROOT%~1 if %ROOT% set ROOT%CD% set LOG_DIR%ROOT%\_build_logs set REPORT%ROOT%\_build_report_%date:~0,4%%date:~5,2%%date:~8,2%.txt :: if not exist %LOG_DIR% mkdir %LOG_DIR% if exist %REPORT% del %REPORT% echo Build Report - %date% %time% %REPORT% echo. %REPORT% set /a total0, ok0, fail0, warn0 set FAIL_LIST for /r %ROOT% %%f in (*.uvprojx) do ( set /a total1 set projPath%%f set projName%%~nxf :: generate unique log name by relative path set rel%%f set rel!rel:%ROOT%! set rel!rel:\_! set log%LOG_DIR%_!rel!.log echo. echo echo [!total!] !projName! echo if exist !log! del !log! set startTime!time! pushd %%~dpf %UV4% -j0 -b %%~nxf -o !log! set ret!errorlevel! popd set endTime!time! :: elapsed seconds for /f tokens1-2 delims:., %%a in (!startTime!) do set /a sh%%a, sm%%b for /f tokens2-3 delims:., %%a in (!startTime!) do set /a ss%%a*1 for /f tokens1-3 delims:., %%a in (!startTime!) do set /a s1%%a*3600%%b*60%%c for /f tokens1-3 delims:., %%a in (!endTime!) do set /a s2%%a*3600%%b*60%%c set /a elapseds2-s1 if !elapsed! lss 0 set /a elapsed86400 :: count errors and warnings set errCnt0 set warnCnt0 for /f %%i in (findstr /i /c:: error: !log! 2^nul ^| find /c /v ) do set errCnt%%i for /f %%i in (findstr /i /c:: warning: !log! 2^nul ^| find /c /v ) do set warnCnt%%i :: result if !ret!0 ( set /a ok1 set resultOK ) else if !ret!1 ( set /a warn1 set resultOK_WITH_WARNINGS ) else ( set /a fail1 set resultFAILED set FAIL_LIST!FAIL_LIST!!projPath! !result! ERR!errCnt!n ) echo !result! runtime!elapsed!s err!errCnt! warn!warnCnt! echo [%date% %time%] !projPath! ^| !result! ^| ERR!errCnt! WARN!warnCnt! ^| !elapsed!s %REPORT% ) :: summary echo. echo echo Total: !total! OK: !ok! Warn: !warn! FAILED: !fail! echo echo. echo FAILED LIST: echo !FAIL_LIST! echo. echo Full Report: %REPORT% echo Build Logs: %LOG_DIR% :: exit code for CI if !fail! gtr 0 exit /b 1 exit /b 0这个版本里我保留了耗时统计、错误警告统计、失败清单和 CI 退出码日常用已经足够。7.2 使用中的注意事项有几个使用细节我再啰嗦一遍都是实际跑过才发现的不建议把脚本放到 Keil 安装目录里避免修改受保护目录引发权限问题放在独立工具目录或工程根目录都行。日志会越积越多_build_logs目录跑一个月可能几百兆可以加个计划任务定期清理七天前的日志或者直接在脚本开头用forfiles /P %LOG_DIR% /S /M *.log /D -7 /C cmd /c del path删除老日志。第一次跑之前先手动跑一个单工程确认 UV4 路径、许可证、返回码都正常不然脚本批量跑完才发现全是同一个环境问题等于白跑一趟。7.3 实测踩坑排查表我把这些年用命令行编译 Keil 工程遇到的典型问题整理成一张表按频率排序现象可能原因处理办法所有工程返回码都是 1日志里是版本提示UV4 版本低于工程创建工具版本统一升级 Keil MDK 版本日志为空或只生成 0 字节文件路径含空格命令没完整配对引号检查所有引号确保成对包裹编译报cannot open source file工作目录不正确确认脚本中已 pushd 到工程目录字符路径导致命令截断路径含 被解析为分隔符路径改用下划线或短路径中文路径日志乱码脚本编码不是 ANSI/GBK用记事本另存为 ANSI 编码杀毒软件提示 UV4 行为异常命令行模式触发了行为监测将工程目录和日志目录加入白名单定时任务没有按计划执行系统睡眠/休眠错过了触发时间勾选唤醒计算机以运行此任务跨午夜编译耗时为负时间差计算未处理跨天差值为负时加 86400 秒7.4 最后再分享一个个人体会这套脚本来来回回用了一年多最大的感受是批处理脚本的价值不在于技术多复杂而在于把人的判断从重复劳动中抽离出来。以前我担心自动化会漏掉什么后来发现真正容易漏掉的恰恰是手动操作时的注意力分散。现在不管是发版前全量构建还是夜间自动回归脚本跑完我看一眼报告就知道所有工程的状态心里踏实得多。如果你现在还在手动编译多个 Keil 工程强烈建议先拿我这个骨架跑起来。不要一上来就追求完整的报告和定时任务先在命令行里把单个工程编通再把循环串起来最后根据你手上的工程结构调整日志命名和结果判断。等跑通一次全量编译你会发现这个问题早就该解决了。
返回列表