diff options
| author | Patrick Williams <patrick@stwcx.xyz> | 2016-11-07 13:54:52 -0600 |
|---|---|---|
| committer | Patrick Williams <patrick@stwcx.xyz> | 2016-12-05 16:46:14 +0000 |
| commit | 31f951b3a47735330b7a1fdcae2e9bb6757965d5 (patch) | |
| tree | fa24a638d0698234ea321161b85c7a97019a0f24 | |
| parent | e1712f320914e14f456f3921e7ab0d748c79622d (diff) | |
| download | openbmc-docs-31f951b3a47735330b7a1fdcae2e9bb6757965d5.tar.gz openbmc-docs-31f951b3a47735330b7a1fdcae2e9bb6757965d5.zip | |
cpp-style: define style guidelines in-depth
The original set of C++ style guidelines were arguably insufficient
for teams of diverse backgrounds. Attempt to formalize these guidelines
and specify in more depth.
Change-Id: I22253f7b9de91d693c33d55d612c3555fa5b219f
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
| -rw-r--r-- | contributing.md | 21 | ||||
| -rw-r--r-- | cpp-style-and-conventions.md | 408 |
2 files changed, 409 insertions, 20 deletions
diff --git a/contributing.md b/contributing.md index e97625b..7837a43 100644 --- a/contributing.md +++ b/contributing.md @@ -73,26 +73,7 @@ This style can mostly be verified with 'astyle' as follows: ### C++ -Being an extensive and complicated language, there are often differences of -opinions on "good" and "bad" C++ code. The following are the approaches -favored within the OpenBMC projects: - - 1. Favor syntax and techniques from the latest available C++ standard, - currently C++14. - 2. Rely on well-recognized opinions on best practices: - 1. C++ Core Guidelines - https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md - 2. Effective Modern C++ - http://www.aristeia.com/books.html - 3. Give preference to style decisions from the Google C++ Style Guide - - https://google.github.io/styleguide/cppguide.html - -In order to meet the chosen style for C++ code, files should pass through -'astyle' unchanged when called as follows: - - astyle --style=allman --add-brackets --convert-tabs --max-code-length=80 \ - --indent=spaces=4 --indent-classes --indent-switches --indent-labels \ - --indent-preproc-define --min-conditional-indent=0 --pad-oper \ - --pad-header --unpad-paren --break-after-logical \ - --align-pointer=type --align-reference=type +See [C++ Style and Conventions](./cpp-style-and-conventions.md). Submitting changes ------------------ diff --git a/cpp-style-and-conventions.md b/cpp-style-and-conventions.md new file mode 100644 index 0000000..442d6ef --- /dev/null +++ b/cpp-style-and-conventions.md @@ -0,0 +1,408 @@ +# C++ Coding Style and Conventions + +## General Philosophy + +Being an extensive and complicated language, there are often differences of +opinions on "good" and "bad" C++ code. Bjarne Stroustrup has said "Within C++ +is a smaller, simpler, safer language struggling to get out." We are striving +to write in this variant of C++ and are therefore following the "C++ Core +Guidelines" that Bjarne and Herb Sutter introduced at CppCon 2015. + +Beyond a set of rules that help codify "good" and "bad" C++, we have general +principles that help us align the software we develop with the constraints +within the problem domain being solved by OpenBMC. These are: + 1. Code should be clear and concise. + 2. Code should be written with modern practices. + 3. Code should be performant. + +### Code should be clear and concise + +> Brevity is the soul of wit. + +It is important that code be optimized for the reviewer and maintainer and not +for the writer. Solutions should avoid tricks that detract from the clarity +of reviewing and understanding it. + +Modern practices allow C++ to be an expressive, but concise, language. We tend +to favor solutions which succinctly represent the problem in as few lines as +possible. + +When there is a conflict between clarity and conciseness, clarity should win +out. + +### Code should be written with modern practices + +We strive to keep our code conforming to and utilizing of the latest in C++ +standards. Today, that means all C++ code should be compiled using C++14 +compiler settings. As the C++17 standard is finalized and compilers support +it, we will move to it as well. + +We also strive to keep the codebase up-to-date with the latest recommended +practices by the language designers. This is reflected by the choice in +following the C++ Core Guidelines. + +[[Not currently implemented]] We finally desire to have computers do our +thinking for us wherever possible. This means having Continuous Integration +tests on each repository so that regressions are quickly identified prior to +merge. It also means having as much of this document enforced by tools as +possible by, for example, astyle/clang-format and clang-tidy. + +For those coming to the project from pre-C++11 environments we strongly +recommend the book "Effective Modern C++" as a way to get up to speed on the +differences between C++98/03 and C++11/14/17. + +### Code should be performant. + +OpenBMC targets embedded processors that typically have 32-64MB of flash and +similar processing power of a typical smart-watch available in 2016. This +means that there are times where we must limit library selection and/or coding +techniques to compensate for this constraint. Due to the current technology, +performance evaluation is done in order of { code size, cpu utilization, and +memory size }. + +From a macro-optimization perspective, we expect all solutions to have an +appropriate algorithmic complexity for the problem at hand. Therefore, an +`O(n^3)` algorithm may be rejected even though it has good clarity when an +`O(n*lg(n))` solution exists. + +## Global Guidelines and Practices + +Please follow the guidelines established by the C++ Core Guidelines (CCG). + +https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md + +[[ Last reviewed revision is 53bc78f ]] + +Exceptions: + +### Guideline Support Library (GSL) + +We do not currently utilize the Guideline Support Library provided by the CCG. +Any recommendation within the CCG of GSL conventions may be ignored at this +time. + +### Style recommendations + +The following are not followed: + * NL.10 Avoid CamelCase + * NL.17 Use K&R-derived layout + +## Library and Feature Specifics + +Additional recommendations within the OpenBMC project on specific language +features or libraries. + +### Exceptions + +We do use exceptions as a basis for error handling within OpenBMC. + +### Boost, QT, etc. + +> If you give a mouse a cookie... + +While, in general, we appreciate reuse over rewriting, we are not using large +general-purpose libraries such as Boost. Due to 'Code should be performant: +code size' we do not want to utilize the entirety of Boost. If approval is +given for a single part of a large general-purpose library it becomes much more +difficult to disapprove of another part of the library. Before long, we may +have effectively approved of the entire library. + +We do look for single feature libraries that can be used in place of our own +implementations. + +### iostream + +The iostream conventions of using 'operator<<' contribute to an increased code +size over printf-style operations, due to individual function calls for each +appended value. We therefore do not use iostreams, or iostream-style APIs, +for logging. + +There are cases when using an iostream utility (such as sstream) can result in +clearer and similar-sized code. iostream may be used in those situations. + +## Coding Style + +Indentation, naming practices, etc. + +[[ These should be codified as much as possible with astyle / clang-format. ]] + +An astyle-invocation that closely approximates our indentation style is: +``` +astyle --style=allman --add-brackets --convert-tabs --max-code-length=80 \ + --indent=spaces=4 --indent-classes --indent-switches --indent-labels \ + --indent-preproc-define --min-conditional-indent=0 --pad-oper \ + --pad-header --unpad-paren --break-after-logical \ + --align-pointer=type --align-reference=type +``` + +### General + +* Line length should be limited to 80 characters. +* Indentation should be done with 4 space characters. + +### Bracket style + +* Utilize 'Allman' style brackets. Brackets are on their own line at the same + indentation level as the statement that creates the scope. + +``` +if (condition) +{ + ... +} +``` + +``` +void foo() +{ + ... +} +``` + +* Even one line conditional and loop statements should have brackets. + +``` +/// Wrong. +if (condition) + do_something; + +/// Correct +if (condition) +{ + do_something; +} +``` + +### Indentation + +* Content within a namespace should be at the same indentation level as the + namespace itself. + +``` +namespace foo +{ + +content + +} +``` + +* Content within a class / struct should be indented. + +``` +class Foo +{ + public: + Foo(); +} +``` + +* Content within a function / conditional / loop should be indented. + +``` +void foo() +{ + while (1) + { + if (bar()) + { + ... + } + } +} +``` + +* Switch / case statements should be indented. + +``` +switch (foo) +{ + case bar: + { + bar(); + break; + } + + case baz: + { + baz(); + break; + } +} +``` + +* Labels should be indented so they appear at 1 level less than the current + indentation, rather than flush to the left. (This is not to say that goto + and labels are preferred or should be regularly used, but simply when they + are used, this is how they are to be used.) + +``` +void foo() +{ + if (bar) + { + do + { + if (baz) + { + goto exit; + } + + } while(1); + + exit: + cleanup(); + } +} +``` + +### Naming Conventions. + +* We generally abstain from any prefix or suffix on names. + +#### Files + +* C++ headers should end in ".hpp". C headers should end in ".h". +* C++ files should be named with lower_snake_case. + +#### Types + +* Prefer 'using' over 'typedef' for type aliases. +* Structs, classes, enums, and typed template parameters should all be in + UpperCamelCase. +* Prefer namespace scoping rather than long names with prefixes. +* A single-word type alias within a struct / class may be lowercase to match + STL conventions (`using type = T`) while a multi-word type alias should be + UpperCamelCase (`using ArrayOfT = std::array<T, N>`). +* Exception: A library API may use lower_snake_case to match conventions of the + STL or an underlying C library it is abstracting. Application APIs should + all be UpperCamelCase. +* Exception: A for-convenience template type alias of a template class may end + in `_t` to match the conventions of the STL. + +``` +template <typename T> +class foo +{ + using type = std::decay_t<T>; +}; + +template <typename T> using foo_t = foo<T>::type; +``` + +#### Variables + +* Variables should all be lowerCamelCase, including class members, with no + underscores. + +#### Functions + +* Functions should all be lowerCamelCase. +* Exception: A library API may use lower_snake-case to match conventions of + the STL or an underlying C library it is abstracting. Application APIs + should all be lowerCamelCase. + +#### Constants + +* Constants and enums should be named like variables in lowerCamelCase. + +#### Namespaces + +* Namespaces should be lower_snake_case. +* Top-level namespace should be named based on the containing repository. +* Favor a namespace called 'details' or 'internal' to indicate the equivalent + of a "private" namespace in a header file and anonymous namespaces in a C++ + file. + +### Header Guards + +Prefer '#pragma once' header guard over '#ifndef'-style. + +### Additional Whitespace + +* Follow NL.18: Use C++-style declarator layout. + +``` +foo(T& bar, const S* baz); /// Correct. +foo(T &bar, const S *baz); /// Incorrect. +``` + +* Follow NL.15: Use spaces sparingly. + +* Insert whitespace after a conditional and before parens. + +``` +if (...) +while (...) +for (...) +``` + +* Insert whitespace around binary operators for readability. + +``` +foo((a-1)/b,c-2); /// Incorrect. +foo((a - 1) / b, c - 2); /// Correct. +``` + +* Do not insert whitespace around unary operators. +``` +a = * b; /// Incorrect. +a = & b; /// Incorrect. +a = b -> c; /// Incorrect. +if (! a) /// Incorrect. +``` + +* Do not insert whitespace inside parens or between a function call and + parameters. + +``` +foo(x, y); /// Correct. +foo ( x , y ); /// Incorrect. + +do (...) +{ +} while(0); /// 'while' here is structured like a function call. +``` + +* Prefer line-breaks after operators to show continuation. +``` +if (this1 == that1 && + this2 == that2) /// Correct. + +if (this1 == that1 + && this2 == that2) /// Incorrect. +``` + +* Long lines should have continuation start at the same level as the parens or + all all items inside the parens should be at a 2-level indent. + +``` +reallyLongFunctionCall(foo, + bar, + baz); // Correct. + +reallyLongFunctionCall( + foo, + bar, + baz); // Also correct. + +reallyLongFunctionCall( + foo, bar, baz); // Similarly correct. + +reallyLongFunctionCall(foo, + bar, + baz); // Incorrect. +``` + +### Misc Guidelines. + +* Always use `size_t` or `ssize_t` for things that are sizes, counts, etc. + You need a strong rationale for using a sized type (ex. `uint8_t`) when a + size_t will do. + +* Use `uint8_t`, `int16_t`, `uint32_t`, `int64_t`, etc. for types where size + is important due to hardware interaction. Do not use them, without good + reason, when hardware interaction is not involved; prefer size_t or int + instead. + + |

