libmaple Coding Standards ========================= Author: Marti Bolivar (mbolivar@leaflabs.com) LeafLabs team members are required to follow these when producing new code. Community contributors to libmaple are strongly encouraged to do so; following these rules will greatly increase the probability that your patches will be folded in. In general, do it like this unless there's a really good reason why not. You being lazy doesn't count as a good reason. Most, if not all, of these decisions are entirely arbitrary, but it's important for readability that we be consistent. The file .dir-locals.el in the libmaple root directory already ensures that many of these standards are followed by default in Emacs (but not on Windows, where it would need to be named _dir_locals.el, and no way, man). There's also some elisp scattered about this file which will provide you additional help. Vim customizations to do the same thing would be nice (hint, hint)! License ------- - Put an MIT license at the beginning of the file (look at any of our source files for an example). Copyright should go to either you or LeafLabs LLC. Emacs: if you don't like seeing the license, you should use elide-head (which will hide it for you). Here is some elisp you can modify to make this pleasant: (require 'elide-head) (setq programming-mode-hooks '(c-mode-hook c++-mode-hook)) (add-to-list 'elide-head-headers-to-hide '("The MIT License" . "DEALINGS IN\n [*] THE SOFTWARE")) (add-to-list 'elide-head-headers-to-hide '("The MIT License" . "DEALINGS IN THE\n...SOFTWARE")) (dolist (hook mbolivar-programming-mode-hooks) (add-hook hook (lambda () (elide-head)))) Whitespace/Indentation ---------------------- - 4 space indents. [Set in .dir-locals.el] - Unix newlines. - No tab characters. [Set in .dir-locals.el] - No trailing whitespace. For help getting this (and no tab characters) done automatically in Emacs, you can use this: http://github.com/mbolivar/code-fascism I hear tell you can get something similar in vim; ask around, I guess. - Files end in exactly one newline. [The presence of a newline at EOF is already done by `c-require-final-newline' in recent versions of Emacs.] - Exactly two newlines separate source paragraphs (you do separate your code into paragraphs, don't you?). - The first line in a function is non-blank. - Don't indent C code within a conditionally-compiled extern "C" block. Emacs does this by default, which can be very annoying; you can turn this behavior off with (defun c-mode-inextern-lang-hook () (setcdr (assq 'inextern-lang c-offsets-alist) '-)) (add-hook 'c-mode-hook c-mode-inextern-lang-hook) Comments -------- - Multi-line comments look like this: /* text starts here * continued lines have a '*' before them * the comment can end after the last line */ or this: /* comment starts here * the comment can end on the same line */ - Doxygen comments are newline comments that begin with /** instead. It is not required that the "/**" appear on a line by itself. - Single-line comments on the same line are // in c or c++. - Single-line comments on their own source line are /* */ in c, but can also be // in c++. If you think that typing out /* */ is too slow in emacs, use M-; (comment-dwim) when you're on an empty line, and it'll ... well... You should be using the (super awesome) comment-dwim; it pretty much does exactly what you want to the comment on the current line, including "create one and put it in the right place". Braces ------ - 1TBS. Nothing more need be said. http://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS Naming conventions ------------------ - There's always a fight about upper and lower case vs. underscores. We'll handle this as follows. First, Dammit_Dont_Mix_Like_This, because It_Looks_Really_Ugly, ok? [There's been some debate about this, and some exceptions are already grandfathered in, so in order to settle it, let's call this a "recommendation" instead of "requirement".] - Variables: Use underscores to separate words in C identifiers: int some_example_name; It is strongly advised to do it this way in C++ too, but it's not [yet] mandatory. - Classes: Pascal case. So ThisIsAClassName, but thisIsNot, this_is_not, and like I said, Dont_You_DareTryANYTHING_STUPID. - Functions: C functions are all lowercase, and words are separated by underscores. C++ method names are camel cased (thisIsAnExample). - Structs: pick a style from "Variables" or "Classes" depending on how you mean it (since it might be either a simple record type, in which case do like c variables, or you might be faking an object in c, in which case do like classes). If it's in a typedef, don't feel obliged to put "_t" at the end of the name; we don't. - Macros and constants: all caps, separated by underscores. Variables with the "const" qualifier aren't considered "constants" for the purposes of this rule; i.e., case them according to the rules for variables. - foo.h gets #ifdef'ed to _FOO_H_. - Acronyms: The case of letters in an acronym is determined by the case of the first letter in the acronym, which is determined by following the above rules. Examples: void usb_func() { ... } class SomethingUSB { void usbInit(); void initUSB(); }; Never do this: class BadUsb { ... }; // say "GoodUSB" instead Documentation ------------- - Document your code. This should go without saying. - For complicated peripherals, it would be nice if you put longer-form comments into this directory (notes/), with a comment in the corresponding .h file referring to it. See libmaple/dac.h for an example. That lets us keep the source files relatively clean while still allowing new readers to have a starting point. - At least put a doxygen comment with a nonempty @brief for every .h file you add. See the existing ones for examples. For now, it'd be better if you didn't put a @brief into any .c[pp] files, since it (currently) interferes with our documentation generator in a way that I won't explain here (though you can look into the LeafLabs or michaeljones breathe repos on github and potentially figure out why). - Doxygen comments generally just belong on types, functions, etc. that are part of the public user-facing API. This generally means that if there's ReST documentation for it under docs/source/, it needs Doxygen comments, and that ReST should use Breathe to pull that Doxygen comment out. (For more info on this, see docs/README). There are some exceptions to this rule since Breathe isn't totally mature yet and Sphinx's C++ domain is still in flux. In these cases, document the code "manually" in ReST. This should be avoided if at all possible, since it creates a maintenance burden of documenting things in two places at once, and provides an opportunity for bad documentation to slip in, when the code comments fall out of sync with the ReST docs. General Formatting ------------------ - Keep it 80-column clean. That means Emacs says the largest column number=79. If you haven't already, you should turn on column numbers to help you out: (column-number-mode 1) You can get more help from lineker-mode. Download it here: http://www.helsinki.fi/~sjpaavol/programs/lineker.el Then put the file somewhere in your load-path, and: (require 'lineker) (dolist (hook '(c-mode-hook c++-mode-hook)) (add-hook hook (lambda () (lineker-mode 1)))) There are only a few exceptional situations. The most important one is when specifying a lookup table like PIN_MAP where it'd be ugly to split each entry over multiple lines.