# Huawei LiteOS 代码&文档贡献指南 - [编程规范](#编程规范) - [总体原则](#总体原则) - [目录结构](#目录结构) - [命名](#命名) - [排版与格式](#排版与格式) - [注释](#注释) - [宏](#宏) - [头文件](#头文件) - [数据类型](#数据类型) - [变量](#变量) - [函数](#函数) - [可移植性](#可移植性) - [业界编程规范](#业界编程规范) - [文档写作规范](#文档写作规范) - [Commit message规范](#Commitmessage规范) - [贡献流程](#贡献流程) - [协议](#协议) - [加入我们](#加入我们)

编程规范

此编程规范在业界通用的编程规范基础上进行了整理,供开发者参考使用。 ### 总体原则 - 清晰,易于维护、易于重构。 - 简洁,易于理解,并且易于实现。 - 风格统一,代码整体风格保持统一。 - 通用性,遵循业界通用的编程规范。 ### 目录结构 建议将工程按照功能模块划分子目录(可参考LiteOS的功能模块划分),子目录再定义头文件和源文件目录。 ### 命名 - 使用驼峰风格进行命名,此风格大小写字母混用,不同单词间通过单词首字母大写来分开,具体规则如下: | 类型 | 命名风格 | 形式 | | --------------------------- | -------------------------------- | ------------------------- | | 函数,自定义的类型 | 大驼峰,或带有模块前缀的大驼峰 | AaaBbb, XXX_AaaBbb | | 局部变量,函数参数,宏参数,结构体成员,联合体成员 | 小驼峰 | aaaBbb | | 全局变量 | 带'g_'前缀的小驼峰 | g_aaaBbb | | 宏,枚举值 | 全大写并下划线分割 | AAA_BBB | | 内核头文件中防止重复包含的宏变量 | 带'_LOS'前缀和'H'后缀,中间为大写模块名,以下划线分割 | \_LOS_MODULE_H | - 全局函数、全局变量、宏、类型名、枚举名的命名,应当准确描述并全局唯一。 - 在能够准确表达含义的前提下,局部变量,或结构体、联合体的成员变量,其命名应尽可能简短。 - LiteOS的对外API使用LOS_\\的方式,如果有宾语采用前置的方式,比如: ``` LOS_TaskCreate LOS_SwtmrStart LOS_SemPend ``` kernel目录下内部模块间接口使用Os\\的方式,比如: ``` OsTaskScan OsSwtmrStart ``` arch目录需要给上层模块提供Low Level接口,这部分接口采用Arch\\的方式。 其他情况可采用\\的方式。 ### 排版与格式 - 程序块采用缩进风格编写,使用空格而不是制表符('\t')进行缩进,每级缩进为4个空格。 - 采用K&R风格作为大括号换行风格,即函数左大括号另起一行放行首,并独占一行,其他左大括号跟随语句放行末, 右大括号独占一行,除非后面跟着同一语句的剩余部分,如if语句的else/else if或者分号,比如: ```c struct MyType { // 左大括号跟随语句放行末,前置1个空格 ... }; // 右大括号后面紧跟分号 ``` ```c int Foo(int a) { // 函数左大括号独占一行,放行首 if (a > 0) { // 左大括号跟随语句放行末,前置1个空格 ... } else { // 右大括号、"else"、以及后续的左大括号均在同一行 ... } // 右大括号独占一行 ... } ``` - 条件、循环语句使用大括号,比如: ```c if (objectIsNotExist) { // 单行条件语句也加大括号 return CreateNewObject(); } ``` ```c while (condition) {} // 即使循环体是空,也应使用大括号 ``` ```c while (condition) { continue; // continue表示空逻辑,使用大括号 } ``` - case/default语句相对switch缩进一层,缩进风格如下: ```c switch (var) { case 0: // 缩进一层 DoSomething1(); // 缩进一层 break; case 1: DoSomething2(); break; default: break; } ``` - 一行只写一条语句。 - 一条语句不能过长,建议不超过120个字符,如不能缩短语句则需要分行写。 - 换行时将操作符留在行末,新行进行同类对齐或缩进一层,比如: ```c // 假设下面第一行不满足行宽要求 if (currentValue > MIN && // 换行后,布尔操作符放在行末 currentValue < MAX) { // 与(&&)操作符的两个操作数同类对齐 DoSomething(); ... } ``` ```c // 假设下面的函数调用不满足行宽要求,需要换行 ReturnType result = FunctionName(paramName1, paramName2, paramName3); // 保持与上方参数对齐 ``` ```c ReturnType result = VeryVeryVeryLongFunctionName( // 写入第1个参数后导致过长,直接换行 paramName1, paramName2, paramName3); // 换行后,4空格缩进一层 ``` ```c // 每行的参数代表一组相关性较强的数据结构,放在一行便于理解,此时可理解性优先于格式排版要求 int result = DealWithStructLikeParams(left.x, left.y, // 表示一组相关参数 right.x, right.y); // 表示另外一组相关参数 ``` - 声明定义函数时,函数的返回类型以及其他修饰符,与函数名同行。 - 指针类型"*"应该靠右跟随变量或者函数名,比如: ```c int *p1; // Good:右跟随变量,和左边的类型隔了1个空格 int* p2; // Bad:左跟随类型 int*p3; // Bad:两边都没空格 int * p4; // Bad:两边都有空格 ``` 当"*"与变量或函数名之间有其他修饰符,无法跟随时,此时也不要跟随修饰符,比如: ```c char * const VERSION = "V100"; // Good:当有const修饰符时,"*"两边都有空格 int Foo(const char * restrict p); // Good:当有restrict修饰符时,"*"两边都有空格 ``` - 根据上下内容的相关程度,合理安排空行,但不要使用连续3个或更多空行。 - 编译预处理的"#"统一放在行首,无需缩进。嵌套编译预处理语句时,"#"可以进行缩进,比如: ```c #if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) // 位于行首,不缩进 #define ATOMIC_X86_HAS_CMPXCHG16B 1 // 缩进一层,区分层次,便于阅读 #else #define ATOMIC_X86_HAS_CMPXCHG16B 0 #endif ``` ### 注释 - 注释的内容要清楚、明了,含义准确,防止注释二义性。 - 在代码的功能、意图层次上进行注释,即注释解释代码难以直接表达的意图,而不是仅仅重复描述代码。 - 函数声明处注释描述函数功能、性能及用法,包括输入和输出参数、函数返回值、可重入的要求等;定义处详细描述函数功能和实现要点,如实现的简要步骤、实现的理由、设计约束等。 - 全局变量要有较详细的注释,包括对其功能、取值范围以及存取时注意事项等的说明。 - 避免在注释中使用缩写,除非是业界通用或子系统内标准化的缩写。 - 文件头部要进行注释,建议注释列出:版权说明、版本号、生成日期、作者姓名、功能说明、与其它文件的关系、修改日志等。 - 注释风格要统一,建议优先选择/* */的方式,注释符与注释内容之间要有1空格,单行、多行注释风格如下: ```c /* 单行注释 */ ``` ```c /* * 多行注释 * 第二行 */ ``` - 注释应放在其代码上方或右方。 上方的注释,与代码行之间无空行,保持与代码一样的缩进。 右边的注释,与代码之间至少相隔1个空格。如果有多条右置注释,上下对齐会更加美观,比如: ```c #define A_CONST 100         // 此处两行注释属于同类 #define ANOTHER_CONST 200   // 可保持左侧对齐 ``` ### 宏 - 代码片段使用宏隔离时,统一通过#ifdef的方式,例如: ```c #ifdef LOSCFG_XXX ... #endif ``` - 定义宏时,要使用完备的括号,比如: ```c #define SUM(a, b) a + b     // 不符合本条要求 #define SUM(a, b) ((a) + (b)) // 符合本条要求 ``` 但是也要避免滥用括号,比如单独的数字或标识符加括号毫无意义: ```c #define SOME_CONST 100         // 单独的数字无需括号 #define ANOTHER_CONST   (-1)    // 负数需要使用括号 #define THE_CONST   SOME_CONST  // 单独的标识符无需括号 ``` - 包含多条语句的函数式宏的实现语句必须放在do-while(0)中,例如: ```c #define FOO(x) do { \ (void)printf("arg is %d\n", (x)); \ DoSomething((x)); \ } while (0) ``` - 禁止宏调用参数中出现预编译指令。 - 宏定义不以分号结尾。 ### 头文件 - 设计原则 - 头文件应当职责单一。 - 一个模块通常包含多个.c文件,建议放在同一个目录下,目录名即为模块名;如果一个模块包含多个子模块,则建议每一个子模块提供一个对外的.h,文件名为子模块名。 - 建议每一个.c文件应有一个同名.h文件,用于声明需要对外公开的接口。 - 头文件中适合放置接口的声明,不适合放置实现。 - 不要在头文件中定义变量。 - 禁止头文件循环依赖,循环依赖指a.h包含b.h,b.h包含c.h,c.h包含a.h。 - 头文件应当自包含,即任意一个头文件均可独立编译,但同时也要避免包含用不到的头文件。 - 头文件必须用#define保护,防止重复包含,比如内核中统一使用以下宏定义保护: ```c #ifndef _LOS__H // 比如 _LOS_TASK_H #define _LOS__H ... #endif ``` - 禁止通过声明的方式引用外部函数接口、变量,只能通过包含头文件的方式使用其他模块或文件提供的接口。 - 禁止在 extern "C" 中包含头文件。 - 按照合理的顺序包含头文件: 1) 源文件对应的头文件 2) C标准库 3) 需要包含的OS其他头文件 - 版权声明 - 头文件版权声明一致,放在头文件置顶位置。 - 如果提交的代码是在开源软件基础上修改所编写或衍生的代码,请遵循开源许可协议要求,并且已履行被修改软件的许可证义务。 ### 数据类型 基础类型定义统一使用los_typedef.h中定义的类型,比如定义无符号32位整型变量使用UINT32。 ### 变量 - 一个变量只有一个功能,不要把一个变量用作多种用途。 - 防止局部变量与全局变量同名。 - 不用或者少用全局变量。 - 定义函数的局部变量时,控制变量的占用空间,避免因占用过多栈空间导致程序运行失败。比如需要一个大数组,可以通过动态分配内存的方式来避免栈空间占用过大。 - 在首次使用前初始化变量。 - 指向资源句柄或描述符的变量,在资源释放后立即赋予新值,包括指针、socket描述符、文件描述符以及其它指向资源的变量。 - 禁止将局部变量的地址返回到其作用域以外,下面是一个**错误示例:** ```c int *Func(void) { int localVar = 0; ... return &localVar; // 错误 } void Caller(void) { int *p = Func(); ... int x = *p; // 程序产生未定义行为 } ``` **正确代码示例:** ```c int Func(void) { int localVar = 0; ... return localVar; } void Caller(void) { int x = Func(); ... } ``` - 如果要使用其他模块的变量,应尽量避免直接对变量进行访问,而是通过统一的函数封装或者宏封装的方式,比如mutex模块中: ```c // 私有头文件中引入全局变量,但要避免直接使用 extern LosMuxCB *g_allMux; // 通过GET_MUX的方式对g_allMux进行访问 #define GET_MUX(muxID) (((LosMuxCB *)g_allMux) + GET_MUX_INDEX(muxID)) ``` ### 函数 - 重复代码应该尽可能提炼成函数。 - 避免函数过长,新增函数不超过 40-50 行。 - 内联函数要尽可能短,避免超过 10 行(非空非注释)。 - 避免函数的代码块嵌套过深。 - 函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用。 ### 可移植性 不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句,以提高软件的可移植性和可重用性。 ### 业界编程规范 C语言编程规范参考资料较多,大家可以自行了解,本文不再过多赘述。

