원클릭으로
repository-encoding-normalizer
源码仓库编码规范化(UTF-8 统一 + 编译时 GBK 自动转换)。仅当用户明确要求规范化源码仓库文件编码时使用;若用户没有明确要求,禁止使用。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
源码仓库编码规范化(UTF-8 统一 + 编译时 GBK 自动转换)。仅当用户明确要求规范化源码仓库文件编码时使用;若用户没有明确要求,禁止使用。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
在当前会话里按已写好的实现计划顺序执行任务时使用
在已有规格或多步骤任务需求、且在动代码之前使用。若上游 ddev-pc-test 已产出测试用例,自动走 TDD 流程:先实现测试 demo 代码(红灯),再实现被测代码(绿灯),测试覆盖不到的部分直接开发。
文档审查技能。将文档审查任务派发给独立子代理,重点审查文档基于代码改动的合理性、说明正确性、前后一致性、错漏和逻辑谬误,以及 AI 实现过程中产生的决策记录(implementation-notes.md)。当用户需要审查技术文档、spec文档、设计文档、计划文档、API文档、README 或任何与代码改动相关的文档时使用。
代码修改场景下,spec 文档确认后,需要继续以图优先方式梳理结构体定义、数据流和流程时使用
在代码修改前需要编写 spec 文档且应优先用图表达边界、入口、流程和改动关系时使用(仅限代码改动场景,非项目级架构文档初始化)
在代码实现完成后、准备结束任务或进入发布前使用,用来核对代码实现是否与 spec 文档以及 detail 文档一致,并通过代码质量审查、清理、编码规范和注释审查后给出最终验收结论
| name | repository-encoding-normalizer |
| description | 源码仓库编码规范化(UTF-8 统一 + 编译时 GBK 自动转换)。仅当用户明确要求规范化源码仓库文件编码时使用;若用户没有明确要求,禁止使用。 |
源码统一为 UTF-8。BOM 策略取决于编译器环境:ARM/Keil(armcc)→ UTF-8 with BOM;ARMCLang / Linux/GCC → UTF-8 without BOM。中文运行期字面量保留在源码中,编译时由 gbk_encode.exe(Windows/ARM/Makefile)或 gbk_build.py(Linux/GCC/CMake,Python 源码,跨平台)自动检测含 CJK 字面量的文件并生成 GBK 编码副本供编译器使用。
<skill_dir>=C:/Users/DELL/.config/opencode/skills/repository-encoding-normalizer
本 skill 附带的脚本为唯一合法实现,禁止自写替代: scan_encoding.py(编码审计)、normalize_encoding.py(批量转换)、check_mojibake.py(乱码巡检)、gbk_encode.exe(GBK 编译时转换,Windows PE)、gbk_build.py(GBK 编译时转换,Python 源码,跨平台)。ARM/Makefile 项目将 gbk_encode.exe 复制到仓库 tool/ 目录;Linux/CMake 项目直接使用 gbk_build.py。
# 1. 确定扫描范围(--root 指向实际需要规范化的目录,不要全仓扫描)
# 多机型仓库只扫描目标机型子目录(如 tp586w_gen/),不是仓库根
# 2. 编码审计(含 Makefile、*.mk、*.bat、CMakeLists.txt)
python <skill_dir>/scan_encoding.py --root <target_dir> --out encoding_audit.md --json-out encoding_audit.json
# 3. 编译器环境检测(确定 armcc / armclang / gcc 及正确编译命令)
# 检查 Makefile 中 ifeq/ifneq ($(armclang),1) 等分支 + 搜索 build*.bat/build*.sh
# 本仓库若 armclang=1 可用则优先;否则用默认 armcc。记录真实 make 命令。
# Linux/GCC 项目:检查 CMakeLists.txt 中的 CMAKE_C_COMPILER,确认是否为 GCC。
# 4. 批量转换(compiler 参数需与实际编译器匹配)
# armcc → --compiler armcc(UTF-8 with BOM); armclang → --compiler armclang(UTF-8); GCC → --compiler armclang(UTF-8 without BOM)
python <skill_dir>/normalize_encoding.py --root <target_dir> --compiler armcc --audit-json encoding_audit.json
# ⚠️ 转换后易出两类编译问题:(a) Makefile 若含 BOM → GNU Make exit 2;(b) GBK 注释含中文 → 字节膨胀导致跨行断裂。
# 建议转换后立即用 grep 抽查 `//` 行是否完整,并对 Makefile 强制 strip BOM(PowerShell: Set-Content -Encoding UTF8)
# 若误用 armcc 模式给 GCC 项目的文件加了 BOM:find <dir> '(' -name '*.c' -o -name '*.h' ')' -exec sh -c 'tail -c+4 "$1" > /tmp/stripbom && mv /tmp/stripbom "$1"' _ {} \;
# 5. 复制 GBK 转换工具
# ARM/Makefile 项目 → copy gbk_encode.exe 到 tool/; Linux/CMake 项目 → 直接用 gbk_build.py(无需复制)
# 6. 改造构建系统(按项目类型选择)
# Makefile ARM 项目 → 下方「Makefile 集成模板」; CMake 项目 → 下方「CMake 集成」章节
# ⚠️ 仅修改与编码/GBK 转换相关的部分,禁止改动其他编译逻辑。
# 注意检查 Makefile 自身编码:若为 UTF-16 LE 等非 UTF-8,先转换为 UTF-8 BOM。
# 7. 确定 gbk_encode 扫描范围
# 从 Makefile 的 SRCS/OBJS/vpath 等变量推导实际参与编译的源文件目录集合,
# gbk_encode -s 参数必须恰好覆盖这些目录(不多扫也不少漏)。
# GBK 命中预览:
tool/gbk_encode.exe -s <从Makefile推导的扫描根目录> -o <out_dir> --list
# 8. 乱码巡检(从审计 JSON 自动读取文件列表)
python <skill_dir>/check_mojibake.py --root <target_dir> --from-json encoding_audit.json
# 9. 编译验证(使用步骤 3 检测到的真实编译命令)
make clean; if ($?) { make armclang=1 project=<name> -j }
# 验证产物:
# Get-ChildItem out\<project>\objs\*.o | Measure-Object | Select-Object Count
# Get-ChildItem out\<project>\*.axf,*.bin,*.hex
-s DIR(源根)/ -o DIR(输出目录)/ -x DIR(排除目录,至少排除构建输出)/ --list(仅列出)/ --force(忽略 mtime)/ -q(静默)。检测跳过 # // /* */ 行,自动清理陈旧副本。
-s 参数必须从 Makefile 中推导:读取 SRCS/OBJS/vpath 等变量,确定实际参与编译的源文件所在目录集合,-s 参数只覆盖这些目录。禁止用 . 全仓扫描——会引入不参与编译的文件或遗漏 vpath 引用的源文件。
改造 Makefile 前需确认项目实际使用的编译器,避免 make 无参数时走错分支:
Makefile 中 ifeq ($(armclang),1) / ifeq ($(gcc),1) 等分支条件build*.bat / build*.sh,获取实际编译命令(如 make armclang=1 project=tp80k)CFLAGS 中的编译选项语法:-mcpu → armclang,--cpu → armcc占位符模板:必须替换
<>为仓库实际值后才可使用。
.DEFAULT_GOAL := all # 1. 顶部(避免默认目标落在首个目标)
GBK_SRC_DIR := <OBJDIR>gbk_src/ # 2. 路径变量
# 3. vpath — ⚠️ ifneq 保护:空 wildcard 会清除所有 .c vpath
ifneq ($(wildcard $(GBK_SRC_DIR)),)
vpath %.c $(wildcard $(GBK_SRC_DIR)*/)
vpath %.c $(GBK_SRC_DIR)
endif
# 4. resolve_gbk(路径剥离按仓库 src_root 调整)
resolve_gbk = $(if $(wildcard $(GBK_SRC_DIR)$(subst <src_root>,,$1)),$(GBK_SRC_DIR)$(subst <src_root>,,$1),$1)
# 5. OBJDIR 有效目标(编译规则 | <OBJDIR> 需要对应的目录创建规则)
<OBJDIR>:
if not exist "$(<OBJDIR>)" mkdir "$(subst /,\,$(<OBJDIR>))"
# 6. gbk_prepare — cmd.exe 下 exe 用反斜杠!-x 排除构建输出防陈旧副本
# <scan_root> 必须从 Makefile 的 SRCS/OBJS/vpath 推导(见上方步骤 6),禁止全仓扫描
.PHONY: gbk_prepare
gbk_prepare: | $(OBJDIR)
.\tool\gbk_encode.exe -s <scan_root> -x <exclude_dir> -o "$(GBK_SRC_DIR)" -q
# 7. 顺序依赖
$(obja) $(objc): | gbk_prepare
# 8. 编译规则:C 注入 resolve_gbk + | <OBJDIR>;ASM 加 | <OBJDIR>
# 9. clean 必须递归删除
clean:
-if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR))
CheckList: GBK_SRC_DIR 指向 $(OBJDIR)gbk_src/ · <OBJDIR>: 目录规则存在 · gbk_prepare: | <OBJDIR> · $(obja) $(objc): | gbk_prepare · vpath 用 ifneq 保护 · exe 用反斜杠 · .DEFAULT_GOAL := all · -x 排除构建输出 · rmdir /s /q 递归 clean · 使用检测到的正确编译命令实际通过 · 若用 foreach + eval + call 生成单文件规则,recipe 内自动变量需写为 $$@ / $$< / $$(@D)(双 $ 转义,防 eval 阶段提前展开)
适用于 ESP-IDF / CMake 项目的 GBK 编码编译时转换。使用
gbk_build.py(Python 源码,无需 Windows PE)。
顶层 CMakeLists.txt(在 project() 之前):
# GBK 编码副本生成 — 必须在 project() 之前!
# ESP-IDF 的 project() 内部会递归注册组件,此时 GBK 副本必须已就绪
execute_process(
COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tool/gbk_build.py
-s ${CMAKE_CURRENT_SOURCE_DIR}/<component_dir>
-o ${CMAKE_CURRENT_BINARY_DIR}/gbk_src
-x ${CMAKE_CURRENT_BINARY_DIR}
RESULT_VARIABLE GBK_RESULT
)
if(NOT GBK_RESULT EQUAL 0)
message(WARNING "gbk_build.py failed, continuing without GBK copies")
endif()
组件 CMakeLists.txt(GBK 副本优先包含):
# GBK 副本存在时,优先使用 GBK 编码的源文件
set(GBK_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/gbk_src)
# 源文件替换:GBK 副本存在则用它,否则用原始 UTF-8 文件
foreach(src ${srcs})
file(RELATIVE_PATH rel_src ${CMAKE_CURRENT_SOURCE_DIR} ${src})
if(EXISTS ${GBK_SRC_DIR}/${rel_src})
list(APPEND gbk_srcs ${GBK_SRC_DIR}/${rel_src})
else()
list(APPEND gbk_srcs ${src})
endif()
endforeach()
# GBK include 目录 — 必须 EXISTS 检查!gbk_build.py 只给含 CJK 字面量的文件创建目录
if(EXISTS ${GBK_SRC_DIR})
target_include_directories(${COMPONENT_LIB} PRIVATE ${GBK_SRC_DIR})
endif()
trigraph 警告抑制(GCC/ESP-IDF,组件级别):
# GBK 编码中 ??! 等字节序列匹配 C trigraph 模式(??! → |)
# GCC/ESP-IDF 默认 -Werror=trigraphs 将其当错误,需在组件 target 级别抑制
# 不要用 add_compile_options() — 可能被 ESP-IDF 默认参数覆盖
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-trigraphs)
要点:
execute_process 放 project() 之前,确保 GBK 副本在组件注册时已存在foreach 中对每个 include 目录加 if(EXISTS) 检查,防止 gbk_build.py 未创建的空目录被加入target_compile_options 级别,不能用全局 add_compile_optionsfile(RELATIVE_PATH …) 计算相对路径,匹配 gbk_build.py 的输出结构normalize_encoding.py 无法修复的预置乱码文件(GBK 字节已腐坏,被工具跳过),需手动修复:
修复流程(严格遵守,防止二次编码腐坏):
git log --oneline -- <file> 列出文件历史git show <commit>:<file> | iconv -f gbk -t utf-8 > /dev/null 2>&1,退出码 0 表示该版本编码干净git show <clean_commit>:<file> 导出原始内容git show <clean_commit>:<file> > /tmp/original_gbk.c # 从 git 提取原始 GBK
python <skill_dir>/normalize_encoding.py --root /tmp --compiler armclang # 转换原始 GBK
# 再从转换后的版本提取正确注释
高发陷阱: 在已转 UTF-8 的文件上做 GBK decode → 字节被误读产生二次腐坏。每次修复前自问:当前文件是原始 GBK 还是已转 UTF-8?只有原始 GBK 才能用 GBK decode。
| 现象 | 根因 | 修复 |
|---|---|---|
'tool' is not recognized | cmd.exe 把 / 当开关前缀 | exe 路径用反斜杠 |
| make 只跑第一个目标 | 默认目标是 gbk_prepare | 顶部 .DEFAULT_GOAL := all |
| clean build 只编译 asm | 空 wildcard 清空 .c vpath | ifneq 保护 GBK vpath |
| UTF-8 解码失败 | 扫描到 out/ 陈旧 GBK 副本 | -x <build_dir> 排除 |
| 编译仍用原始 UTF-8 | vpath 仅一级扁平搜索 | $(wildcard $(GBK_SRC_DIR)*/) |
| 改中文后未更新 | mtime 缓存/陈旧副本 | --force 或递归 clean |
ASM .d 写失败 | OBJDIR 不存在 | gbk_prepare 中 mkdir |
-j 并行编译抢先 | 并列前置依赖不保序 | $(obja) $(objc): | gbk_prepare |
target 'out/.../objs/' failed to remake | C/ASM 规则依赖 | $(OBJDIR) 但没有目录创建规则,或规则目标名含尾斜杠与依赖项不匹配 | 添加 <OBJDIR>: 无尾斜杠的目录创建目标,recipe 内用 $@(非 $<)并在 mkdir 前 strip 尾斜杠 |
C3900U: Unrecognized option / A3903U: Cortex-M33 not permitted | armcc 与 armclang 选项语法不匹配 | 检查 build*.bat,用 make armclang=1 |
| 改造后链接超限 / 编译反馈未触发 | 擅自修改了 Makefile 中的 --feedback 等编译反馈条件分支 | 回滚所有非编码/GBK 相关改动,仅保留 GBK_SRC_DIR、vpath、resolve_gbk、gbk_prepare、编译规则注入等编码相关修改 |
| gbk_encode 生成副本缺失或包含无关文件 | -s 扫描范围与 Makefile 实际编译范围不一致 | 从 Makefile 的 SRCS/OBJS/vpath 推导实际参与编译的源文件目录集合,重新指定 -s |
Makefile 转 UTF-8 BOM 后 make exit 2 | GNU Make 无法解析 BOM 前缀 | 用 PowerShell Set-Content -Encoding UTF8(无 BOM)重写 Makefile;normalize_encoding.py 对 Makefile 应跳过 BOM 或转换后自动 strip BOM |
GBK→UTF-8 后 // 注释断裂导致语法错误(如 //#include \"hw_led.h 与下一行 led.h\" 分裂) | GBK 多字节字符(如中文)转 UTF-8 后字节数膨胀,原 // 注释行内不再容纳全部内容而跨行 | 手动重排断裂注释:将跨行注释重组为完整行,或改用 /* */ 块注释;高发文件为 includes.h 等集中包含头文件 |
Makefile 编辑后 \r\r\n / 编译语法错乱 | Makefile 自身是 UTF-16 LE 等非 UTF-8,编辑破坏行尾 | 先对 Makefile 做 UTF-16 LE → UTF-8 BOM 转换 |
Linux/GCC 编译报 error: trigraph ?? ignored 导致 -Werror 失败 | GBK 编码中 ??! 等字节序列匹配 C trigraph 模式 | 组件 CMakeLists.txt 中 target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-trigraphs);Makefile 项目在 CFLAGS 中加 -Wno-trigraphs |
CMake configure 报 Include directory not a directory | gbk_build.py 只给含 CJK 字面量的文件创建目录,未创建的目录被无条件加入 INCLUDE_DIRS | foreach 遍历 include 目录时加 if(EXISTS ${dir}) 判断 |
| CMake 构建时找不到 GBK 副本 include 目录 | execute_process 放在了 project() 之后,ESP-IDF project() 内部注册组件时 GBK 副本尚未生成 | execute_process 移到 project() 之前 |
| GCC 环境文件被误加了 BOM | normalize_encoding.py 无 GCC 模式,误用 armcc 加了 BOM | 用 --compiler armclang 重新转换;或批量 strip BOM:`find -name '.c' -o -name '.h' |
| 修复乱码后注释仍腐坏(反复修复不成功) | 在已转 UTF-8 的文件上做 GBK decode 导致二次腐坏 | 从 git 历史提取原始 GBK 版本,在原始版本上修复,再转换到 UTF-8。见「预置乱码修复」章节 |
eval 生成规则中 $@ / $(@D) 展开为空,增量编译 mkdir 报路径语法错误 | foreach + eval + call 批量生成单文件 GBK copy 规则时,recipe 内自动变量 $@、$<、$(@D) 在 eval 阶段被 Make 提前展开(首次全量编译不触发,仅增量暴露) | recipe 中所有自动变量改为 $$@ / $$< / $$(@D)(双美元转义,阻止 eval 阶段展开)。同时确保 mkdir / if not exist 路径参数非空 |
*.c, *.h, *.s, *.S, *.mk, Makefile, *.bat, CMakeLists.txt(含无扩展名的 Makefile)*.s/*.S → UTF-8 无 BOM;Makefile → UTF-8 无 BOM(GNU Make 不兼容 BOM)--root <target_dir> 而非 .,仅处理需要规范化的子目录check_mojibake.py 复查编码不确定、无法无损转换、中文处于协议字节/校验数据/固件资源、字符串移动影响链接/ABI → 暂停询问用户。Linux/GCC 环境默认不加 BOM;armcc 环境加 BOM。
变更清单 + 编码审计 + GBK 命中列表 + 编译通过证据(exit 0 + .o 文件数 + 最终产物 hex/bin/dfu 已生成,注意 exit 0 不代表实际编译了 C 文件)+ 跳过/风险说明。