blob: f14aa33ef2ad19dee47b56c9f0c8aac6156fb968 [file] [log] [blame] [view]
# Starboard C and C++ Style Guide
A description of the coding conventions for Starboard code and API headers.
**Status:** REVIEWED\
**Created:** 2016-11-08
Starboard generally tries to follow the coding conventions of Cobalt, which
itself mostly follows the conventions of Chromium, which mostly follows the
externally-published Google C++ coding conventions. But, Starboard has some
special requirements due to its unusual constraints, so it must add a few new
conventions and loosen some of the existing style prescriptions.
## Background
Before looking at this document, bear in mind that it is not intending to
completely describe all conventions that apply to Starboard. You probably want
to take some time to familiarize yourself with these documents first, probably
in this order:
* [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
* [Chromium C++ Style Guide](https://chromium.googlesource.com/chromium/src/+/master/styleguide/c++/c++.md)
* [Cobalt Style Guide](http://cobalt.foo/broken)
The main additional constraints that Starboard has to deal with are:
* The Starboard API is defined in straight-C. It must be able to interface
with all possible third-party components, many of which are in C and not
C++.
* Starboard is a public API. Starboard platform implementations and
applications written on top of Starboard will change independently. This
means there are intense requirements for API stability, usage
predictability, searchability, and documentation.
* Note that even though it is presented as a "style guide," the conventions
presented here are required to be approved for check-in unless otherwise
noted.
## Definitions
### snake-case
Words separated with underscores.
lower_snake_case
ALL_CAPS_SNAKE_CASE
### camel-case
Words separated by letter capitalization.
camelCase
CapitalizedCamelCase
## C++ Guidelines
What follows are hereby the guidelines for Starboard C and C++ code. Heretofore
the guidelines follow thusly as follows.
### API Definitions
* Starboard API definitions must always be compatible with straight-C99 compilers.
* All public API declarations must be specified in headers in
`src/starboard/*.h`, not in any subdirectories.
* Non-public declarations must NOT be specified in headers in
`src/starboard/*.h`.
* C++ inline helper definitions may be included inside an `#if
defined(__cplusplus)` preprocessor block. They must only provide
convenience, and must NOT be required for any API functionality.
* All public API functions should be exported symbols with the SB_EXPORT
attribute.
* No non-const variables shall be exposed as part of the public API.
* All APIs should be implemented in C++ source files, not straight-C source files.
### Modules
* Each module header must be contained with a single header file.
* The name of the module must be the singular form of the noun being
interfaced with by the module, without any "sb" or "starboard".
* `file.h`
* `directory.h`
* `window.h`
* Module interfaces should not have circular dependencies.
### File Names
* Like in the other conventions (e.g. Google, Chromium), file names must be in
`lower_snake_case`.
* File names must not contain `sb_` or `starboard_`.
* The name of a module header file must be the `lower_snake_case` form of the
module name.
* `SbConditionVariable` `starboard/condition_variable.h`
* A header that is intended to be an internal implementation detail of one or
more platform implementations should have the suffix `_internal.h`, and
include the header `starboard/shared/internal_only.h`.
* See "Implementations" for conventions about where to place implementation files.
### Types
* Like in the other conventions, types should be `CapitalizedCamelCase`.
* Every public Starboard type must start with `Sb`. There are no namespaces in
C, so `Sb` is the Starboard namespace.
* Every public Starboard type must be declared by a module, and must have the
name of the module following the `Sb`.
* `file.h` contains `SbFile`, `SbFileInfo`, `SbFileWhence`, etc...
* Every seemingly-allocatable, platform-specific Starboard type should be
defined as an opaque handle to a publically undefined struct with the
`Private` suffix. Follow this pattern for all such type declarations.
* `struct SbFilePrivate` is declared, but not defined in the public header.
* `SbFilePrivate` is `typedef`'d to `struct SbFilePrivate`. This is a C
thing where types are defined as names with the "`struct`" keyword
prepended unless `typedef`'d.
* `SbFile` is defined as a `typedef` of `struct SbFilePrivate*`.
* C structs may be defined internally to have functions and visibility. It is
allowed for such structs to have constructors, destructors, methods,
members, and public members.
* It is also considered idiomatic to never define the private struct but to
just treat it like a handle into some other method of object tracking,
casting the handle back and forth to the pointer type.
* If a word in the name of a type is redundant with the module name, it is
omitted.
* A monotonic time type in the Time module is `SbTimeMonotonic`, not
~~`SbMonotonicTime`, `SbTimeMonotonicTime`, or
`SbTimeMonotonicSbTime`~~.
### Functions
* Like in the other conventions, functions should be `CapitalizedCamelCase`.
* Every public Starboard function must start with `Sb`. There are no namespaces
in C, so `Sb` is the Starboard namespace.
* Every public Starboard function must be declared by a module, and must have
the name of the module following the `Sb`.
* `system.h` contains `SbSystemGetPath()`
* `file.h` contains `SbFileOpen()`
* After the Starboard and Module prefix, functions should start with an
imperative verb indicating what the function does.
* The Thread module defines `SbThreadCreateLocalKey()` to create a key for
thread local storage.
* If a word in the name of a function is redundant with the module name, it is
omitted.
* The `File` module as the function `SbFileOpen`, not ~~`SbOpenFile`,
`SbFileOpenFile` or `SbFileOpenSbFile`~~.
* If this gets awkward, it may indicate a need to split into a different
module.
### Variables, Parameters, Fields
* Like in the other conventions, variable, function parameter, and field names
must be in `lower_snake_case`.
* Private member fields end in an underscore.
* Public member fields do not end in an underscore.
### Namespaces
Most Starboard API headers are straight-C compatible, so cannot live inside a
namespace. Implementations, since they implement straight-C interface functions,
also cannot live inside a namespace.
But, in all other cases, Starboard C++ code should follow the inherited
conventions and use a namespace for each directory starting with a "starboard"
namespace at the starboard repository root.
### Preprocessor Macros
* Like in the other conventions, variable, function parameter, and field names
must be in `ALL_CAPS_SNAKE_CASE`.
* Macros may be used as compile-time constants because straight-C does not
have a proper facility for typed constants. This is as opposed to macros
used primarily at preprocessor-time to filter or modify what gets sent to
the compiler. Macros used as compile-time constants and that are not
configuration parameters should be explicitly-typed with a c-style cast, and
should follow the Constants naming conventions.
* Macros must start with `SB_`, and then must further be namespaced with the
module name, with the exception of configuration definitions.
* Configuration definitions should be namespaced with the module name that
they primarily affect, if applicable, or a scope that generally indicates
its domain.
* `SB_FILE_MAX_NAME`
* `SB_MEMORY_PAGE_SIZE`
* Always use `#if defined(MACRO)` over `#ifdef MACRO`.
### Constants
* Constants (including enum entries) are named using the Google constant
naming convention, `CapitalizedCamelCase`d, but starting with a lower-case
`k`.
* After the `k`, all constants have `Sb`, the Starboard namespace.
* `kSb`
* After `kSb`, all constants then have the module name.
* `kSbTime`
* `kSbFile`
* After `kSb<module>` comes the rest of the name of the constant.
* `kSbTimeMillisecond`
* `kSbFileInvalid`
* Enum entries are prefixed with the full name of the enum.
* The enum `SbSystemDeviceType` contains entries like
`kSbSystemDeviceTypeBlueRayDiskPlayer`.
### Comments
* All files must have a license and copyright comment.
* It is expected that the straight-C compiler supports C99 single-line
comments. Block comments should be avoided whenever possible, even in
license and copyright headers.
* Each public API module file should have a Module Overview documentation
comment below the license explaining what the module is for, and how to use
it effectively.
* The Module Overview must be separated by a completely blank line from the
license comment.
* The first line of the Module Overview documentation comment must say
"`Module Overview: Starboard <module-name> module`", followed by a blank
comment line (i.e. a line that contains a `//`, but nothing else).
* The first sentence of a documentation comment describing any entity (module,
type, function, variable, etc...) should assume "This module," "This type,"
"This function," or "This variable" at the beginning of the sentence, and
not include it.
* The first sentence of a documentation comment describing any entity should
be a single-sentence summary description of the entire entity.
* The first paragraph of a documentation comment should describe the overall
behavior of the entity.
* Paragraphs in comments should be separated by a blank comment line.
* All public entities must have documentation comments, including enum
entries.
* Documentation comments should be formatted with Markdown.
* Variables, constants, literals, and expressions should be referenced in
comments with pipes around them.
* All comments must be full grammatically-correct English sentences with
proper punctuation.
* Comments in Starboard headers must be written as requirements for the
porter, for example: "must not return NULL" or "should not return
NULL" rather than "will not return NULL". The choice of "must" vs "should"
must follow the guidelines of IETF RFC,
https://www.ietf.org/rfc/rfc2119.txt .
### Implementations
* Each API implementation should attempt to minimize other platform
assumptions, and should therefore use Starboard APIs to accomplish
platform-specific work unless directly related to the platform functionality
being implemented.
* For example, `SbFile` can use POSIX file I/O, because that what it is
abstracting, but it should use `SbMemoryAllocate` for any memory
allocations, because it might be used with a variety of `SbMemory`
implementations.
* Whenever possible, each shared function implementation should be implemented
in an individual file so as to maximize the chances of reuse between
implementations.
* This does not apply to platform-specific functions that have no chance of
being reusable on other platforms.
* Implementation files that can conceivably be shared between one or more
implementations should be placed in a `starboard/shared/<dependency>/`
directory, where `<dependency>` is the primary platform dependency of that
implementation. (e.g. `libevent`, `posix`, `c++11`, etc.)
* Implementation files that don't have a specific platform dependency, but
whether to use them should be a platform decision should be placed in
`starboard/shared/starboard/`, and must only have dependencies on other
Starboard APIs.
* Implementation files that definitely can be common to ALL implementations
should be placed in `starboard/common/`.
### Language Features
* In public headers, particularly in inline functions and macros, only C-Style
casts may be used, though they are forbidden everywhere else.
* It is expected that the C compiler supports inline functions. They must be
declared `static`, and they must use the `SB_C_INLINE` or
`SB_C_FORCE_INLINE` attribute. In straight-C code, there is no anonymous
namespace, so `static` is allowed and required for inline functions.
* No straight-C ISO or POSIX headers should be assumed to exist. Basic C++03
headers may be assumed to exist in C++ code. The ISO C standards have grown
up over a long period of time and have historically been implemented with
quirks, missing pieces, and so on. Support for the core C++ standard library
is much more consistent on those platforms that do support it.
* It is idiomatic to include thin C++ inline wrappers inside public API
headers, gated by an `#if defined(cplusplus__)` check.