esp-iot-solution 贡献指南Pull Request 流程、编码规范与 CI 质量门禁全解析【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution本文以仓库根目录的 CONTRIBUTING.rst 与配套的 编码规范文档 为核心系统讲解如何为 Espressif IoT 库 esp-iot-solution 提交高质量代码从提交前的自检清单、Pull Request 合入流程到头文件/函数/变量/类型定义/注释的编码规范、代码格式化工具以及仓库内置的 pre-commit 钩子与版权检查等 CI 机制。读完本文你将具备向该仓库提交合规、可维护、易通过评审的代码的完整实战能力。一、贡献方式与总体原则esp-iot-solution 欢迎一切形式的贡献——修复 bug、增加功能、补充文档均可。仓库通过 GitHub Pull Request 接收贡献合入前需满足 Apache License 2.0 兼容的许可要求并遵循仓库自身的代码风格与文档规范。项目的目录结构是贡献者首先需要理解的地图依据 编码规范文档 中的目录结构章节components/按功能分类的组件库大类下若存在多级目录应包含一个README做综述与索引例如 components/i2c_bus 下就有 README 与 Kconfigdocs/rst格式文档包括各组件使用指南与 API 说明分en与zh_CN两个语言目录examples/按与组件对应的功能分类的示例工程tools/CI 脚本与调试工具如 tools/ci 下的检查脚本、tools/format.sh 格式化脚本。总体编码原则可概括为四点简洁明了、结构清晰统一风格、易于维护充分注释、易于理解继承 ESP-IDF 已有规范并继承第三方代码已有规范不擅自重排第三方源码。二、提交前的自检清单Before Contributing在发出 Pull Request 之前CONTRIBUTING.rst 要求贡献者逐项确认许可合规贡献是否完全是自己的作品或已采用 Apache License 2.0 兼容的开源许可证否则无法被接受。仓库根目录的 LICENSE 即为 Apache-2.0风格合规新代码是否符合 esp-idf 的 Style Guide详见下文第三至七节pre-commit 钩子是否为 esp-iot-solution 项目安装了 pre-commit hook。仓库根目录的 .pre-commit-config.yaml 定义了完整的钩子集合包括版权检查、尾随空白清理、行尾统一为 LF、分支名校验、astyle 代码格式化等代码文档代码文档是否符合 ESP-IDF 的 Documenting-code 要求即对每个公开接口做 Doxygen 注释注释质量代码是否被充分注释以便他人理解结构注释与文档是否使用清晰无拼写/语法错误的英文提交组织多个 commit 是否按逻辑分组一个 PR 对应一个主要变更类似 fixed typo 的零碎提交是否已 squash 进前序提交。如果对上述任何一点不确定也请照常打开 Pull Request然后在评论中请求反馈即可——评审过程本身就是学习过程。三、Pull Request 合入流程与法律条款贡献流程分为三段评审阶段PR 打开后评审讨论会在 PR 自身的评论区进行作者需要回应意见并迭代修改。内部测试阶段PR 准备就绪后会先合入项目内部 git 系统进行自动化测试。仓库的 tools/ci 目录提供了这些门禁的脚本例如 check_components.py 会校验每个组件idf_component.yml中声明的 example 路径是否真实存在check_readme_links.py 校验 README 链接有效性check_copyright_config.yaml 用于版权头检查。此外 conftest.py 与 pytest.ini 支撑着各组件test_apps的自动化测试。公开合入阶段内部测试通过后才会合入公开的 GitHub 仓库。法律条款在贡献被接受之前贡献者需要签署 contributor agreementEspressif 贡献者协议。该签署会在 Pull Request 流程中被自动提示无需提前单独操作。四、头文件规范include guard、extern C 与声明原则编码规范文档 对头文件提出了六条硬性要求尽量每个.c对应一个同名.h文件单个组件存在多个.h时主要对外.h的命名尽量与组件名保持一致头文件主要放函数声明不放函数实现尽量不在头文件定义任何形式的变量头文件需按注释规范对函数接口做充分注释使用宏定义避免重复引用宏名采用大写头文件名加下划线填充#ifndef _IOT_I2C_BUS_H_ #define _IOT_I2C_BUS_H_ #endif以实际仓库为证components/i2c_bus/include/i2c_bus.h 的头部同时示范了 include guard、SPDX 版权头与 Apache-2.0 许可声明三要素/* * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #ifndef _I2C_BUS_H_ #define _I2C_BUS_H_此外函数声明需要添加extern C修饰以支持 C/C 混合编程#ifdef __cplusplus extern C { #endif //c code #ifdef __cplusplus } #endif仓库中大量组件头文件遵循此模式例如 components/button/include/iot_button.h 即在#ifdef __cplusplus之后开启extern C {。五、注释规范Doxygen 框架与版权声明工具支持仓库建议安装 VSCode 插件 Doxygen Documentation Generator可自动生成注释框架注释中应避免单词缩写。函数注释模板函数声明处注释需描述功能、性能或用法并说明输入/输出参数与返回值。自动生成的框架与补充信息后的完整示例取自 编码规范文档/** * brief Create an I2C bus instance then return a handle if created successfully. * note Each I2C bus works in a singleton mode, which means for an i2c port only one group parameter works. When * iot_i2c_bus_create is called more than one time for the same i2c port, following parameter will override the previous one. * * param[in] port I2C port number * param[in] conf Pointer to I2C parameters * return i2c_bus_handle_t Return the I2C bus handle if created successfully, return NULL if failed. */ i2c_bus_handle_t iot_i2c_bus_create(i2c_port_t port, i2c_config_t* conf);注意param[in]的方向标注与return的成败双态描述这是仓库组件 API 的普遍写法。版权声明注释第三方代码必须保留其原始版权声明/* * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */这条版权声明不只是建议——仓库的 tools/ci/check_copyright_config.yaml 在 CI 中强制执行默认对所有文件校验allowed_licenses: [Apache-2.0]新文件会自动插入SPDX-FileCopyrightText: {years} Espressif Systems (Shanghai) CO LTDSPDX-License-Identifier: {license}模板C/CPP/H/HPP/LD 与 Python 各有对应注释风格并通过.pre-commit-config.yaml中的check-copyright钩子配置指向该 yaml 与 check_copyright_ignore.txt在每次提交时把关。对于上游引入的第三方代码如components/quickjs-ng/quickjs-ng/**、BME690 传感器驱动等则在ignore段显式豁免保留其原有许可头。六、函数与变量规范函数规范多处重复使用的代码尽量设计为函数作用域仅限于当前文件的函数必须声明为static设计使用静态全局/局部变量的函数时需考虑重入问题尽量在一个固定函数中操作静态全局变量若存在重入或线程安全问题须在注释中说明同一组件内的公有函数名应保持同一前缀函数名统一使用snake_case只使用小写字母单词间加_。函数命名指引应保持与已有代码风格一致不严格约束函数名格式函数示例说明iot_type_xxxiot_sensor_xxx;iot_board_xxx;iot_storage_...高度抽象的 iot 组件type_xxximu_xxx;light_xxx;eeprom_xxx对一类外设的抽象name_xxxmpu6050_xxx底层 driver可来自第三方不约束函数名xxx_creat / xxx_delete—创建和销毁xxx_read / xxx_write—数据操作变量规范避免使用全局变量确需跨函数共享时声明为静态全局变量并通过get_/set_接口操作作用域仅限当前文件的变量必须声明为static静态全局变量加g_前缀静态局部变量加s_前缀局部变量设计大小时考虑栈溢出问题任何变量定义时必须赋初值变量功能要明确避免单一变量多用途句柄类型变量在对象销毁后应重新赋值为 NULL例如 components/i2c_bus/include/i2c_bus.h 中的i2c_bus_handle_t这类句柄变量统一使用snake_case避免不必要缩写如data不必缩写成dat尽量使用有意义词语或公认缩写。变量命名指引类型规范示例全局变量避免使用—静态全局变量static 标识g_前缀赋初值static uint32_t g_connect_num 0;静态局部变量static 标识s_前缀赋初值static uint32_t s_connect_num 0;迭代计数变量使用通用的ijk—常用缩写参考 abbreviations-in-code 社区约定addr,buf,cfg,cmd,ctrl常用缩写速查表缩写全称缩写全称缩写全称缩写全称addraddressididentifierlenlengthptrpointerbufbufferinfoinformationobjobjectretreturncfgconfighdrheaderparamparametertemptemporary、temperaturecmdcommandinitinitializepospositiontstimestamp七、类型定义规范类型名使用snake_case加_t后缀typedef int signed_32_bit_t;枚举应通过 typedef 定义枚举值使用全大写模块前缀typedef enum { MODULE_FOO_ONE, MODULE_FOO_TWO, MODULE_FOO_THREE } module_foo_t;仓库中此类风格比比皆是例如 components/i2c_bus/include/i2c_bus.h 中软件 I2C 端口枚举即采用I2C_NUM_SW_0、I2C_NUM_SW_MAX等I2C_NUM_SW_*前缀风格。八、格式与排版规范继承 ESP-IDF该部分继承 ESP-IDF 规范同时由仓库 tools/ci/astyle-rules.yml 中的默认选项自动执行。1. 缩进每个缩进层使用4 个空格不用制表符编辑器应配置为按 Tab 键时输出 4 个空格。2. 垂直间隔函数之间放置一个空行不要以空行开始或结束函数体void function1() { do_one_thing(); do_another_thing(); // INCORRECT, dont place empty line here } // place empty line here void function2() { // INCORRECT, dont use an empty line here int var 0; while (var SOME_CONSTANT) { do_stuff(var); } }只要不严重影响可读性最大行长度为 120 个字符。3. 水平间隔条件与循环关键字后总是加单个空格二元操作符两端加单个空格一元运算符不需要空格乘法/除法之间可省略空格if (condition) { // correct // ... } for(int i 0; i CONST; i) { // INCORRECT // ... } const int y y0 (x - x0) * (y1 - y0) / (x1 - x0); // correct const int y y0 (x - x0)*(y1 - y0)/(x1 - x0); // also okay int y_cur -y; // correct y_cur; const int y y0(x-x0)*(y1-y0)/(x1-x0); // INCORRECT.与-操作符周围不需要空格。可用水平间隔对齐函数参数以提升可读性但注意若之后新增一行更长标识符的参数将被迫重排整列、产生无意义 diff因此这种对齐要少用禁止用制表符做水平对齐禁止行尾尾随空格。4. 括号函数定义的大括号单独成行函数内条件/循环语句的左大括号与语句同行// This is correct: void function(int arg) { } // NOT like this: void function(int arg) { } if (condition) { do_one(); } else if (other_condition) { do_two(); }5. 注释单行注释用//多行注释每行用//或块注释/* */。注意三个反例不要用注释禁用功能——不再需要的代码应完全删除可随时从 git 历史找回若因临时原因禁用并打算将来恢复必须在相邻行添加解释例如void init_something() { setup_dma(); // TODO: we should load resources here, but loader is not fully integrated yet. // load_resources(); start_timer(); }#if 0 ... #endif同理不用的代码块请完全删除否则要注释解释禁用原因不要用它或注释来存放未来可能需要的代码段不要添加关于作者和更改日期的琐碎注释// XXX add 2016-09-01这类用 git blame 即可查证每行修改来源。6. 代码行结束commit 中只能包含 LFUnix 风格结尾的文件。Windows 用户可通过 git 的core.autocrlf设置在本地使用 CRLF、提交时转 LF编辑 ESP-IDF 源文件时更推荐直接将编辑器配置为 LF 结尾。若不慎提交了 CRLF可在 MSYS2 或 Unix 终端执行git rebase --exec git diff-tree --no-commit-id --name-only -r HEAD | xargs dos2unix git commit -a --amend --no-edit --allow-empty master此命令在 master 上变基可在末尾改分支名以对其他分支变基。更新单个提交可运行dos2unix FILENAME后git commit --amend。7. 格式化代码可用 astyle 程序按上述建议自动格式化。整文件重写时可直接格式化整个文件只改动一小部分时不要重排未改动的代码以免干扰评审。重排单个文件运行tools/format.sh components/my_component/file.c脚本 tools/ci/format.sh 内部使用astyle_py版本 3.4.7需与 .pre-commit-config.yaml 中配置保持一致核心参数为--styleotbs --attach-namespaces --attach-classes --indentspaces4 --convert-tabs --align-referencename --keep-one-line-statements --pad-header --pad-oper --unpad-paren --max-continuation-indent120与 astyle-rules.yml 中的 DEFAULT 选项一一对应。astyle-rules.yml还定义了not_formatted_permanent豁免名单上游源码、生成文件、patch 等如components/utilities/xz/、components/audio/dac_audio/test/wave_*.c确保不破坏第三方代码。九、CMake 代码风格仓库同样约束 CMake 文件的风格依据 编码规范文档 的 CMake 章节缩进为 4 个空格最大行长为 120 个字符分割行时以可读性为先例如将关键字/参数对放在单独行endforeach()、endif()等语句后面的可选括号中不要放任何内容命令、函数、宏名使用小写with_underscores局部作用域变量用小写with_underscores全局作用域变量用大写WITH_UNDERSCORES其余遵循 cmake-lint 项目的默认设置。十、把规范落进日常提交pre-commit 与 CI 门禁仓库将上述绝大部分规范固化为自动化检查贡献者提交前运行 pre-commit 即可提前暴露问题。.pre-commit-config.yaml要求 pre-commit 版本 ≥ 3.3.0默认安装 pre-commit 与 commit-msg 两类钩子包含以下关键钩子check-copyrightespressif/check-copyright v1.1.1以 check_copyright_config.yaml 为配置、check_copyright_ignore.txt 为豁免名单强制 SPDX 版权头trailing-whitespace / end-of-file-fixer / mixed-line-ending清理尾随空白、保证文件以换行结尾、统一 LF 行尾check-executables-have-shebangs / check-shebang-scripts-are-executable保证脚本可执行性正确no-commit-to-branch禁止分支名含多个斜杠或大写字母--pattern ^[^/]*/[^/]*/与^[^A-Z]*[A-Z]astyle 格式化espressif/astyle_py按上文第八节的规则自动重排代码与 tools/ci/format.sh 保持一致。此外 CI 还运行 check_components.py 校验组件idf_component.yml中examples段声明的路径有效性遍历.github/workflows/upload_component.yml中的组件目录从入口处杜绝文档写了、示例路径却不存在的问题。实战建议安装 pre-commit 后每次git commit都会自动触发上述检查若格式化类钩子修改了文件重新git add后再次提交即可。提交信息建议按逻辑变更分组一个 PR 一个主题零碎修改用交互式 rebase squash 合并并在 PR 描述中说明改动背景与测试情况评审通过后即进入内部测试→公开仓库的合入流程。结语向 esp-iot-solution 贡献代码的完整路径可以浓缩为许可合规 → 遵循本文所述编码规范 → 安装 pre-commit 通过自动化门禁 → 提交逻辑清晰、注释充分的 PR → 参与评审迭代 → 签署贡献者协议 → 合入。规范细节以 CONTRIBUTING.rst 与 编码规范文档英文版见 docs/en/contribute/style-guide.rst为准格式化与检查工具可直接复用 tools/ci/format.sh 和 .pre-commit-config.yaml。对照仓库内现有组件如 components/i2c_bus/include/i2c_bus.h的实际代码风格是快速上手、写出像本仓库原生代码的最有效方法。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考