Chinaunix首页 | 论坛 | 博客
  • 博客访问: 255800
  • 博文数量: 108
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 314
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-29 10:58
文章分类

全部博文(108)

文章存档

2015年(20)

2014年(88)

我的朋友

分类: LINUX

2014-09-23 09:11:02

Linux最大的优势就是它有一个紧密团结了众多使用者和开发者的社区。

1.社区

(1)Linux kernel mailing list,内核邮件列表

发送一下纯文本信息订阅内核邮件列表

subscribe linux-kernel

(2) 

内核邮件列表的FAQ

(3

适合内核开发初级黑客的乐土。

(4) 

Linux新闻周刊,有一个专门报道有关内核的重要新闻。

2.Linux编码风格

Linux指定了一套编码风格,并不是说这套编码风格多么优秀(可能确实还不错)或者你原来风格有多么拙劣,而是因为保持编码风格的一致性,有助于提高编程效率。

(1) 缩进

缩进风格用制表符(Tab),每次缩进8个字符长度,不能用空格代替;八个字符宽度的缩进能让不同的代码块看起来一目了然,特别是在连续几个小时的开发之后,效果更加明显。

(2) switch语句

switch语句下属的case标记应该缩进到与switch声明对齐,这样有助于减少8个字符的tab键的排版缩进。

点击(此处)折叠或打开

  1. switch (animal) {
  2. case ANIMAL_CAT:
  3.               handle_cats();
  4.               break;
  5. case ANIMAL_WOLF:
  6.               handle_wolves();
  7.               /* fall through */
  8. case ANIMAL_DOG:
  9.               handle_dogs();
  10.               break;
  11. default:
  12.               printk(KERN_WARNING”unknown animal!\r\n”);
  13. }

当执行逻辑需要有意地从一个case声明尾部进入另外一个case声明时,对齐进行注释。

(3) 空格

空格放在关键字周围,函数名和圆括号之间无空格。

点击(此处)折叠或打开

  1. if (foo)
  2. while (foo)
  3.     for (I = 0; I < NR_CPUS; i++)
  4. switch (foo)

括号内,参数前后也不假空格;

对于大多数二元或三元操作符,在操作符的两边加上空格;

点击(此处)折叠或打开

  1. int ret = (bar) ? bar : 0;

对大多数一元操作符,在操作符和操作数之间不加空格;

点击(此处)折叠或打开

  1. struct work_struct *work = &dwork->work;

在提领运算符的周围加上合适的空格尤为重要,

点击(此处)折叠或打开

  1. char *strcpy(char *dest, const char *src);

(4) 花括号

左括号紧跟在语句的最后,与语句在相同的一行,而右括号新起一行。

函数,左右括号都新起一行;

不需要一定使用括号的语句可以忽略它:

点击(此处)折叠或打开

  1. if (cnt > 63)
  2.               cnt = 63;

(5) 每行代码的长度

尽可能地保证每行代码长度不超过80个字符;

可以在圆括号内分行,对齐排列函数参数;

(6) 命名规范

不允许使用骆驼拼写法(CamelCase), Studly Caps,匈牙利命名法或者其他混合的大小写字符。

全局变量和函数,都应该选择包含描述性内容的名称,并且使用小写字母,必要时加上下划线区分单词。

(7) 函数

根据经验,函数的代码长度不应该超过两屏,局部变量不应超过10个。一个函数应该功能单一并且实现精准。

将一个函数分解成一些更短小的函数的组合不会带来危害,如果你担心函数调用导致的开销,可以使用inline关键字。

(8) 注释

一般情况下,你应该描述的是你的代码,要做什么,为什么要做,而不是具体通过什么方式实现的,怎么实现应该由代码本身展现。

此外,注释不应该包含谁写了哪个函数、修改日期和其他那些琐碎而无实际意义的内容,这些信息应该集中在文件开头的地方。

注释中,重要信息常以“xxx:”开头,而bug通常以“FIXME:”开头

点击(此处)折叠或打开

  1. /*
  2.  * FIXME: We assume dog == cat which may not true in the future
  3. */

内核包含一套自动文档生成工具,它源自GNOME-doc, 略加修改后命名为Kernel-doc,如果想要生存独立的HTML格式文档,运行

make htmldocs

如果想要postscript格式的话,运行

make psdocs

有关此方面更多细节,参看Documentation/kernel-doc-nano-HOWTO.txt文件。

(9) typedef

内核开发者们强烈返回使用typedef语句,理由是:

typedef掩盖了数据的真实类型;

由于数据类型隐藏起来了,所以很容易因此犯错误,比如以传值的方式向栈中推入结构;

使用typedef往往是因为想要偷懒;

使用typedef的情况:

当需要隐藏变量与体系结构相关的实现细节的时候,当某种类型将来有可能发生变化,而现有程序必须要考虑到向前兼容问题的时候,需要使用typedef. 

(10) 多用现成的东西

请勿闭门造车,内核本身就提供了字符串操作函数、压缩函数和一个链表接口,所以请使用它们。

不要为了使现存接口更通用化而对它们进行封装,当移植时,隐藏的接口可能不兼容,所以请直接使用内核提供的接口。

(11) 在源码中减少使用ifdef

不赞成在源码中使用ifdef预处理指令,绝不应该出现如下实现方法:

点击(此处)折叠或打开

  1. #ifdef CONFIG_FOO
  2.               Foo();
  3. #endif

正确做法,在CONFIG_FOO没定义的时候,应该让foo()函数为空。

点击(此处)折叠或打开

  1. #ifdef CONFIG_FOO
  2. static int foo(void)
  3. {
  4.        /**/
  5. }
  6. #else
  7. static inline int foo(void) {}
  8. #endif

(12) 结构初始化

内核支持新的C99标识符格式初始化

点击(此处)折叠或打开

  1. struct foo my_foo = {
  2.               .a = INITIAL_A,
  3.               .b = INITIAL_B,
  4. };

对于结构体其他未初始化成员,按ANSIC规定的默认值(指针设为NULL, 整型设为0,浮点型设为0.0.

(13) 代码的事后修正,利用Indent工具,格式化得到GNU风格代码

indent -kr -i8 -ts8 -sob -l80 -ss -bs -psl

还可通过scripts/Lindent自动按照所需的格式调用indent

3.管理系统

所有做出卓越贡献的黑客都能在源码树根目录上的CREDITS文件中留名。

内核中几乎每个部分都对应一个维护者(一个或几个对内核特定部分负责的人)。驱动程序和子系统的维护者也能在源代码树根目录上的MAINTAINERS文件中找到。

还有一类特殊的内核维护者,他们负责维护的实际上就是代码树本身。以前Linus自己负责维护开发板的内核,稳定版最开始的一段时间也有他来维护,等该内核版本稳定下来,他就会把火炬传递给最好的内核开发者中的一些人手上,由他们维护该代码树,而Linus也会启动下一个开发版本的内核开发工作。

4.提交错误报告

提交一个错误报告最重要的莫过于对问题进行清楚的描述,讲清楚症状,系统输出信息,完整并经过解码的oops,更好重要的是,应该尽可能地提供能够准确地重现这个错误的步骤,并提供你机器的硬件配置基本信息。

MAINTAINERS文件列举了每个相关的设备驱动程序和子系统的单独信息接收关于其所维护的代码的所有问题。如果找不到对此问题感兴趣的人,的内核邮件列表

文档REPORTING-BUGSDocumentation/oops-tracing.txt中有更多相关信息。


5.补丁

对内核的任何修改都是以补丁的形式发布的,补丁其实是GNU diff程序的一种特定格式的输出,该格式的信息能够被patch程序接收。

(1) 创建补丁

创建补丁最简单的办法是通过两份内核源代码进行,一份源码,另一份是加进了修改部分的源代码。比如源码为linux-x.y.x, 修改过的代码起名为Linux,下面命令可以创建补丁:

diff –urN  linux-x.y.x  linux/   > my-patch

-u是格式化字串,-r参数保证遍历所有子目录,-N指明做出修改的源代码中所有新加入的文件在diff操作时都会包含在内。

如果想单独对一个文件进行diff

diff –u linux-x.y.z/some/file  linux/some/file  > my-patch

注意,在代码所在目录执行diff很重要,这样方便别人使用补丁。

打补丁:

在自己的源码树下,执行下面命令

patch –p1 < ../my-patch

补丁的名字叫my-patch, 它位于当前目录的上一级目录上,-p1参数用来剥去补丁中头一个目录的名称。

diffstat是一个很有用的工具,它可以列出补丁所引起的变更的统计,输出关于补丁的信息,执行:

diffstat –p1  my-patch

在向lkml贴出自己的补丁时,附带上这份信息往往会很有用。

(2) 用Git创建补丁

Git管理源代码树时,可以用git工具来生成补丁。

把所做的修改提交到你的Git版本库:

git commit –a

-a参数表示提交所有的修改,如果仅仅想提交某个指定文件

git commit some/file.c

即使有了-a参数,git并不立即提交新文件,知道把它们添加到版本库中才提交。

要增加一个文件,然后再提交

git add some/other/file.c

git commit –a

执行gitcommit命令时,git会要求输入一个更改日志,用来详细完整的记载修改缘由。可以为每个提交创建一个补丁

git format-patch  origin

对于所有的提交,这样产生的补丁放在你的版本库中而不是原始树中,git产生的补丁位于源码树的根目录中。如果只想为最后第N此提交产生补丁,则可以执行

git format-path  -N

(3) 提交补丁

如果补丁涉及了某个特定的驱动或子系统,应该把它发送给MAINTAINER中列举的相关部分的维护者,发送一份拷贝。只有在广泛讨论之后,或者补丁的修改很细微并且很容易就能保证正确的时候,才应该向内恶化维护者(比如Linus)提交。

一个补丁邮件,主题一览应该以“[PATCH] 简要说明”格式写出,邮件主题应该描述所作的改变的技术细节,以及这么做的原因,越详细越好;在Email中还要注明补丁对应的内核版本。

内核开发者们希望能够通过邮件阅读补丁,并且能够将其保存为一个单独文件,因此,最好把补丁直接插入邮件,放在所有信息的最后。

如果你的补丁很大或者包含了几个不同的逻辑的修改,那么应该将你的补丁分成几块,每块对应一个逻辑。如果任何一个部分需要其他的补丁先行,要明确注明这一点。

 

阅读(856) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~