Skip to content

Commit

Permalink
docs(cpp): Add partial set of C++ contribution guidelines. (#26)
Browse files Browse the repository at this point in the history
Co-authored-by: LinZhihao-723 <[email protected]>
  • Loading branch information
kirkrodrigues and LinZhihao-723 authored Jan 8, 2025
1 parent 4b1d950 commit b1c48a5
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
160 changes: 160 additions & 0 deletions docs/dev-guide/contrib-guides-cpp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# C++

Follow the guidelines below when writing and updating C++ files.

## Automated linting

As mentioned in the overview, where possible, we have automated linting processes, so you need not
remember all the guidelines perfectly. For C++, we currently use the following tools:

* `clang-format` for formatting ([base config][clang-format-config])
* `clang-tidy` for static analysis ([base config][clang-tidy-config])

When the linter disagrees with a guideline, err on the side of following the linter, since:

* we don't want automated runs of the linters to fail, leading to them being ignored due to the
noise.
* the linter may have a good reason for disagreeing with the guideline.
* the linter's configuration may be more up-to-date than the guideline.

:::{tip}
To learn about how to apply the linters to a new C++ project, [see here][adding-cpp-linting].
:::

When you encounter such a disagreement, if it hasn't been noted below, please open an [issue] to
track it.

## Guidelines

We adhere to [Google's C++ style guide][google-cpp-style-guide] (as of
[8f97e24][google-styleguide-8f97e24]) with the following exceptions (organized according to the
sections in Google's style guide).

:::{note}
This section is a work in progress and does not yet include all exceptions after the
[Classes][google-cpp-style-guide-classes] section of Google's style guide.
:::

### Header files

#### Self-contained Headers

* Header files should end in `.hpp`.
* Don't use non-header files meant for inclusion (e.g., `.impl`/`.inc`/`.tpp` files included at the
end of the `.hpp` file), since they can confuse static analysis tools.

#### The #define Guard

The symbol name should have the form

```txt
<NAMESPACE>_<FILENAME-STEM>_<FILENAME-EXTENSION>
```

where

* `<NAMESPACE>` is the namespace of the file.
* For files in a nested namespace, each namespace layer should be separated by an underscore.
* `<FILENAME_STEM>` is the file's name without the extension.
* For stems with multiple words, the words should _not_ be separated with underscores.
* `<FILENAME_EXTENSION>` is the file's extension.

For example:

`clp/streaming_archive/reader/SegmentManager.hpp`

```c++
#ifndef CLP_STREAMING_ARCHIVE_READER_SEGMENTMANAGER_HPP
#define CLP_STREAMING_ARCHIVE_READER_SEGMENTMANAGER_HPP

namespace clp::streaming_archive::reader {
// ...
}

#endif // CLP_STREAMING_ARCHIVE_READER_SEGMENTMANAGER_HPP
```

#### Names and order of includes

* For codebases where the code is not organized into well-defined libraries, it is fine to use UNIX
directory aliases to include headers.
* For C headers that have C++ counterparts (e.g., `stddef.h` vs `cstddef`), use the C++ counterpart.

### Scoping

#### Namespaces

Single-line nested namespace declarations (e.g. `bar` in `foo`) should use the following format
(unless doing so would affect clarity):

```cpp
namespace foo::bar {
}
```
#### Internal linkage
Only use unnamed namespaces (instead of the `static` qualifier) to give functions and variables
internal linkage. However, as Google's style guide indicates, you can't use unnamed namespaces in
header files. For symbols that should only be used within a header file, you can create a named
namespace in the header file, where its name is of the form:
```txt
<FilenameStem>_internal
```

where

* `<FilenameStem_stem>` is the file's name without the extension.
* `_internal` is a fixed suffix indicating the namespace's purpose.

For example:

`clp/streaming_archive/reader/SegmentManager.hpp`

```c++
namespace clp::streaming_archive::reader {
namespace SegmentManager_internal {
// Internal symbols
}
}
```
### Classes
#### Doing work in constructors
We allow (but discourage) the use of exceptions, even in constructors. If creating an object can
fail, you're encouraged to use a factory function that performs the work that can fail, and then
returns a result containing an error code if unsuccessful or the object if successful.
#### Declaration order
Within each section, order declarations as follows:
1. Types and type aliases (`typedef`, `using`, `enum`, nested structs and classes, and `friend`
types).
2. Static constants.
3. Static functions:
* Factory functions.
* Other functions.
4. Static variables.
5. Constructors.
6. Copy & move constructors and assignment operators.
7. The destructor.
8. Methods (member functions):
* Overridden methods.
* Implemented abstract methods.
* All other methods.
9. Data members.
The differences between our declaration order and the order in Google's style guide is to conform
with our general [ordering guidelines](./contrib-guides-general.md#declaration-order).
[adding-cpp-linting]: https://github.com/y-scope/yscope-dev-utils/blob/main/docs/lint-tools-cpp.md
[clang-format-config]: https://github.com/y-scope/yscope-dev-utils/blob/main/lint-configs/.clang-format
[clang-tidy-config]: https://github.com/y-scope/yscope-dev-utils/blob/main/lint-configs/.clang-tidy
[google-cpp-style-guide]: https://google.github.io/styleguide/cppguide.html
[google-cpp-style-guide-classes]: https://google.github.io/styleguide/cppguide.html#Classes
[google-styleguide-8f97e24]: https://github.com/google/styleguide/tree/8f97e24da04753c7a15eda6b02114a01ec3146f5
[issue]: https://github.com/y-scope/yscope-docs/issues/new
18 changes: 18 additions & 0 deletions docs/dev-guide/contrib-guides-general.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# General guidelines

Follow the guidelines below when writing and updating any source files.

## Code organization

(declaration-order)=
### Declaration order

Organize declarations in order of:

* Visibility, from public to private; then
* Lifetime, from static to dynamic; then
* Alphabetically (unless a different ordering is required for functionality or enhanced clarity).

This is so readers who read from top to bottom should understand the high-level interfaces
(public/static) before the low-level implementation details (private/dynamic). Alphabetical ordering
is to make symbols easy to find.
10 changes: 10 additions & 0 deletions docs/dev-guide/contrib-guides-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ This section is a work in progress while we open-source all our guidelines.
::::{grid} 1 1 2 2
:gutter: 2

:::{grid-item-card}
:link: contrib-guides-general
General guidelines
:::

:::{grid-item-card}
:link: contrib-guides-cpp
C++
:::

:::{grid-item-card}
:link: contrib-guides-taskfiles
Taskfiles
Expand Down
2 changes: 2 additions & 0 deletions docs/dev-guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ This section contains docs describing our development practices and the like.
:maxdepth: 1

contrib-guides-overview
contrib-guides-general
contrib-guides-cpp
contrib-guides-taskfiles
:::

Expand Down

0 comments on commit b1c48a5

Please sign in to comment.