RT-Thread Keil项目编译文件清理:自动化脚本与Git集成实践 📅 2026/8/19 5:25:38 1. 为什么需要清理Keil编译过程文件在RT-Thread项目开发中使用Keil MDK作为IDE是很多嵌入式工程师的日常。每次点击编译按钮Keil都会在项目目录下生成大量的中间文件和输出文件。这些文件我们通常称之为“过程文件”或“编译产物”包括但不限于.o目标文件、.d依赖文件、.lst列表文件、.axf可执行文件、.map内存映射文件以及各种.build_log等。日积月累这些文件会占据可观的磁盘空间一个中等规模的项目其Objects和Listings文件夹轻松就能达到几十甚至上百兆。但这还不是最关键的。真正让人头疼的是版本管理。如果你使用Git、SVN等工具管理代码这些不断变化的编译文件会成为仓库的“噪音”。每次编译后git status都会显示一大堆未跟踪的修改让你难以分辨哪些是真正的源代码变更。更糟糕的是如果团队成员不小心将这些过程文件提交到了仓库会导致仓库体积无谓地膨胀拉取和克隆代码的速度变慢甚至可能因为不同机器上编译环境如工具链版本、路径的细微差异导致从仓库拉取的过程文件在你的机器上无法使用引发编译错误。因此定期或是在提交代码前清理这些过程文件是一个保持项目整洁、提升协作效率的好习惯。手动删除当然可以右键选中Objects和Listings文件夹然后按Delete。但这种方法效率低下且容易遗漏尤其是当项目结构复杂存在多级子目录时。我们的目标是找到一个一劳永逸、可靠且可重复执行的方法。这就是为什么我们需要一个自动化的“删除脚本”。这个脚本的核心价值在于一键清理释放空间净化仓库让开发环境回归纯粹。2. 编译过程文件详解它们是什么有什么用为何能删在动手写脚本之前我们有必要搞清楚Keil到底生成了哪些文件它们的作用是什么以及为什么我们可以安全地删除它们。知其然更要知其所以然这样在遇到问题时才能从容应对。2.1 核心输出目录Objects 与 ListingsKeil MDK默认或通过配置会在项目根目录下创建两个主要的输出文件夹Objects目录这是编译过程的核心产出目录。当你编译一个C/汇编源文件如main.c时编译器ARMCC或AC6会将其翻译成机器码生成对应的.o目标文件存放在这里。链接器ArmLink则将这些.o文件、库文件.lib以及分散加载文件.sct链接在一起生成最终的可执行文件.axf和二进制镜像.bin或.hex如果使能了生成选项。简单来说Objects目录存放的是从源代码“编译”和“链接”后的直接结果。Listings目录这个目录存放的更多是用于“分析”和“调试”的中间文件。例如.lst列表文件包含了源代码与汇编指令的混合视图对于深度优化和排查某些硬件相关问题时非常有用。.map文件则是链接过程的内存“地图”详细列出了每个函数、变量被放置到了哪个地址占用了多少空间是分析内存使用情况和排查链接错误的神器。2.2 常见过程文件类型与可删除性分析下表列出了Keil编译后常见的过程文件并分析了其作用和删除安全性文件扩展名通常位置作用描述是否可安全删除备注.o/*.objObjects\目标文件由单个源文件编译生成。是链接的输入。是由源代码重新编译即可生成。删除后下次编译会重新产生。.dObjects\依赖关系文件由编译器生成。记录了源文件所依赖的头文件列表。是用于实现增量编译。删除后首次编译会重新生成不影响功能。.axfObjects\ARM可执行文件格式包含完整的调试信息、代码和数据。用于调试和烧录。是由链接过程生成。删除后重新编译链接即可。这是调试器如J-Link直接加载的文件。.bin/*.hexObjects\或项目根目录纯二进制或Intel HEX格式的镜像文件用于烧录到芯片Flash。视情况如果需要保留某个特定版本用于生产烧录则应备份。否则可删重新编译即可生成。.lstListings\汇编列表文件混合了源代码和生成的汇编指令。是用于分析代码生成质量。删除无任何运行时影响。.mapListings\链接映射文件详细描述内存布局。建议保留对于分析内存溢出、优化空间非常有用。建议在每次重要版本发布时归档日常可删。.build_log.htm项目根目录编译过程的HTML格式日志。是仅记录本次编译信息可删。*.crf/*.Objects\浏览信息文件用于Keil IDE内的符号跳转、查找引用。是删除后IDE的“Go to Definition”等功能需要重新编译后才能使用。JLinkSettings.ini项目根目录J-Link调试器的会话配置文件。否包含你的调试器配置如接口、速度。删除会丢失个人调试设置。*.uvoptx项目根目录Keil工程选项文件包含断点、书签、调试窗口布局等工作区设置。否绝对不要删除这是你的个人工作环境配置。*.uvprojx项目根目录Keil工程文件包含目标、组、文件列表、编译选项等工程设置。否绝对不要删除这是工程的定义文件。注意*.uvoptx和*.uvprojx是工程的“命脉”脚本必须将它们排除在删除范围之外。误删这两个文件工程将无法正常打开或会丢失所有个性化设置。2.3 为何可以安全删除因为所有这些过程文件都是“派生文件”Derived Files。它们的源头是你的源代码.c,.h,.s和工程配置文件.uvprojx 包含编译选项、链接脚本路径等。只要源代码和工程配置不变在任何一台配置好相同工具链的电脑上重新编译生成的过程文件在功能上都是完全等价的尽管由于时间戳等原因二进制内容可能不完全一致。因此删除它们不会损害项目的“源”信息只会清除“中间结果”。3. 手动清理与脚本自动化方案对比了解了目标我们来看看实现路径。从最原始的手动操作到集成度高的自动化方案各有优劣。3.1 方案一手动删除最基础操作在文件资源管理器中手动选中Objects和Listings文件夹按Delete键。或者进入Keil点击Project - Clean Targets菜单如果存在。优点无需任何准备简单直接。缺点效率低下每次都要重复操作。容易遗漏可能还有其他自定义输出目录或散落的过程文件如单独的.bin文件。风险高容易误选、误删其他重要文件。不可重复无法作为固定流程固化下来。3.2 方案二使用批处理脚本.bat- Windows原生方案这是最经典、兼容性最好的方案。批处理脚本轻量在任何Windows电脑上都能直接运行。echo off chcp 65001 nul echo 正在清理RT-Thread Keil工程编译文件... echo. REM 删除 Objects 目录 if exist Objects ( echo 删除 Objects 目录... rmdir /s /q Objects ) else ( echo Objects 目录不存在跳过。 ) REM 删除 Listings 目录 if exist Listings ( echo 删除 Listings 目录... rmdir /s /q Listings ) else ( echo Listings 目录不存在跳过。 ) REM 删除根目录下可能存在的特定过程文件 del /q *.build_log.htm 2nul del /q *.axf 2nul del /q *.bin 2nul del /q *.hex 2nul del /q *.map 2nul echo. echo 清理完成 pause脚本解析与实操要点echo off关闭命令回显让输出更简洁。chcp 65001将控制台代码页设置为UTF-8防止中文路径或文件名乱码。nul将这条命令本身的输出屏蔽。if exist检查目录或文件是否存在避免删除不存在的目标时报错。rmdir /s /q/s表示删除目录及其所有子目录和文件/q表示安静模式无需确认。del /q ... 2nul/q安静删除2nul将错误信息如文件不存在重定向到空设备避免刷屏。安全加固可以在脚本开头添加一行将工程文件设置为排除项提供双重保险attrib R *.uvprojx *.uvoptx 2nul设置为只读但注意这可能会影响你正常编辑工程。如何使用将上述代码复制到记事本中。保存文件并将文件名后缀改为.bat例如clean_keil.bat。将此批处理文件放置在你的RT-Thread工程根目录下与.uvprojx文件同级。双击运行即可。3.3 方案三使用Shell脚本.sh- 跨平台/Windows Linux子系统方案如果你在Windows上使用WSLWindows Subsystem for Linux或者在Linux/macOS下使用Keil的交叉编译链但通过其他IDE或Makefile管理Shell脚本是更通用的选择。#!/bin/bash echo 正在清理RT-Thread Keil工程编译文件... echo # 删除 Objects 目录 if [ -d Objects ]; then echo 删除 Objects 目录... rm -rf Objects else echo Objects 目录不存在跳过。 fi # 删除 Listings 目录 if [ -d Listings ]; then echo 删除 Listings 目录... rm -rf Listings else echo Listings 目录不存在跳过。 fi # 删除根目录下可能存在的特定过程文件 rm -f *.build_log.htm *.axf *.bin *.hex *.map 2/dev/null echo echo 清理完成 read -p 按回车键继续...脚本解析与实操要点#!/bin/bash指定脚本解释器。[ -d 目录名 ]判断目录是否存在。rm -rf-r递归删除-f强制删除不提示。2/dev/null将错误信息丢弃。权限问题首次运行前需要在终端给脚本添加执行权限chmod x clean_keil.sh。路径问题确保在工程根目录下执行脚本或者修改脚本中的路径为相对或绝对路径。3.4 方案四集成到Keil IDE中自定义菜单命令这是最优雅的方案让清理动作成为Keil IDE的一部分。在工程根目录创建上述的.bat或.sh脚本例如clean.bat。打开Keil工程点击菜单栏Tools - Customize Tools Menu...。在弹出的对话框中点击“New”插入一个新工具。进行如下配置Menu Content::Clean Build Output(这里显示在菜单上的文字)Command::C:\Windows\System32\cmd.exe(调用Windows命令处理器)Arguments::/c clean.bat(/c表示执行后续命令然后终止)Initial Folder::$P(代表当前项目目录)勾选上Run Minimized可以让命令行窗口最小化运行不干扰界面。点击“OK”保存。现在你的Tools菜单下就会出现一个Clean Build Output的选项。点击它就会在工程目录下执行清理脚本效果和双击运行一样但无需离开Keil环境。个人经验我强烈推荐方案四Keil集成。它将零散的脚本工具无缝整合到开发流程中减少了上下文切换也方便团队统一。如果团队使用版本管理可以将clean.bat脚本一同提交到仓库其他成员拉取代码后只需在Keil中配置一次指向同一个脚本文件即可享受同样的便利。4. 高级清理策略与版本管理集成基础的清理脚本已经能解决80%的问题。但对于追求极致整洁或面临复杂场景如多项目、自定义输出路径的团队可以考虑更高级的策略。4.1 处理自定义输出路径与多级项目有些项目可能会在Options for Target - Output或Options for Target - Listing中修改默认的输出路径。也可能项目本身是一个复杂结构包含多个子模块或示例代码。应对策略增强型脚本我们可以让脚本更“聪明”去读取Keil的工程文件.uvprojx 本质是XML格式解析出用户自定义的Objects和Listings输出路径。但这涉及XML解析对于批处理来说比较复杂。一个更实用的折中方案是在脚本中预定义多个常见的或项目已知的潜在输出目录路径。echo off chcp 65001 nul echo 正在深度清理RT-Thread Keil工程... echo. REM 标准输出目录 call :CleanDir Objects call :CleanDir Listings call :CleanDir output REM 一些项目可能叫output call :CleanDir build REM 一些自定义或脚本生成的目录 REM 遍历所有子目录清理可能存在的标准目录 (谨慎使用确保了解项目结构) REM for /d /r . %%d in (Objects Listings) do ( REM if exist %%d ( REM echo 删除 %%d... REM rmdir /s /q %%d REM ) REM ) REM 删除常见的过程文件跨目录搜索 (谨慎使用) REM del /s /q *.o *.d *.axf *.bin *.hex *.lst *.map *.crf *.build_log.htm 2nul echo. echo 深度清理完成 pause exit /b :CleanDir if exist %~1 ( echo 删除目录 %~1... rmdir /s /q %~1 ) else ( echo 目录 %~1 不存在跳过。 ) exit /b警告使用del /s或for /d /r进行递归删除时务必谨慎最好在脚本中先用echo命令模拟显示将要删除的文件确认无误后再移除echo执行真实删除。最安全的方式还是明确知道你的项目输出结构。4.2 与Git版本控制集成.gitignore文件清理脚本是“事后清理”而.gitignore文件是“事前预防”。它告诉Git哪些文件或目录不应该被纳入版本管理。对于RT-Thread Keil项目一个典型的.gitignore文件内容如下# Keil MDK 编译过程文件 Objects/ Listings/ *.uvoptx *.uvguix.* *.crf *.o *.d *.axf *.lnp *.lst *.map *.build_log.htm # 生成的二进制文件 (可选择是否忽略建议忽略) *.bin *.hex *.srec # 本地用户特定文件 *.uvguix.* .jlink JLinkSettings.ini # RT-Thread 特定如果使用scons等 rtthread.bin rtthread.elf rtthread.map *.elf如何操作在RT-Thread工程根目录下创建一个名为.gitignore的文本文件注意开头有个点。将上面的内容复制进去。保存。之后Git就会自动忽略这些文件和目录的变动。重要提示.gitignore只对未跟踪的文件生效。如果之前已经不小心将Objects目录添加并提交到了Git仓库那么.gitignore对它就无效了。你需要先将它从Git仓库中删除但保留本地文件git rm -r --cached Objects/ git commit -m “Remove Objects directory from repo”然后再提交.gitignore文件。这样Objects目录的历史记录被清除且未来不会被跟踪。4.3 自动化流水线在编译前/后自动清理在持续集成/持续部署CI/CD环境中例如使用Jenkins、GitLab CI或GitHub Actions我们通常希望每次构建都是从“干净”的状态开始以确保构建的可重复性。你可以在CI的构建脚本如.gitlab-ci.yml或GitHub Actions的steps中在编译步骤之前显式地执行清理命令。如果项目使用scons或cmake等构建工具它们通常有clean命令如scons -c。对于纯Keil项目就可以直接调用我们编写的clean.bat或clean.sh脚本。示例GitHub Actions 步骤片段- name: Clean previous build artifacts run: | # 调用清理脚本 ./clean.bat shell: cmd # 如果是Windows runner5. 避坑指南与最佳实践在实施自动化清理的过程中我踩过不少坑也总结出一些让流程更顺畅的经验。5.1 常见陷阱与解决方案误删工程文件.uvprojx,.uvoptx坑脚本编写不严谨使用通配符如del *.uv*导致工程文件被删。避坑脚本中明确排除关键文件。如前所述使用attrib R设置为只读作为额外保护或者在删除命令中精确指定目录避免在根目录使用宽泛的通配符删除文件。清理后首次编译时间巨长坑清理了所有.o和.d文件导致下次编译是全量编译而非增量编译。避坑这是正常现象也是清理的目的之一确保编译环境干净。如果项目很大全量编译耗时可以接受。如果希望保留增量编译的快捷可以考虑只清理最终输出文件.axf,.bin,.hex,.map而保留.o文件。但这会占用磁盘空间且不是完全“干净”的状态。我的建议是在提交代码或归档版本前执行全清理日常开发中如果编译异常再执行清理。脚本在中文路径或含空格路径下执行失败坑项目路径包含中文或空格批处理命令解析出错。避坑在批处理脚本中对路径变量使用双引号包裹例如rmdir /s /q “%CLEAN_DIR%”。确保脚本文件本身的保存编码为ANSI或带BOM的UTF-8并在开头使用chcp 65001切换控制台代码页。清理不彻底有“漏网之鱼”坑项目使用了非标准的输出目录名或者某些插件生成了额外文件。避坑在第一次使用脚本后手动检查项目目录看看是否还有大的、明显是编译生成的文件夹或文件。将它们补充到脚本的删除列表或.gitignore文件中。可以使用dir /s /b *.o等命令辅助查找。5.2 个人推荐的工作流结合多年经验我形成了一套高效且安全的工作习惯日常开发主要依赖Keil的增量编译。除非遇到诡异的编译/链接错误比如提示某个.o文件格式不对我一般不主动清理。Keil自身的编译依赖管理基于.d文件在大多数情况下是可靠的。提交代码前这是清理脚本的主战场。我会双击运行集成在Keil中的Clean Build Output命令确保Objects和Listings目录被清除。然后执行一次完整的重建Rebuild All确保代码在完全干净的环境下能正确编译通过。最后使用git status查看变更确保只有源代码和必要的工程文件.uvprojx被修改没有过程文件混入。版本发布时除了清理编译文件我还会运行清理脚本。执行Rebuild All生成最终镜像。将生成的.bin/.hex文件、.map文件以及本次版本的发布说明一起归档到一个单独的发布目录或打上Git Tag。确保.gitignore文件是最新且有效的。团队协作将clean.bat或clean.sh和.gitignore文件一并纳入版本库。在新成员入职或新拉取代码时引导他们配置Keil的自定义工具菜单统一团队内的清理方式。这能极大减少因过程文件冲突导致的问题。通过将清理工作自动化、流程化你不仅能节省磁盘空间更能维护一个清晰、可追溯的代码仓库让团队把精力集中在真正的开发与创新上。这个小技巧是专业嵌入式开发者工具箱里必不可少的一件利器。