Chromium的代码风格说明写得很不错,很多细节都很符合我的习惯,比如代码格式和对assert的处理。:-)
Chromium项目的代码风格遵守Google C++ Style Guide。下面几点是在Google风格的基础上进行的扩展。本文没有提到的规则,都遵守Google风格。如果某规则在Google风格中是可随意的,本文也没有特别说明,那么在Chromium中就也是可随意的。Objective-C/C++代码应该遵守Google Objective-C Style Guide。如果使用emacs,可以使用style definition for c-mode。Python代码应该遵守PEP-8,不过在Chromium中,把4空格缩进改成2空格缩进,方法和函数名使用混合大小写(MixedCase)风格,而不是带下划线的小写(lower_case_with_underscores)。
-单元测试和性能测试的命名应分别以_unittest和_perftest结尾,它们应与被测的程序文件放在同一个目录中。
-Win32窗体类的命名应以Chrome_开头(注意大小写)。
-表示数量的变量,应在名字中带上单位。比如kUpdateTimerMsec或num_downloaded_bytes。
-表示web地址时,应该用URL,而不是URI。
-应该使用unix_hacker风格,而不是驼峰法(CamelCase)。
-Google风格强烈建议(不是必须)使用unix_hacker风格来命名内容很简短、影响很小的成员函数,比如那些简单的函数,或者设置读取器函数(getters and setters)。当然,这也要看团队的习惯。有些代码,什么东西都用驼峰法(CamelCase)命名。没必要只为了改几个函数名风格就专门打补丁,但在新代码中,应使用这些命名风格,除非是在封装时驼峰法(CamelCase)更合适(unless there are encapsulation reasons why CamelCase would be much more appropriate)。
-"Chromium"是项目名,而不是产品名,不要把它写到代码或API中。需要的话,可以用"chrome"。
-虽然Google C++ Style Guide中说现在应该用kConstantNaming的风格来命名枚举类型,但现在的代码中,还是在用MACRO_STYLE,以便保持一致性。
-用Foo* bar和const Foo& bar的形式,而不是Foo *bar和const Foo &bar。
-有条件返回语句时,return应单独一行(方便跟踪)。
-当表达式换行时,操作符应该在上一行的末尾,而不是下一行的开头。比如:
正确:
foo = bar +
baz;
错误:
foo = bar
+ baz;
打印日志是个例外。如果写一行日志超过80个字符,需要换行时,子行应该以<<操作符开头,并且开头的<<应与上一行的<<对齐:
LOG(INFO) << "I have a very long log message here, with multiple things to"
<< " say and some variables to print out, like var1: "
<< var1 << " and var2: " << var2;
-空指针使用NULL,而不是0或者自定义一个null(例外:WebKit风格的代码应该使用0来保持一致性)。
-bool型变量使用true和false。在有些地方,必须使用BOOL型,那么就应该用TRUE和FALSE。
-某些有强迫症的童鞋喜欢把cc文件里的函数顺序和h文件里的函数声明顺序保持一致。Google C++ Style Guide里没有这个要求,如果你碰到有顺序不一致的,应保留它原样不变。
-当被h文件包含时,我们尝试过,并能确定消息映射宏按字母顺序排列的话,更容易扫描。所以请按照此约定添加新的消息处理代码。
-当你实现一个接口时,应把从它继承的函数在h文件里排在一起,与其它声明区分开来,这样就能很清晰地知道它们是实现的同一接口。它们的顺序也必须和基类里的一致,中间不要加注释和空格,这样阅读的时候就能看出基类里的更多信息。
-类的函数定义应明确加上inline关键字来表明它们的编译方式,前提是如果它们确实需要是内联函数。把一个类放在一个cc文件中,把声明和定义分开是个好主意,这样可以增强声明的可读性。
平台相关的代码应该使用build/build_config.h中定义的宏,而不是WIN32这种玩意。现在已经有的平台定义有OS_WIN,OS_MACOSX和OS_LINUX。不要用#else来处理平台相关的代码,应该明确地表明代码是用在哪些平台下的。同时用在Mac和Linux下的代码,可以用OS_POSIX来定义(比如pthreads)。
错误:
#ifdef OS_WIN
<Windows code>
#else
<Mac & Linux code>
#endif
#if defined(OS_WIN)
<Windows code>
#elif defined(OS_POSIX)
<Mac & Linux code>
#endif
-不要check-in以vcproj,sln,xcodeproj,scons为后缀的文件,只check-in GYP文件就可以了。我们通常的编译设置在common.gypi中查看。
-只有一种情况可以接受非gyp工程文件,那就是不用打开工程文件的第三方库。这可以让复制品尽可能与原版保持一致。
-尽量用#pragma而不是工程设置来引入lib文件。
-在编译选项中把waning级别设置为fatal,除非你要编译第三方代码,而它又不容易修改。(即便如此,加上#pragma warning(disable: [warning #])试试看也没啥损失)。
-不要使用有构造或析构函数,甚至啥也没有的静态变量(尤其是全局变量)。要像避免诡异的crash(就是那种连crash捕捉器都捉不到的crash)那样避免它们。需要的话,就用单例(Singleten)模式吧。
-上面都是基于Google C++ Style Guide来讨论的。包括“用int来处理一般的记数”和“不要用unsigned int因为你不确定结果什么时候会是负数”。但是,还是有几点需要澄清一下:
-处理对象数量或内存数据大小时,比如很大的一个buffer或内存块的字节数,字符串的长度,STL容器中对象的数量,应优先用size_t而不是int。有种情况就是,当调用一个库函数时,它要求传入或返回一个size_t类型变量,那你就应该使用size_t,而不是在它与int之间转来转去。
-有些情况要处理一些数据类型的精确大小(比如32位像素值,位图遮罩(bitmask),精确宽度的计数器),应使用uint32这种类型,而不是size_t。对于有些不在内存中的对象,或者数量超过32位的,比如下载文件的偏移量(可能有好几G),那就应使用uint64。
-跨主机或进程传递数据时,安全起见应使用精确大小的类型,因为发送和接收方可能对int和size_t编译出的大小不同。例如,在IPC层,我们使用uint32来存储“内存中的小对象”。一般不论什么情况,调用这些函数的代码都应该使用原生类型(上面所有规则都适用),有必要的话,应在IPC层的入口处做转换。
-因为有符号类型是病毒,而我们也不可能总是小心翼翼地做到上面几点,所以你可能能找到一些调API时该传size_t却传了int的错误。如果有可能,考虑清理下吧。
-基于经验和测试,函数通过返回值返回std::[w]string和通过传出参数返回速度是一样的。所以为了可读性,我们鼓励尽量通过返回值返回字符串。
-Chromium项目中所有源文件必须以下面的文字开头。注意,你不用修改已存在的文件里的版权时间,除非你因为什么原因修改过它。
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-Chromium OS项目的源代码以下面文字开头,与Chromium稍有不同(Chromium -> Chromium OS)。
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-Chromium项目在服务器上为一些其它开源项目做了镜像(比如U-Boot)。当为这些项目贡献代码时,请保留原项目的版权头。
-我们没有把作者(Author):这些内容加到源文件中。如果贡献了代码,那么trunk/src/AUTHORS里是没有你或你的组织的名字的,请把你的名字和联系方式加进去。
在WebKit转换和glue目录中,你应该能找到WebKit文件。我们已经在WebKit glue源文件里使用了Google风格,除非它包含了WebKit的文件。glue代码应该按WebKit方式包含WebKit h文件(不带额外的路径信息),并带有警告监控包装了WebKit头,这样当这些文件被忽略时,就可以收到警告。包含WebKit时,一定要先包含config.h,否则就会有奇怪的错误!例如:
#include "webkit/glue/me.h" // Begin with the corresponding header for this .cc file.
#include <stdlib.h>
#include "config.h" // WebKit section, note alphabetical order.
#include "Document.h"
#include "Frame.h"
#include "Page.h"
#pragma warning(pop)
#include "webkit/glue/webkit_glue.h"
对于Chromium开发,你应该在~/.subversion/config (On Windows: %APPDATA%\Subversion\config)中,配置http://src.chromium.org/viewvc/chrome/trunk/tools/buildbot/slave/config为自动设置属性。
CHECK()用来检查断言,如果不满足条件就会立刻crash。DCHECK()和CHECK()差不多,但它只在debug编译时起作用。NOTREACHED()只在debug下中断,相当于DCHECK(false)。这些宏定义在base/logging.h里。
Coding Style
Coding style for the Chromium projects generally follows the Google C++ Style Guide. The notes below are usually just extensions beyond what the Google style guide already says. If this document doesn't mention a rule, follow the Google C++ style. If Google style is flexible on a particular topic, and this document doesn't clarify below, then Chromium style is also flexible on that topic. Objective-C/C++ code should follow the Google Objective-C Style Guide. If you use emacs, you may find Google's style definition for c-mode helpful. Python code should follow PEP-8, except that Chromium uses two-space indentation instead of four-space indentation, and it uses MixedCase for method names and function names instead of lower_case_with_underscores. Try to follow any per-file conventions you notice when modifying existing code.When working on WebKit code, you should use the WebKit coding style instead. The remainder of this page covers rules that are specific to the Chromium projects.
Naming
Code formatting
foo = bar + not:
foo = bar An exception is log messages. When you have a log line that is longer than 80 characters, subsequent lines should start with the << operator and should be aligned based on the first << from the original line:
LOG(INFO) << "I have a very long log message here, with multiple things to"
Platform-specific codePlatform-specific code should use the system specific defines in build/build_config.h and not other things such as WIN32. Current platforms are OS_WIN, OS_MACOSX, andOS_LINUX. Don't use an #else clause to define platform behavior, it should opt-in to everything explicitly. Use OS_POSIX to define something applicable for Mac and Linux (for example, pthreads).Prefer #if defined(...) rather than #ifdef for platform-specific code. This lets somebody else add an #elif defined(...) later on which will match.
Bad:
#ifdef OS_WIN Good:
#if defined(OS_WIN) If you need to do something based on the type of wchar_t, don't use platform defines. Use WCHAR_T_IS_UTF16 or WCHAR_T_IS_UTF32 instead.
Project settings
Static variables
Method signatures
File headers
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
WebKit glue styleYou should only be including WebKit files in our WebKit port and glue directories. We always use Google style for WebKit glue files with the exception of when WebKit files need to be included. Glue code should include WebKit headers the WebKit way (with no extra path information) and wrap WebKit headers with warning guards so that warnings in those files are ignored. Be sure to include config.h first when you are using WebKit includes, or you will get weird errors! Example:
#include "webkit/glue/me.h" // Begin with the corresponding header for this .cc file. Subversion propertiesFor Chromium development, you should configure your We do not use svn:eol-style=native. It is a pain to move diff files across platforms, especially for the try server.
CHECK() vs DCHECK() and NOTREACHED()The CHECK() macro is used for checking assertions, and will cause an immediate crash if its assertion is not met. DCHECK() is like CHECK() but is only compiled in on debug builds. NOTREACHED() is a debug-only break, equivalent to DCHECK(false). These macros are defined in base/logging.h.
Use DCHECK or NOTREACHED to inform developers when they are misusing a function or when a bad condition arises that the developer should be made aware of. In general--and this may seem counter-intuitive — it is preferable to crash instead of handling a DCHECK failure. Attempting to handle a DCHECK failure in a graceful manner is a statement that the DCHECK can fail, which contradicts the point of writing the DCHECK. (If you find yourself writing such code, then perhaps what you really want is to use DLOG or LOG.) In some cases the consequences of a failed DCHECK may result in a crash. This is not necessarily a terrible thing. The crash will be logged, and that will result in visibility to the fact that the DCHECK fails in the wild. It is far better to receive detailed crash reports than vague anecdotes about unreproducible hangs, dead clicks, or other misbehaving non-crash conditions.
Sometimes it is preferable to force a crash to happen via CHECK. Those cases include situations where you are dealing with untrusted input (provided there is no reasonable recovery path) and the consequences of continuing execution could result in a security vulnerability. It is also common practice to use CHECK to help root out the source of an observed, but obtuse, crash report. Developers may sprinkle CHECKs around the crash site to reveal more information about the crash.
Sometimes there are better options besides CHECK when dealing with malformed input from an untrusted source. For example, if a renderer sends the browser process a malformed IPC, it is better to just kill the offending renderer than to crash the browser process.
|