文档写作规范

Huawei LiteOS(以下简称LiteOS)欢迎开发者参与到开源社区的贡献中来,本文主要介绍参与LiteOS文档贡献的写作规范,如果贡献者提交文档的修改或提交新的文档,请参照此规范。 ### 命名规范 如需提交新的文档,在LiteOS代码仓doc目录下创建新的.md文件,命名需遵循 xxx\_xxx.md 格式,根据文档的内容来声明。 比如介绍写作规范的文档,可以命名为 LiteOS\_doc\_write\_standard.md。 ### 内容规范 以简洁、直观地表达所述内容为目的,介绍性文档言简意赅介绍原理、架构、设计思路等,操作类文档写明关键步骤,以便能对其他开发者起到帮助。可以优先使用中文,建议中英文都支持,LiteOS也将持续更新,保证中英文的同步。 1. **标题** 建议标题层级不超过三级。 2. **正文** - 操作类文档以移植为例,文档结构可以参考如下: 1. 目的(简述操作目的,如移植到哪款型号的单板) 2. 软硬件环境准备 3. 移植具体步骤 4. 结果验证 - 介绍性文档以开发指南某一功能为例,文档结构可以参考如下: 1. 概述(概念及原理介绍) 2. 功能(支持的接口列表) 3. 开发流程(如何使用及相应步骤) 4. 编程实例(提供具体代码示例) 5. 注意事项 6. 其他 3. **图片** 图片统一存放到文档同级目录下的figures文件夹中(英文文档对应figures-en),如 LiteOS/doc/quick\_start/LiteOS\_doc\_write\_standard.md 中使用的图片,统一放置到 LiteOS/doc/quick\_start/figures 目录下,文档中使用相对路径引用图片。图片建议根据内容命名,只用数字序列不利于后续图片的继承。 >![](public_sys-resources/icon-note.gif) **说明:** >引用方式: >!\[\]\(./figures/figures-standard.png\) 如果是自制图片,配色请参考如下,格式不限,png/jpg/gif...均可,如果是截图或者其他地方引用图片,风格不做限制。 ![](figures/contribute/picture_color_in_document_writing.png) 4. **表格** 在md文件中可以按照如下形式插入表格。 ``` | Tables | Type | Note | | ----------- |:-------------:| -----:| | first | standard | None | | second | outstanding | 5 | | third | inside | with | ``` 5. **代码** 正文中插入代码段,可以在段落前后加上符号 \`\`\`。
```c int size = 10; \```

Commit message规范

### 概要说明 目前,社区有多种 Commit message 的写法规范。LiteOS采用的是Angular规范,这是目前使用最广的写法,比较合理和系统化,并且有配套的工具。 ### Commit message的作用 格式化的Commit message有几个好处: - 提供更多的历史信息,方便快速浏览 - 可以过滤某些commit(比如文档改动),便于快速查找信息 - 可以直接从commit生成Change log ### LiteOS Commit message的格式 每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。 ```
空一行 空一行