Programming Style Guide
Consistency is the most important. Following the existing style, formatting, and naming conventions of the file you are modifying and of the overall ILLIXR project. Failure to do so will result in a prolonged review process that has to focus on updating the superficial aspects of your code, rather than improving its functionality and performance. Below are some general guidelines to follow. We also use a pre-commit bot that runs after pushes to GitHub. It enforces some general formatting rules, so don't be surprised if you see minor updates to your code. In general ILLIXR uses the Google C++ Style Guide with a few minor changes.
Directory Structure
Here is the basic directory structure used by ILLIXR (some files/directories have been omitted for brevity)
├── cmake
│ ├── ConfigurationSummary.cmake # functions to generate a summary after a cmake configuration run
│ ├── *.patch # patch files for any 3rd party code
│ ├── do_patch.sh # script for applying the patches
│ ├── Find*.cmake # cmake files for locating packages that do not have one installed by a repo
│ ├── Get*.cmake # cmake files used to build 3rd party packages
│ └── HelperFunctions.cmake # general helper functions
├── CMakeLists.txt # main cmake file for ILLIXR, edit with caution
├── CONTRIBUTORS # list of contributors to ILLIXR
├── docs
│ ├── docs
│ │ ├── contributing
│ │ │ └── *.md # markdown files containing documentation on how to contribute to ILLIXR
│ │ ├── css
│ │ │ └── *.css # css files used in the generated HTML documentation
│ │ ├── images
│ │ │ ├── *.png # images used in the generated documentation
│ │ │ └── *.svg
│ │ ├── js
│ │ │ └── *.js # javascript files used in the generated HTML documentation
│ │ ├── plugin_README
│ │ │ └── *.md # readme files for individual plugins
│ │ ├── policies
│ │ │ └── *.md # general policy documents
│ │ ├── getting_started.md.in # processed into markdown during cmake documentation build
│ │ ├── modules.json # json style file listing plugins and any 3rd party dependencies
│ │ └── *.md # general documentation
│ ├── doxygen
│ │ └── Doxyfile.in # file to control doxygen, processed during cmake configuration
│ └── mkdocs
│ └── mkdocs.yaml.in # file to control mkdocs, processed during cmake configuration
├── include
│ └── illixr
│ ├── data_format # header files for commonly used data structures
│ └── * # header files used my multiple plugins or the main binary
├── plugins
│ ├── <plugin_name> # each plugin has its own subdirectory
│ │ └── CMakeLists.txt # if the plugin is from another repository, then only this file is needed
│ ├── <plugin_name>
│ │ ├── CMakeLists.txt # cmake file which configures the build for this plugin
│ │ ├── plugin.hpp # header file for the plugin, defining the class
│ │ ├── *.hpp # additional header files, if any, for the plugin
│ │ ├── *.cpp # additional source files, if any, for the plugin
│ │ └── plugin.cpp # every plugin must have this file which contains the code for the plugin
│ └── plugins.yaml # yaml style file listing configurations, plugins, and services
├── profiles
│ └── *.yaml # yaml style files for each profile, these are auto-generated
├── services
│ ├── <service_name>
│ │ ├── CMakeLists.txt # cmake file which configures the build for this plugin
│ │ ├── service.hpp # header file for the plugin, defining the class
│ │ ├── *.hpp # additional header files, if any, for the service
│ │ ├── *.cpp # additional source files, if any, for the service
│ │ └── service.cpp # every plugin must have this file which contains the code for the plugin
├── src
│ ├── display
│ │ ├── *.hpp # header files for display back ends
│ │ └── *.cpp # source files for display back ends
│ ├── sqlite3pp
│ │ └── *.hpp # header files for the sqlite interface
│ ├── CMakeLists.txt # cmake file for configuring the build of the main binary
│ ├── *.hpp # header files for the main binary
│ └── *.cpp # source files for the main binary
└── utils
├── imgui
│ └── * # header and source files for the ImGui library
├── CMakeLists.txt # cmake file for configuring the build of the utility static libraries
├── *.hpp # header files for the utility libraries
└── *.cpp # source files for the utility libraries
In addition to the above, if any individual plugin relies on third party code, this code should be placed in a directory named third_party
inside the plugin directory. Files inside the third_party
directory can be organized in any fashion. For example:
plugins
└── myplugin
├── third_party
│ ├── vk_mapper.c # third party code
│ └── vk_mapper.h
├── plugin.hpp # plugin header
├── plugin.cpp # plugin code
└── CMakeLists.txt # plugin CMake file
File Naming
Illixr has adopted the following file naming conventions:
- files and directories are all lower case
- the
_
should be used as a word seperator - header files should have the
.hpp
suffix - code files should have the
.cpp
suffix - documentation files should have the
.md
suffix - each plugin must have its own header file called
plugin.hpp
which defines the class, this is to make it easier to see all the variables, etc. which could become buried in code otherwise - each service must have its own header file called
service.hpp
which defines the class, this is to make it easier to see all the variables, etc. which could become buried in code otherwise - any third party code used in ILLIXR is not subject to the above rules and can keep their original naming conventions
Exceptions
Files which must have a specific naming convention that is expected by outside code (e.g. CMakeLists.txt, Doxyfile, etc.), can use any case needed.
Header Files
ILLIXR has adopted the #pragma once
include guard for all header files.
Includes
Header files used via the #include
pre-processor directive should be at the top of the code and header files, and ordered in the following fashion:
- any
plugin.hpp
orservice.hpp
associated with the plugin/service - any headers from inside the ILLIXR codebase
- blank line
- system headers (those in angle brackets, e.g.
<stdlib.h>
<string>
)
Not every file will have includes from each group. Any missing group can just be skipped.
Header files in each group should be listed in alphabetical order. Some headers will only be included under certain conditions, by using #ifdef
statements. These headers, and their conditionals, should be added below all other header files. This is an example:
#include "illixr/data_format.hpp"
#include "illixr/phonebook.hpp"
#include "illixr/plugin.hpp"
#include <iostream>
#include <stdlib.h>
#include <string>
#include <vulkan/vulkan_core.h>
#ifdef ZED
#include "zed.h"
#endif
Comments may be added between the groups as long as there is a blank line after each grouping. #define
and #undef
directives can be used at any place inside, before, or after any header grouping as needed.
Namespace
All ILLIXR code is inside the ILLIXR namespace. The use of additional namespaces below ILLIXR (e.g. ILLIXR::data_format
)
Classes
We have adopted the Google style for class
declaration order:
class XYZ {
public:
# types and aliases (including enums)
# static constants
# factory functions (not widely used in ILLIXR)
# constructor(s) and assignment operators (if any)
# destructor
# all other functions
# data members
protected:
# types and aliases
# static constants
# factory functions (not widely used in ILLIXR)
# all other functions
# data members
private:
# types and aliases
# static constants
# factory functions (not widely used in ILLIXR)
# all other functions
# data members
};
For struct
s, the order should be:
struct XYZ {
# all data members
# constructor(s)
# all other functions
};
If a class constructor and/or destructor has no functionality it should be defined with = default
rather than {}
. For example
class XYZ {
public:
XYZ() {}
~XYZ() {}
};
should be
class XYZ{
public:
XYZ() = default;
~XYZ() = default;
};
Single argument constructors should be marked explicit
in order to avoid unintentional implicit conversions.
Naming
Names (file, variable, class, arguments, etc.) should be readable and clear, even to those unfamiliar to the project. Names should be descriptive of the purpose of the item. Shorter names (e.g. n
, i
) are acceptable for iterators, indexes, etc. Common abbreviations are also acceptable (e.g. no
or num
for number; attr
or attrib
for attribute; l
or L
for left, etc.).
ILLIXR has adopted the snake case naming convention. Names (variables, class names, files, etc.) start with a lower
case letter and use the underscore _
in place of spaces. Additionally, there should be no prefixes like _
, m_
, or _M_
on any class member variable names. All class data members should be suffixed with a single underscore _
.
Templates
In order to make reading the code clearer, template parameters should either be a single capital letter (T
, H
, etc.) or be a descriptive name that starts with a capital letter.
CMake
We currently require a minimum version of 3.22 for CMake. If you use any CMake features that have changed their default behavior over timeE17, we request you use CMake's POLICY
directives to quiet any spurious warning messages. For example:
if (POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()