This document describes the design, naming, coding, and style rules and recommendations for CMS software written in C++, plus a few guidelines for Python configuration.
This document describes the CMS C++ software naming, coding, style, and documentation rules and recommendations. All CMS C++ software is expected to comply with the rules. The asterisk (*) after some rules indicates that there may be exceptional use cases where the rule may be violated with good justification. Intentional violations must be documented in the code next to the violation. Coding rules are meant to prevent serious problems in software function, performance, maintainability, usability, and portability. The Packaging Rules section also has some brief guidelines for Python configuration.
- C++ header files use the suffix .h, e.g.
CaloCluster.h
. (*) - For C++ source files, the preferred suffix is .cc, e.g.
CaloCluster.cc
. (*) - For a header file that contains a class, name that file after the class.
- Name source files after the class.
- For class, struct, type, and enumeration names use upper class initials, e.g.
GeometryBuilder
. - For namespaces use lower case, e.g.
namespace edm
. - Start method names with lowercase, use upper case initials for following words, e.g.
collisionPoint()
.
Allowed exception: Implementation of virtual methods inherited from external packages, e.g.ProcessHits()
method required by Geant4. - Start data member names with lower case. A trailing "_" is the preferred method to distinguish a data member from the getter method (e.g.
momentum_
). - Using "set" for a setter method is preferred, e.g.
setMomentum(double momentum)
. - For a getter method, using the value name is preferred, e.g.
momentum()
. - Do not use single character names, except for loop indices.
- Do not use special characters, except for "_" where allowed.
- Do not use "_" as first character, except for user-defined suffixes (used in user-defined literals). Only use it as the last character for class data member names, not local variable names.
- Do not use "__".
- Use clear and explanatory variable names.
- Do not indent pre-processor directives -- there should be no leading spaces before a directive. (*)
- Never change the language syntax using
#define
. - Do not use spaces between a function, constructor, or method name and its opening parenthesis, e.g.
energy()
rather thanenergy ()
. A similar style is encouraged but not required when brace initialization is used, e.g.energy{13}
. - Do not use spaces in front of [] or on either side of -> . For example,
position[i]
instead ofposition [i]
. - Separate expressions in a
for
statement by including a space after each semicolon. - Use the same indentation for comments as for the block the comments refer to.
- Protect each header file from multiple inclusion with:
#ifndef PackageName_SubPackageName_FileName_h
#define PackageName_SubPackageName_FileName_h
(body of header file)
#endif
If necessary to create a unique name, one can add the directory name:
PackageName_SubPackageName_Directory_FileName_h
. - Each header file contains one class declaration only. (*)
- Header files must not contain any implementation except for class templates and code to be inlined.
- Do not inline virtual functions.
- Do not inline functions which contain control structures which require block scoping.
- In your own packages, use forward declarations if they are sufficient.
- Do not forward-declare an entity from another package.
- Do not use absolute directory names or relative file paths in
#include
directives. - Use
nullptr
, not "0" or "NULL". (*) - Use types like
int
,uint32_t
,size_t
, andptrdiff_t
consistently and without mixing them. - Use the
bool
type for booleans. - Copy and move assignment operators should return a reference to
*this
. - For a class, definition of any of the following requires definition of all five: destructor, copy constructor, copy assignment operator, move constructor, and move assignment operator. (*)
- Do not use function-like macros.
- Use C++ casts, not C-style casting. (*)
- Do not use the ellipsis notation for function arguments, except for variable argument templates.
- Do not use union types. (*)
- If a class has at least one virtual method, it must have a public virtual destructor or (exceptionally) a protected non-virtual destructor.
- When a derived class function overrides a virtual function, always mark it with
override
orfinal
. - Pass by value arguments which are not to be modified and are built-in types or small objects; otherwise pass arguments of class types by reference or, if necessary, by pointer.
Allowed exception: If the function algorithm would benefit from using a move of the argument instead of a copy, pass the argument by value. - Properly use rvalue references for temporary objects that will be moved.
- The argument to a copy constructor and to an assignment operator must be a
const
reference, while the argument for a move constructor or move assignment operator must be an rvalue reference. (*) - Do not let
const
member functions change the state of the object. Any special exceptions to this rule must still maintain thread safety. (*) - A function must never return or in any way give access to references or pointers to local variables (stack variables) outside the scope in which they are declared, and a
const
member function must not give non-const
access to any data directly or indirectly held by the object. - Each class may have only one each of public, protected, and private sections, which must be declared in that order. (*)
- Keep the ordering of methods in the header file and in the source file identical.
- Provide meaningful argument names in method declarations in the header file to indicate usage, unless the type fully describes the usage.
- Try to avoid excessively long lines of code that impair readability.
- Data members of a class must not be redefined in derived classes since doing so hides the original data member and could create confusion between the original and redefined data members.
- Always comment complex, tricky, or non-intuitive portions of code.
- When revising code, be sure to update and revise comments.
- It is discouraged to have small packages (with couple of cc and header files).
- Functionality used by multiple packages should go in the
.../src
and.../interface
directories. - Only header files that expose a public interface should go into the
.../interface
directory. - Include only files that are in the current directory, e.g.
#include "some_header.h"
or in the.../interface
directory, e.g
#include "Subsystem/Package/interface/some_header.h"
- Group code files into packages based upon their matching dependencies. Such dependencies can be on other CMSSW packages or, more importantly, external libraries.
- Put plugins (e.g. EDProducers, EDAnalyzers, etc.) into a
Package/Subpackage/plugins/
directory, with its dedicatedBuildFile.xml
. - Do not split plugins into header and source files. If you do split them, keep the header files in the
.../plugins
directory. - All code used only by the plugins in
../plugins
should also go under.../plugins
.plugins.cc
andSealPlugins.cc
or any special files that just define plugins, except for template instantiations, are discouraged.
- Unit tests to test the functionalities of your Library and/or Plugins should go under
.../test
. - Add test library/plugins in
.../test/BuildFile.xml
for the common functionality used only by your unit tests. - For unit tests which simply run
cmsRun your-cfg
(to test your plugin), please use<test name="..." command="cmsRun …"/>
in your.../test/BuildFile.xml
. - Unit tests should return a non-zero value from their main to indicate test failure. Successful tests should print nothing or a very small amount to the log file. Tests should not require a human to read their output to determine if they succeed or fail.
- A
_cfi
file should contain only the definition of one module, and possible Modifier ("era") customizations on it. The module label should be the same as the_cfi
file name. - The
_cfi
file should be left to be generated automatically with thefillDescriptions()
. When Modifier customizations are needed, the auto-generated label should have e.g. "Default" postfix and be imported+cloned to the desired name. - A module/Task/Sequence/Path with a given name should be defined in exactly one
_cfi
or_cff
file. - All Modifier customizations on a module/Task/Sequence/Path should be applied on the same file that defines the module/Task/Sequence/Path.
- When one customizes an existing parameter in
clone()
,Modifier.toModify()
, or in assignment, explicit types on the right hand side should be avoided.
- To keep the repository size under control, we discourage adding any data files under
.../data
. - Please use the cms-data externals GitHub repositories to add/change any data file.
- Public executables/binaries should go under
.../bin
. - It is discouraged to generate plugins from
.../bin
. - Additional libraries used only by multiple executables of your
.../bin
should also go under.../bin
. - Any utilities which should be available publicly (i.e. in the PATH) should go under
.../bin
and use theINSTALL_SCRIPTS
flag in.../bin/BuildFile.xml
. - The
.../scripts
directory is reserved for scripts that need to be available in the PATH. Configuration and data files should go into appropriate directories, like.../data
.
These guidelines are a brief summary of highlights from the C++ Core Guidelines by Bjarne Stroustrup et al. The links for each guideline provide explanations and justifications.
- Do not use mutable global data (no globals).
- Ensure code is thread-safe. Avoid non-constant shared data, like static variables (thread safety).
- Class data members that store a class invariant should be private (invariant data members).
- A collection of data values that can take any value should be a struct, not a class, and those data members should be public without getters and setters. (struct not class).
- Make
const
all methods, data members, variables, and pointer or reference parameters that do not need to be non-const. Useconstexpr
for all constant values that can be evaluated at compile time (const). - Do not use magic numbers. Define constants using
enum class
orconstexpr
, never#define
(enums). - For ownership of dynamic memory, don’t use bare pointers but rather smart pointers:
std::unique_ptr, std::shared_ptr
, andstd::weak_ptr
and their constructorsstd::make_unique<T>()
andstd::make_shared<T>()
(smart pointers). - Avoid inlining unless you are sure you have a relevant performance problem (inlining).
- Use
string
orstring_view
, notchar *
(string). - Avoid use of C-style arrays in favor of STL containers (std::array).
- In general, do not catch exceptions -- leave them to the Framework (see Exception Guidelines).
- Do not use the singleton pattern; use framework services (no singletons).
- Encapsulate algorithms and collaborating classes in namespaces (namespaces).
- Design functions that are short and simple and that perform a single, coherent, logical task (logical task, short functions).
- Do not duplicate code. If procedural code is needed in two or more places, create a function for the task and call it where needed. (functions, encapsulate)
- Do not use goto (no goto).