HoloCubic 固件中的 LVGL 编码规范:从命名约定到 astyle 自动格式化实战
嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载本文以 HoloCubic 开源仓库内置的 LVGL 图形库规范文档 CODING_STYLE.md 为核心系统讲解 LVGL 的 C 语言编码风格体系文件模板、命名约定、函数与变量组织、注释写法以及基于 astyle 的自动化格式化流程。读完本文你将能理解 HoloCubic 固件中所有lv_*API 的命名规律与代码结构并能在自己的嵌入式 GUI 项目中套用这套可落地的规范。HoloCubic 是一款带网络功能的伪全息透明显示桌面站其固件2.Firmware/HoloCubic-fw以 ESP32 LVGL 为 UI 核心仓库内完整携带了 LVGL 源码库lib/lvgl。这套编码规范就是驱动该图形库数万行源码保持整齐划一的核心约束——理解了它就等于拿到了阅读、维护甚至二次扩展 HoloCubic UI 代码的通关密码。文件格式一切源码从模板起步规范的第一条要求是新文件一律从官方模板起步。LVGL 提供了两个模板文件C 源码模板src/lv_misc/lv_templ.c头文件模板src/lv_misc/lv_templ.h打开 lv_templ.h 可以看到固定的分节骨架所有 LVGL 头文件都遵循这一布局/** * file lv_templ.h * */ #ifndef LV_TEMPL_H #define LV_TEMPL_H #ifdef __cplusplus extern C { #endif /********************* * INCLUDES *********************/ /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /********************** * GLOBAL PROTOTYPES **********************/ /********************** * MACROS **********************/ #ifdef __cplusplus } /* extern C */ #endif #endif /*LV_TEMPL_H*/而 lv_templ.c 则对应如下分节并额外增加了 STATIC 部分/********************* * INCLUDES *********************/ /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /* This typedef exists purely to keep -Wpedantic happy when the file is empty. */ /* It can be removed. */ typedef int _keep_pedantic_happy; /********************** * STATIC PROTOTYPES **********************/ /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /********************** * STATIC FUNCTIONS **********************/这套分段注释贯穿整个仓库例如 lv_widgets/lv_label.h 的INCLUDES / DEFINES / TYPEDEFS分区以及 lv_core/lv_obj.c 中按GLOBAL FUNCTIONS组织函数的方式都是同一模板的产物。此外 src/lv_widgets/lv_objx_templ.h 还提供了一套新建控件模板其中明确标注了替换规则template - 控件全小写名、templ - 控件短名、TEMPL - 控件名全大写新建一个控件时只需全局替换这三个占位符。命名约定lv_前缀背后的工程学LVGL 的命名体系是全库可读性的基石规则可归纳为以下四层分隔与大小写单词之间一律用下划线_分隔变量名、函数名只允许小写字母例如height_tmp枚举常量与宏定义只允许大写字母例如MAX_LINE_NUM。对照仓库实际代码lv_label.h中的枚举LV_LABEL_LONG_EXPAND、LV_LABEL_LONG_BREAK、LV_LABEL_LONG_DOT、LV_LABEL_LONG_SROLL、LV_LABEL_LONG_SROLL_CIRC、LV_LABEL_LONG_CROP见 lv_label.h即为全大写枚举的典型而函数lv_label_set_text、lv_obj_invalidate则全部使用小写。API 全局命名公式全局可见的名称即对外 API遵循严格的四级拼装规则以lv开头紧跟模块名btn按钮、label标签、style样式等对函数再追加动作词set、get、refrrefresh等以对象主体收尾name、size、state等。典型组合如lv_label_set_text模块label 动作set 主体text。在 HoloCubic 固件 src/display.cpp 中调用的一串 API——lv_disp_buf_init、lv_disp_drv_init、lv_disp_drv_register、lv_task_handler——都能按该公式逐词拆解看名字即可推断功能。Typedef 约定优先使用typedef struct与typedef enum而不是裸写struct name/enum name所有typedef struct/typedef enum的类型名必须以_t结尾。示例来自 lv_label.henum { LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_CENTER, LV_LABEL_ALIGN_RIGHT, LV_LABEL_ALIGN_AUTO, }; typedef uint8_t lv_label_long_mode_t; /* 以 _t 结尾的类型别名 */缩写规则缩写必须同时满足三个条件只有长度大于等于 6 个字符的单词才允许缩写缩写后长度至少要缩短一半只使用约定俗成、毫无歧义的缩写例如pos(position)、def(default)、btn(button)。从源码中可以印证ext(extended)、refr(refresh)、disp(display)、inv(invalidate) 等都是这一规则下的产物例如 lv_core/lv_obj.c 中的lv_obj_invalidate、src/display.cpp 中的lv_disp_drv_t。编码指南函数、变量与作用域纪律函数长度红线理想情况下单个函数控制在 50 行以内硬性上限是 200 行除非逻辑极其直白。这条红线在大型渲染与绘制函数中体现为拆分信号处理式的模块化每个公开 API 只做一件事复杂流程拆解为多个小函数例如lv_label_set_text只负责设置文本刷新动作交由lv_label_refr_text内部完成见 lv_widgets/lv_label.c。变量声明纪律一行只声明一个变量禁止char x, y;这种写法一律使用stdint.h中的定宽类型uint8_t、int32_t等变量在使用处就近声明而不是堆在函数开头使用尽可能小的作用域文件级函数外变量必须声明为static严禁使用全局变量读写静态变量一律通过 set/get 函数完成。HoloCubic 固件源码严格遵守了这些规则src/display.cpp 中static lv_disp_buf_t disp_buf;与static lv_color_t buf[LV_HOR_RES_MAX * 10];就是文件级 static 变量的范例而 src/lv_port_fatfs.c 中的static lv_fs_res_t fs_read(...)、static lv_fs_res_t fs_write(...)则是static 函数 对外封装模式的典型。更值得注意的是LVGL 对外提供的LV_EXPORT_CONST_INT(...)宏见 lv_label.h正是为了不引入全局变量却又能把常量暴露给 Lua 绑定层而设计的折中方案——这印证了规范对全局变量的严防死守。注释规范写为什么不写是什么函数头注释Doxygen 风格每个函数前都必须有统一格式的注释块规范给出了标准示例/** * Return with the screen of an object * param obj pointer to an object * return pointer to a screen */ lv_obj_t * lv_obj_get_scr(lv_obj_t * obj);这一约定在仓库中得到了严格执行——lv_widgets/lv_label.c 中lv_label_set_text的注释与规范示例几乎逐字对应/** * Set a new text for a label. Memory will be allocated to store the text by the label. * param label pointer to a label object * param text \0 terminated character string. NULL to refresh with the current text. */ void lv_label_set_text(lv_obj_t * label, const char * text)注释的为什么原则一律使用/* Something */块注释格式禁止// Something写出可读性强的代码避免描述性注释——比如x; /* Add 1 to x */就是反面教材注释应当解释为什么这么做例如x; /*Because of closing \0 of the string */允许少量几行的代码摘要例如/*Calculate the new coordinates*/注释中引用变量时使用反引号包裹例如/*Update the value of x_act*/。以 lv_label.c 为例代码中对ext-text text ext-static_txt 0分支的注释/*If set its own text then reallocate it (maybe its size changed)*/正是典型的解释动机而非复述代码。格式化括号、缩进与 astyle 自动化括号摆放与空白规范规范给出了一个完整示例展示了函数大括号、语句大括号与空白的正确用法/** * Set a new text for a label. Memory will be allocated to store the text by the label. * param label pointer to a label object * param text \0 terminated character string. NULL to refresh with the current text. */ void lv_label_set_text(lv_obj_t * label, const char * text) { /* Main brackets of functions in new line*/ if(label NULL) return; /*No bracket only if the command is inline with the if statement*/ lv_obj_inv(label); lv_label_ext_t * ext lv_obj_get_ext(label); /*Comment before a section */ if(text ext-txt || text NULL) { /*Bracket of statements start inline*/ lv_label_refr_text(label); return; } ... }要点归纳函数的主大括号另起一行Allman 风格语句级大括号紧跟行尾KR 风格——两种风格在 LVGL 中分层使用这是它最鲜明的格式化特征只有当if与其执行体在同一行时才允许省略大括号如if(label NULL) return;运算符两侧加空格、括号内侧不加空格缩进一律使用 4 个空格禁止 Tab仓库的 scripts/code-format.cfg 中--indentspaces4与--convert-tabs两条规则即为此而生。astyle 一键格式化规范推荐使用astyleArtistic Style自动格式化代码其配置与脚本已内置在仓库中格式化参数文件scripts/code-format.cfg执行脚本scripts/code-format.sh脚本内容只有一行核心命令astyle --optionscode-format.cfg ../src/*.c,*.h即从scripts目录出发用配置文件中定义的规则递归格式化src下所有.c与.h文件。值得逐条解读的配置文件关键项如下astyle 选项含义--stylekr采用 KR 括号风格语句级大括号行尾放置--indentspaces4缩进为 4 个空格--pad-oper运算符两侧补空格--unpad-paren括号内侧不补空格--align-pointermiddle指针星号居中lv_obj_t * label--convert-tabs将 Tab 统一转换为空格--max-code-length120单行最长 120 字符超出自动换行--break-closing-braces收尾大括号另起一行--lineendlinux统一为 Linux 换行符\n--recursive/--suffixnone递归处理且不保留备份文件--exclude...排除自动生成的字体位图源码如lv_font_montserrat_*.c、lv_font_simsun_16_cjk.c等注意--exclude列表排除了大量lv_font_*文件——这些是脚本生成的一维数组字体数据不属于手写代码格式化反而会破坏其紧凑布局。这一细节提示我们自动格式化只应对手工维护的源码启用。规范文档原文写的是Runcode-formatter.shfrom thescripsfolder其中scrips为笔误仓库中实际文件名与路径为 scripts/code-format.sh。规范在 HoloCubic 固件中的落地验证HoloCubic 固件目录2.Firmware/HoloCubic-fw/src的 UI 源码同样遵循这套规范可以作为直接参照src/lv_cubic_gui.c 顶部以/* INCLUDES */分节组织头文件函数内局部变量static lv_style_t default_style;、lv_obj_t* img就近声明、小写命名调用链全部是lv_style_init→lv_style_set_bg_color→lv_obj_add_style→lv_img_create→lv_img_set_src→lv_obj_align这类模块 动作 主体式的命名 APIsrc/display.cpp 中static lv_disp_buf_t disp_buf;与static lv_color_t buf[LV_HOR_RES_MAX * 10];体现了文件级static约束uint32_t w / h体现了stdint.h定宽类型要求回调函数my_disp_flush也保持了就近声明、简短函数的风范src/lv_port_fatfs.c 中fs_read、fs_write、fs_seek等一律声明为static并通过注册机制接入 LVGL 文件系统驱动——正是不用全局变量用函数封装的实践。这意味着若你想为 HoloCubic 固件新增界面或驱动文件直接复制 src/lv_misc/lv_templ.c / lv_templ.h 作为起点套用命名公式与注释模板最后用 scripts/code-format.sh 一键规整就能产出一份与 LVGL 官方风格完全一致的可维护代码。这套方法论同样适用于任何以 LVGL 为 UI 层的嵌入式项目HoloCubic 的 ESP32 工程配置见 platformio.ini是团队协作与长期维护中性价比极高的一项工程投资。结语HoloCubic 固件所携带的 LVGL 编码规范表面上看只是一份风格指南实质上却是一套完整的工程约束体系模板文件统一了文件骨架四级命名公式让 API 自解释函数/变量纪律控制了复杂度注释规则保证了可维护性而 astyle 配置把最后的人为差异交给工具抹平。从命名到格式、从注释到工具链这套规范让数万行代码呈现出由一个人书写的一致性——这正是它值得每个嵌入式开发者借鉴的地方。赞分享嵌入式物联网智能硬件嵌入式GUI硬件开发【免费下载链接】HoloCubic带网络功能的伪全息透明显示桌面站项目地址https://gitcode.com/gh_mirrors/ho/HoloCubic点击查看免费下载相关推荐yaml-cpp 安装与上手指南3 条安装路线 3 个常见坑一次解决yaml cpp 安装与上手指南3 条安装路线 3 个常见坑一次解决 这篇写给刚接触 C 构建体系的开发者用三种方式完成 yaml cpp 安装按序列化后端HoloCubic 固件中 LVGL lv_table 表格组件实战从 Simple Table 示例到源码级剖析HoloCubic 固件中 LVGL lv_table 表格组件实战从 Simple Table 示例到源码级剖析 HoloCubic 是一款带网络功能的伪全嵌入式物联网智能硬件嵌入式GUI硬件开发Move 编码规范实战指南Diem 项目中的命名、导入、注释与格式化约定Move 编码规范实战指南Diem 项目中的命名、导入、注释与格式化约定 本文以 Diem 仓库中的官方文档 Move Coding Conventions区块链金融科技创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考