mirror of
https://fuchsia.googlesource.com/third_party/pigweed.googlesource.com/pigweed/pigweed
synced 2024-09-21 14:16:26 +00:00
ab4eb7ad68
- Update docs copyright. - Remove duplicate title in index.rst. - Update note about Python 2 compatibility, since most Pigweed code requires Python 3. Change-Id: I9c61a55c622b162317ab7fc4c5eec5fdf292bb02
522 lines
17 KiB
ReStructuredText
522 lines
17 KiB
ReStructuredText
.. _chapter-style:
|
|
|
|
.. default-domain:: cpp
|
|
|
|
.. highlight:: sh
|
|
|
|
===========================
|
|
Style Guide and Conventions
|
|
===========================
|
|
|
|
---------
|
|
C++ style
|
|
---------
|
|
|
|
The Pigweed C++ style guide is closely based on Google's external C++ Style
|
|
Guide, which is found on the web at
|
|
https://google.github.io/styleguide/cppguide.html. The Google C++ Style Guide
|
|
applies to Pigweed except as described in this document.
|
|
|
|
The Pigweed style guide only applies to Pigweed itself. It does not apply to
|
|
projects that use Pigweed or to the third party code included with Pigweed.
|
|
Non-Pigweed code is free to use features restricted by Pigweed, such as dynamic
|
|
memory allocation and the entirety of the C++ Standard Library.
|
|
|
|
Recommendations in the :doc:`embedded_cpp_guide` are considered part of the
|
|
Pigweed style guide, but are separated out since it covers more general
|
|
embedded development beyond just C++ style.
|
|
|
|
Automatic formatting
|
|
====================
|
|
Pigweed uses `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`_ to
|
|
automatically format Pigweed source code. A ``.clang-format`` configuration is
|
|
provided with the Pigweed repository.
|
|
|
|
Automatic formatting is essential to facilitate large-scale, automated changes
|
|
in Pigweed. Therefore, all code in Pigweed is expected to be formatted with
|
|
``clang-format`` prior to submission. Existing code may be reformatted at any
|
|
time.
|
|
|
|
If ``clang-format`` formats code in an undesirable or incorrect way, it can be
|
|
disabled for the affected lines by adding ``// clang-format off``.
|
|
``clang-format`` must then be re-enabled with a ``// clang-format on`` comment.
|
|
|
|
.. code-block:: cpp
|
|
|
|
// clang-format off
|
|
constexpr int kMyMatrix = {
|
|
100, 23, 0,
|
|
0, 542, 38,
|
|
1, 2, 201,
|
|
};
|
|
// clang-format on
|
|
|
|
C Standard Library
|
|
==================
|
|
In C++ headers, always use the C++ versions of C Standard Library headers (e.g.
|
|
``<cstdlib>`` instead of ``<stdlib.h>``). If the header is used by both C and
|
|
C++ code, only the C header should be used.
|
|
|
|
In C++ code, it is preferred to use C functions from the ``std`` namespace. For
|
|
example, use ``std::memcpy`` instead of ``memcpy``. The C++ standard does not
|
|
require the global namespace versions of the functions to be provided. Using
|
|
``std::`` is more consistent with the C++ Standard Library and makes it easier
|
|
to distinguish Pigweed functions from library functions.
|
|
|
|
Within core Pigweed, do not use C standard library functions that allocate
|
|
memory, such as ``std::malloc``. There are exceptions to this for when dynamic
|
|
allocation is enabled for a system; Pigweed modules are allowed to add extra
|
|
functionality when a heap is present; but this must be optional.
|
|
|
|
C++ Standard Library
|
|
====================
|
|
Much of the C++ Standard Library is not a good fit for embedded software. Many
|
|
of the classes and functions were not designed with the RAM, flash, and
|
|
performance constraints of a microcontroller in mind. For example, simply
|
|
adding the line ``#include <iostream>`` can increase the binary size by 150 KB!
|
|
This is larger than many microcontroller's entire internal storage.
|
|
|
|
However, with appropriate caution, a limited set of standard C++ libraries can
|
|
be used to great effect. Developers can leverage familiar, well-tested
|
|
abstractions instead of writing their own. C++ library algorithms and classes
|
|
can give equivalent or better performance than hand-written C code.
|
|
|
|
A limited subset of the C++ Standard Library is permitted in Pigweed. To keep
|
|
Pigweed small, flexible, and portable, functions that allocate dynamic memory
|
|
must be avoided. Care must be exercised when using multiple instantiations of a
|
|
template function, which can lead to code bloat.
|
|
|
|
The following C++ Standard Library headers are always permitted:
|
|
|
|
* ``<array>``
|
|
* ``<complex>``
|
|
* ``<initializer_list>``
|
|
* ``<iterator>``
|
|
* ``<limits>``
|
|
* ``<optional>``
|
|
* ``<random>``
|
|
* ``<ratio>``
|
|
* ``<span>``
|
|
* ``<string_view>``
|
|
* ``<tuple>``
|
|
* ``<type_traits>``
|
|
* ``<utility>``
|
|
* ``<variant>``
|
|
* C Standard Library headers (``<c*>``)
|
|
|
|
With caution, parts of the following headers can be used:
|
|
|
|
* ``<algorithm>`` -- be wary of potential memory allocation
|
|
* ``<atomic>`` -- not all MCUs natively support atomic operations
|
|
* ``<bitset>`` -- conversions to or from strings are disallowed
|
|
* ``<functional>`` -- do **not** use ``std::function``
|
|
* ``<new>`` -- for placement new
|
|
* ``<numeric>`` -- be wary of code size with multiple template instantiations
|
|
|
|
Never use any of these headers:
|
|
|
|
* Dynamic containers (``<list>``, ``<map>``, ``<set>``, ``<vector>``, etc.)
|
|
* Streams (``<iostream>``, ``<ostream>``, ``<fstream>``, etc.)
|
|
* ``<exception>``
|
|
* ``<future>``, ``<mutex>``, ``<thread>``
|
|
* ``<memory>``
|
|
* ``<regex>``
|
|
* ``<scoped_allocator>``
|
|
* ``<sstream>``
|
|
* ``<stdexcept>``
|
|
* ``<string>``
|
|
* ``<valarray>``
|
|
|
|
Headers not listed here should be carefully evaluated before they are used.
|
|
|
|
These restrictions do not apply to third party code or to projects that use
|
|
Pigweed.
|
|
|
|
Combining C and C++
|
|
===================
|
|
Prefer to write C++ code over C code, using ``extern "C"`` for symbols that must
|
|
have C linkage. ``extern "C"`` functions should be defined within C++
|
|
namespaces to simplify referring to other code.
|
|
|
|
C++ functions with no parameters do not include ``void`` in the parameter list.
|
|
C functions with no parameters must include ``void``.
|
|
|
|
.. code-block:: cpp
|
|
|
|
namespace pw {
|
|
|
|
bool ThisIsACppFunction() { return true; }
|
|
|
|
extern "C" int pw_ThisIsACFunction(void) { return -1; }
|
|
|
|
extern "C" {
|
|
|
|
int pw_ThisIsAlsoACFunction(void) {
|
|
return ThisIsACppFunction() ? 100 : 0;
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
} // namespace pw
|
|
|
|
Comments
|
|
========
|
|
Prefer C++-style (``//``) comments over C-style commments (``/* */``). C-style
|
|
comments should only be used for inline comments.
|
|
|
|
.. code-block:: cpp
|
|
|
|
// Use C++-style comments, except where C-style comments are necessary.
|
|
// This returns a random number using an algorithm I found on the internet.
|
|
#define RANDOM_NUMBER() [] { \
|
|
return 4; /* chosen by fair dice roll */ \
|
|
}()
|
|
|
|
Indent code in comments with two additional spaces, making a total of three
|
|
spaces after the ``//``. All code blocks must begin and end with an empty
|
|
commment line, even if the blank comment line is the last line in the block.
|
|
|
|
.. code-block:: cpp
|
|
|
|
// Here is an example of code in comments.
|
|
//
|
|
// int indentation_spaces = 2;
|
|
// int total_spaces = 3;
|
|
//
|
|
// engine_1.thrust = RANDOM_NUMBER() * indentation_spaces + total_spaces;
|
|
//
|
|
bool SomeFunction();
|
|
|
|
Control statements
|
|
==================
|
|
All loops and conditional statements must use braces.
|
|
|
|
The syntax ``while (true)`` if preferred over ``for (;;)`` for infinite loops.
|
|
|
|
Include guards
|
|
==============
|
|
The first non-comment line of every header file must be ``#pragma once``. Do
|
|
not use traditional macro include guards. The ``#pragma once`` should come
|
|
directly after the Pigweed copyright block, with no blank line, followed by a
|
|
blank, like this:
|
|
|
|
.. code-block:: cpp
|
|
|
|
// Copyright 2019 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
#pragma once
|
|
|
|
// Header file-level comment goes here...
|
|
|
|
Memory allocation
|
|
=================
|
|
Dynamic memory allocation can be problematic. Heap allocations and deallocations
|
|
occupy valuable CPU cycles. Memory usage becomes nondeterministic, which can
|
|
result in a system crashing without a clear culprit.
|
|
|
|
To keep Pigweed portable, core Pigweed code is not permitted to dynamically
|
|
(heap) allocate memory, such as with ``malloc`` or ``new``. All memory should be
|
|
allocated with automatic (stack) or static (global) storage duration. Pigweed
|
|
must not use C++ libraries that use dynamic allocation.
|
|
|
|
Projects that use Pigweed are free to use dynamic allocation, provided they
|
|
have selected a target that enables the heap.
|
|
|
|
Naming
|
|
======
|
|
Entities shall be named according to the `Google style guide
|
|
<https://google.github.io/styleguide/cppguide.html>`_, with the following
|
|
additional requirements.
|
|
|
|
**C++ code**
|
|
* All Pigweed C++ code must be in the ``pw`` namespace. Namespaces for
|
|
modules should be nested under ``pw``. For example,
|
|
``pw::string::Format()``.
|
|
* Whenever possible, private code should be in a source (.cc) file and placed
|
|
in anonymous namespace nested under ``pw``.
|
|
* If private code must be exposed in a header file, it must be in a namespace
|
|
nested under ``pw``. The namespace may be named for its subsystem or use a
|
|
name that designates it as private, such as ``internal``.
|
|
|
|
**C code**
|
|
* Public names used by C code must be prefixed with ``pw_``.
|
|
* If private code must be exposed in a header, private names used by C code
|
|
must be prefixed with ``_pw_``.
|
|
* Avoid writing C source (.c) files in Pigweed. Prefer to write C++ code with
|
|
C linkage using ``extern "C"``. Within C source, private C functions and
|
|
variables must be named with the ``_pw_`` prefix and should be declared
|
|
``static`` whenever possible; for example, ``_pw__MyPrivateFunction``.
|
|
* The C prefix rules apply to
|
|
|
|
* C functions (``int pw_FunctionName(void);``),
|
|
* variables used by C code (``int pw_variable_name;``),
|
|
* constant variables used by C code (``int pw_kConstantName;``), and
|
|
* structs used by C code (``typedef struct {} pw_StructName;``).
|
|
|
|
The prefix does not apply to struct members, which use normal Google style.
|
|
|
|
**Preprocessor macros**
|
|
* Public Pigweed macros must be prefixed with ``PW_``.
|
|
* Private Pigweed macros must be prefixed with ``_PW_``.
|
|
|
|
**Example**
|
|
|
|
.. code-block:: cpp
|
|
|
|
namespace pw {
|
|
namespace nested_namespace {
|
|
|
|
// C++ names (types, variables, functions) must be in the pw namespace.
|
|
// They are named according to the Google style guide.
|
|
constexpr int kGlobalConstant = 123;
|
|
|
|
// Prefer using functions over extern global variables.
|
|
extern int global_variable;
|
|
|
|
class Class {};
|
|
|
|
void Function();
|
|
|
|
extern "C" {
|
|
|
|
// Public Pigweed code used from C must be prefixed with pw_.
|
|
extern const int pw_kGlobalConstant;
|
|
|
|
extern int pw_global_variable;
|
|
|
|
void pw_Function(void);
|
|
|
|
typedef struct {
|
|
int member_variable;
|
|
} pw_Struct;
|
|
|
|
// Private Pigweed code used from C must be prefixed with _pw_.
|
|
extern const int _pw_kPrivateGlobalConstant;
|
|
|
|
extern int _pw_private_global_variable;
|
|
|
|
void _pw_PrivateFunction(void);
|
|
|
|
typedef struct {
|
|
int member_variable;
|
|
} _pw_PrivateStruct;
|
|
|
|
} // extern "C"
|
|
|
|
// Public macros must be prefixed with PW_.
|
|
#define PW_PUBLIC_MACRO(arg) arg
|
|
|
|
// Private macros must be prefixed with _PW_.
|
|
#define _PW_PRIVATE_MACRO(arg) arg
|
|
|
|
} // namespace nested_namespace
|
|
} // namespace pw
|
|
|
|
Namespace scope formatting
|
|
==========================
|
|
All non-indented blocks (namespaces, ``extern "C"`` blocks, and preprocessor
|
|
conditionals) must have a comment on their closing line with the
|
|
contents of the starting line.
|
|
|
|
All nested namespaces should be declared together with no blank lines between
|
|
them.
|
|
|
|
.. code-block:: cpp
|
|
|
|
#include "some/header.h"
|
|
|
|
namespace pw::nested {
|
|
namespace {
|
|
|
|
constexpr int kAnonConstantGoesHere = 0;
|
|
|
|
} // namespace
|
|
|
|
namespace other {
|
|
|
|
const char* SomeClass::yes = "no";
|
|
|
|
bool ThisIsAFunction() {
|
|
#if PW_CONFIG_IS_SET
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif // PW_CONFIG_IS_SET
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
const int pw_kSomeConstant = 10;
|
|
int pw_some_global_variable = 600;
|
|
|
|
void pw_CFunction() { ... }
|
|
|
|
} // extern "C"
|
|
|
|
} // namespace
|
|
} // namespace pw::nested
|
|
|
|
Pointers and references
|
|
=======================
|
|
For pointer and reference types, place the asterisk or ampersand next to the
|
|
type.
|
|
|
|
.. code-block:: cpp
|
|
|
|
int* const number = &that_thing;
|
|
constexpr const char* kString = "theory!"
|
|
|
|
bool FindTheOneRing(const Region& where_to_look) { ... }
|
|
|
|
Prefer storing references over storing pointers. Pointers are required when the
|
|
pointer can change its target or may be ``nullptr``. Otherwise, a reference or
|
|
const reference should be used. In accordance with the Google C++ style guide,
|
|
only const references are permitted as function arguments; pointers must be used
|
|
in place of mutable references when passed as function arguments.
|
|
|
|
Preprocessor macros
|
|
===================
|
|
Macros should only be used when they significantly improve upon the C++ code
|
|
they replace. Macros should make code more readable, robust, and safe, or
|
|
provide features not possible with standard C++, such as stringification, line
|
|
number capturing, or conditional compilation. When possible, use C++ constructs
|
|
like constexpr variables in place of macros. Never use macros as constants,
|
|
except when a string literal is needed or the value must be used by C code.
|
|
|
|
When macros are needed, the macros should be accompanied with extensive tests
|
|
to ensure the macros are hard to use wrong.
|
|
|
|
Stand-alone statement macros
|
|
----------------------------
|
|
Macros that are standalone statements must require the caller to terminate the
|
|
macro invacation with a semicolon. For example, the following does *not* conform
|
|
to Pigweed's macro style:
|
|
|
|
.. code-block:: cpp
|
|
|
|
// BAD! Definition has built-in semicolon.
|
|
#define PW_LOG_IF_BAD(mj) \
|
|
CallSomeFunction(mj);
|
|
|
|
// BAD! Compiles without error; semicolon is missing.
|
|
PW_LOG_IF_MAD("foo")
|
|
|
|
Here's how to do this instead:
|
|
|
|
.. code-block:: cpp
|
|
|
|
// GOOD; requires semicolon to compile.
|
|
#define PW_LOG_IF_BAD(mj) \
|
|
CallSomeFunction(mj)
|
|
|
|
// GOOD; fails to compile due to lacking semicolon.
|
|
PW_LOG_IF_MAD("foo")
|
|
|
|
For macros in function scope that do not already require a semicolon, the
|
|
contents can be placed in a ``do { ... } while (0)`` loop.
|
|
|
|
.. code-block:: cpp
|
|
|
|
#define PW_LOG_IF_BAD(mj) \
|
|
do { \
|
|
if (mj.Bad()) { \
|
|
Log(#mj " is bad") \
|
|
} \
|
|
} while (0)
|
|
|
|
Standalone macros at global scope that do not already require a semicolon can
|
|
add a ``static_assert`` or throwaway struct declaration statement as their
|
|
last line.
|
|
|
|
.. code-block:: cpp
|
|
|
|
#define PW_NEAT_THING(thing) \
|
|
bool IsNeat_##thing() { return true; } \
|
|
static_assert(true, "Macros must be terminated with a semicolon")
|
|
|
|
Private macros in public headers
|
|
--------------------------------
|
|
Private macros in public headers must be prefixed with ``_PW_``, even if they
|
|
are undefined after use; this prevents collisions with downstream users. For
|
|
example:
|
|
|
|
.. code-block:: cpp
|
|
|
|
#define _PW_MY_SPECIAL_MACRO(op) ...
|
|
...
|
|
// Code that uses _PW_MY_SPECIAL_MACRO()
|
|
...
|
|
#undef _PW_MY_SPECIAL_MACRO
|
|
|
|
Macros in private implementation files (.cc)
|
|
--------------------------------------------
|
|
Macros within .cc files that should only used within one file should be
|
|
undefined after their last use; for example:
|
|
|
|
.. code-block:: cpp
|
|
|
|
#define DEFINE_OPERATOR(op) \
|
|
T operator ## op(T x, T y) { return x op y; } \
|
|
static_assert(true, "Macros must be terminated with a semicolon") \
|
|
|
|
DEFINE_OPERATOR(+);
|
|
DEFINE_OPERATOR(-);
|
|
DEFINE_OPERATOR(/);
|
|
DEFINE_OPERATOR(*);
|
|
|
|
#undef DEFINE_OPERATOR
|
|
|
|
Preprocessor conditional statements
|
|
===================================
|
|
When using macros for conditional compilation, prefer to use ``#if`` over
|
|
``#ifdef``. This checks the value of the macro rather than whether it exists.
|
|
|
|
* ``#if`` handles undefined macros equivalently to ``#ifdef``. Undefined
|
|
macros expand to 0 in preprocessor conditional statements.
|
|
* ``#if`` evaluates false for macros defined as 0, while ``#ifdef`` evaluates
|
|
true.
|
|
* Macros defined using compiler flags have a default value of 1 in GCC and
|
|
Clang, so they work equivalently for ``#if`` and ``#ifdef``.
|
|
* Macros defined to an empty statement cause compile-time errors in ``#if``
|
|
statements, which avoids ambiguity about how the macro should be used.
|
|
|
|
All ``#endif`` statements should be commented with the expression from their
|
|
corresponding ``#if``. Do not indent within preprocessor conditional statements.
|
|
|
|
.. code-block:: cpp
|
|
|
|
#if USE_64_BIT_WORD
|
|
using Word = uint64_t;
|
|
#else
|
|
using Word = uint32_t;
|
|
#endif // USE_64_BIT_WORD
|
|
|
|
Unsigned integers
|
|
=================
|
|
Unsigned integers are permitted in Pigweed. Aim for consistency with existing
|
|
code and the C++ Standard Library. Be very careful mixing signed and unsigned
|
|
integers.
|
|
|
|
------------
|
|
Python style
|
|
------------
|
|
Pigweed uses the standard Python style: PEP8, which is available on the web at
|
|
https://www.python.org/dev/peps/pep-0008/. All Pigweed Python code should pass
|
|
``yapf`` when configured for PEP8 style.
|
|
|
|
Python 3
|
|
========
|
|
Pigweed uses Python 3. Some modules may offer limited support for Python 2, but
|
|
Python 3.6 or newer is required for most Pigweed code.
|