1# C++ Coding Style and Conventions 2 3## General Philosophy 4 5Being an extensive and complicated language, there are often differences of 6opinions on "good" and "bad" C++ code. Bjarne Stroustrup has said "Within C++ 7is a smaller, simpler, safer language struggling to get out." We are striving 8to write in this variant of C++ and are therefore following the "C++ Core 9Guidelines" that Bjarne and Herb Sutter introduced at CppCon 2015. 10 11Beyond a set of rules that help codify "good" and "bad" C++, we have general 12principles that help us align the software we develop with the constraints 13within the problem domain being solved by OpenBMC. These are: 14 1. Code should be clear and concise. 15 2. Code should be written with modern practices. 16 3. Code should be performant. 17 18### Code should be clear and concise 19 20> Brevity is the soul of wit. 21 22It is important that code be optimized for the reviewer and maintainer and not 23for the writer. Solutions should avoid tricks that detract from the clarity 24of reviewing and understanding it. 25 26Modern practices allow C++ to be an expressive, but concise, language. We tend 27to favor solutions which succinctly represent the problem in as few lines as 28possible. 29 30When there is a conflict between clarity and conciseness, clarity should win 31out. 32 33### Code should be written with modern practices 34 35We strive to keep our code conforming to and utilizing of the latest in C++ 36standards. Today, that means all C++ code should be compiled using C++20 37compiler settings. As the C++23 standard is finalized and compilers support 38it, we will move to it as well. 39 40We also strive to keep the codebase up-to-date with the latest recommended 41practices by the language designers. This is reflected by the choice in 42following the C++ Core Guidelines. 43 44[[Not currently implemented]] We finally desire to have computers do our 45thinking for us wherever possible. This means having Continuous Integration 46tests on each repository so that regressions are quickly identified prior to 47merge. It also means having as much of this document enforced by tools as 48possible by, for example, clang-format and clang-tidy. 49 50For those coming to the project from pre-C++11 environments we strongly 51recommend the book "Effective Modern C++" as a way to get up to speed on the 52differences between C++98/03 and C++11/14/17/20. 53 54### Code should be performant. 55 56OpenBMC targets embedded processors that typically have 32-64MB of flash and 57similar processing power of a typical smart-watch available in 2016. This 58means that there are times where we must limit library selection and/or coding 59techniques to compensate for this constraint. Due to the current technology, 60performance evaluation is done in order of { code size, cpu utilization, and 61memory size }. 62 63From a macro-optimization perspective, we expect all solutions to have an 64appropriate algorithmic complexity for the problem at hand. Therefore, an 65`O(n^3)` algorithm may be rejected even though it has good clarity when an 66`O(n*lg(n))` solution exists. 67 68## Global Guidelines and Practices 69 70Please follow the guidelines established by the C++ Core Guidelines (CCG). 71 72https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md 73 74[[ Last reviewed revision is 53bc78f ]] 75 76Exceptions: 77 78### Guideline Support Library (GSL) 79 80We do not currently utilize the Guideline Support Library provided by the CCG. 81Any recommendation within the CCG of GSL conventions may be ignored at this 82time. 83 84### Style recommendations 85 86The following are not followed: 87 * NL.10 Avoid CamelCase 88 * NL.17 Use K&R-derived layout 89 90## Library and Feature Specifics 91 92Additional recommendations within the OpenBMC project on specific language 93features or libraries. 94 95### Exceptions 96 97We do use exceptions as a basis for error handling within OpenBMC. 98 99### Boost 100 101Use of boost is allowed, under the following circumstances: 1021. Use is done as a header-only library. This allows unused functions and 103 methods to be removed by the compiler at link time, and avoids adding large 104amounts of overhead and flash usage. 1052. Implementers should include the lowest level header required to solve the 106 problem at hand. This allows uses to be found and moved forward when new 107standards are available, as well as reduce compile times, and decrease the 108possibility of accidental use. (ie, #include <boost/container/flat_map.hpp> 109not #include <boost/container.hpp>) 1103. The module used should not have an equivalent in the std namespace that meets 111 the same requirements for implementation or clarity: For example, 112std::chrono should be preferred over boost::chrono. std::array over 113boost::array. 1144. Use does not conflict with any of the core tenants of this coding standard 115 (clarity, modern practices, or performance). 116 117### iostream 118 119The iostream conventions of using 'operator<<' contribute to an increased code 120size over printf-style operations, due to individual function calls for each 121appended value. We therefore do not use iostreams, or iostream-style APIs, 122for logging. 123 124There are cases when using an iostream utility (such as sstream) can result in 125clearer and similar-sized code. iostream may be used in those situations. 126 127## Coding Style 128 129Indentation, naming practices, etc. 130 131### General 132 133* Line length should be limited to 80 characters. 134* Indentation should be done with 4 space characters. 135 136### Clang Formatting 137 138Individual OpenBMC repositories can use [clang-format](https://clang.llvm.org/docs/ClangFormat.html) 139if desired. The OpenBMC CI infrastructure will automatically verify the 140code formatting on code check-in if a .clang_format file is found 141within the root directory of the repository. This allows for automatic 142validation of code formatting upon check-in. 143 144If a custom configuration is desired, such as using different clang formatting 145for C and C++ files, a format-code.sh script can be created, which can for 146example use different .clang* files as input depending on the file type. 147The format-code.sh script will be executed as part of CI if found in the root 148directory of the repository, and will check that there are no files that were 149modified after running it (same check as running clang). 150 151OpenBMC requires a clang-format of version 6.0 or greater. An example of 152how to run clang-format against all code in your repo can be found by 153referencing the [tool](https://github.com/openbmc/openbmc-build-scripts/blob/master/scripts/format-code.sh) used by CI. 154 155[Example .clang-format](https://www.github.com/openbmc/docs/blob/master/style/cpp/.clang-format) 156 157### Bracket style 158 159* Utilize 'Allman' style brackets. Brackets are on their own line at the same 160 indentation level as the statement that creates the scope. 161 162``` 163if (condition) 164{ 165 ... 166} 167``` 168 169``` 170void foo() 171{ 172 ... 173} 174``` 175 176* Even one line conditional and loop statements should have brackets. 177 178``` 179/// Wrong. 180if (condition) 181 do_something; 182 183/// Correct 184if (condition) 185{ 186 do_something; 187} 188``` 189 190### Indentation 191 192* Content within a namespace should be at the same indentation level as the 193 namespace itself. 194 195``` 196namespace foo 197{ 198 199content 200 201} 202``` 203 204* Content within a class / struct should be indented. 205 206``` 207class Foo 208{ 209 public: 210 Foo(); 211} 212``` 213 214* Content within a function / conditional / loop should be indented. 215 216``` 217void foo() 218{ 219 while (1) 220 { 221 if (bar()) 222 { 223 ... 224 } 225 } 226} 227``` 228 229* Switch / case statements should be indented. 230 231``` 232switch (foo) 233{ 234 case bar: 235 { 236 bar(); 237 break; 238 } 239 240 case baz: 241 { 242 baz(); 243 break; 244 } 245} 246``` 247 248* Labels should be indented so they appear at 1 level less than the current 249 indentation, rather than flush to the left. (This is not to say that goto 250 and labels are preferred or should be regularly used, but simply when they 251 are used, this is how they are to be used.) 252 253``` 254void foo() 255{ 256 if (bar) 257 { 258 do 259 { 260 if (baz) 261 { 262 goto exit; 263 } 264 265 } while(1); 266 267 exit: 268 cleanup(); 269 } 270} 271``` 272 273### Naming Conventions. 274 275* We generally abstain from any prefix or suffix on names. 276* Acronyms should be same-case throughout and follow the requirements as 277 in their appropriate section. 278 279``` 280/// Correct. 281SomeBMCType someBMCVariable = bmcFunction(); 282 283/// Wrong: type and variable are mixed-case, function isn't lowerCamelCase. 284SomeBmcType someBmcVariable = BMCFunction(); 285``` 286 287### Header Ordering 288 289Header inclusion order for a header file: 290``` 291local headers (e.g. "daemon_sys.hpp") 292c-libraries 293cpp-libraries (including openbmc libraries) 294``` 295 296Header inclusion order for a source file: 297``` 298source.hpp (if applicable) 299local headers 300c-libraries 301cpp-libraries 302``` 303 304All in alphabetically sorted order. 305 306#### Files 307 308* C++ headers should end in ".hpp". C headers should end in ".h". 309* C++ files should be named with lower_snake_case. 310 311#### Types 312 313* Prefer 'using' over 'typedef' for type aliases. 314* Structs, classes, enums, and typed template parameters should all be in 315 UpperCamelCase. 316* Prefer namespace scoping rather than long names with prefixes. 317* A single-word type alias within a struct / class may be lowercase to match 318 STL conventions (`using type = T`) while a multi-word type alias should be 319 UpperCamelCase (`using ArrayOfT = std::array<T, N>`). 320* Exception: A library API may use lower_snake_case to match conventions of the 321 STL or an underlying C library it is abstracting. Application APIs should 322 all be UpperCamelCase. 323* Exception: A for-convenience template type alias of a template class may end 324 in `_t` to match the conventions of the STL. 325 326``` 327template <typename T> 328class Foo 329{ 330 using type = std::decay_t<T>; 331}; 332 333template <typename T> using foo_t = Foo<T>::type; 334``` 335 336#### Variables 337 338* Variables should all be lowerCamelCase, including class members, with no 339 underscores. 340 341#### Functions 342 343* Functions should all be lowerCamelCase. 344* Exception: A library API may use lower_snake-case to match conventions of 345 the STL or an underlying C library it is abstracting. Application APIs 346 should all be lowerCamelCase. 347 348#### Constants 349 350* Constants and enum members should be named like variables in lowerCamelCase. 351 352#### Namespaces 353 354* Namespaces should be lower_snake_case. 355* Top-level namespace should be named based on the containing repository. 356* Favor a namespace called 'details' or 'internal' to indicate the equivalent 357 of a "private" namespace in a header file and anonymous namespaces in a C++ 358 file. 359 360### Header Guards 361 362Prefer '#pragma once' header guard over '#ifndef'-style. 363 364### Additional Whitespace 365 366* Follow NL.18: Use C++-style declarator layout. 367 368``` 369foo(T& bar, const S* baz); /// Correct. 370foo(T &bar, const S *baz); /// Incorrect. 371``` 372 373* Follow NL.15: Use spaces sparingly. 374 375* Insert whitespace after a conditional and before parens. 376 377``` 378if (...) 379while (...) 380for (...) 381``` 382 383* Insert whitespace around binary operators for readability. 384 385``` 386foo((a-1)/b,c-2); /// Incorrect. 387foo((a - 1) / b, c - 2); /// Correct. 388``` 389 390* Do not insert whitespace around unary operators. 391``` 392a = * b; /// Incorrect. 393a = & b; /// Incorrect. 394a = b -> c; /// Incorrect. 395if (! a) /// Incorrect. 396``` 397 398* Do not insert whitespace inside parens or between a function call and 399 parameters. 400 401``` 402foo(x, y); /// Correct. 403foo ( x , y ); /// Incorrect. 404 405do (...) 406{ 407} while(0); /// 'while' here is structured like a function call. 408``` 409 410* Prefer line-breaks after operators to show continuation. 411``` 412if (this1 == that1 && 413 this2 == that2) /// Correct. 414 415if (this1 == that1 416 && this2 == that2) /// Incorrect. 417``` 418 419* Long lines should have continuation start at the same level as the parens or 420 all all items inside the parens should be at a 2-level indent. 421 422``` 423reallyLongFunctionCall(foo, 424 bar, 425 baz); // Correct. 426 427reallyLongFunctionCall( 428 foo, 429 bar, 430 baz); // Also correct. 431 432reallyLongFunctionCall( 433 foo, bar, baz); // Similarly correct. 434 435reallyLongFunctionCall(foo, 436 bar, 437 baz); // Incorrect. 438``` 439 440### Misc Guidelines. 441 442* Always use `size_t` or `ssize_t` for things that are sizes, counts, etc. 443 You need a strong rationale for using a sized type (ex. `uint8_t`) when a 444 size_t will do. 445 446* Use `uint8_t`, `int16_t`, `uint32_t`, `int64_t`, etc. for types where size 447 is important due to hardware interaction. Do not use them, without good 448 reason, when hardware interaction is not involved; prefer size_t or int 449 instead. 450 451 452