diff --git a/requirements.txt b/requirements.txt index 69e61c1..1aef75d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -sphinx==4.2.0 -sphinx_rtd_theme==1.0.0 +sphinx==7.4.7 +sphinx_rtd_theme==2.0.0 diff --git a/source/conf.py b/source/conf.py index 5805202..772399f 100644 --- a/source/conf.py +++ b/source/conf.py @@ -64,14 +64,14 @@ source_suffix = '.rst' # The master toctree document. -master_doc = 'index' +root_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -141,7 +141,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'SODeveloperGuide.tex', 'SO Developer Guide Documentation', + (root_doc, 'SODeveloperGuide.tex', 'SO Developer Guide Documentation', 'Simons Observatory Collaboration', 'manual'), ] @@ -153,7 +153,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'sodeveloperguide', 'SO Developer Guide Documentation', + (root_doc, 'sodeveloperguide', 'SO Developer Guide Documentation', [author], 1) ] @@ -164,7 +164,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'SODeveloperGuide', 'SO Developer Guide Documentation', + (root_doc, 'SODeveloperGuide', 'SO Developer Guide Documentation', author, 'SODeveloperGuide', 'One line description of project.', 'Miscellaneous'), ] diff --git a/source/cpp.rst b/source/cpp.rst index f3f95fb..50084a5 100644 --- a/source/cpp.rst +++ b/source/cpp.rst @@ -5,42 +5,289 @@ C/C++ Overview ======== -.. todo:: Emphasize grandparent clause here, because C/C++ syntax is - very permissive and there are a number of standards. +C++ is an important part of the software ecosystem of SO, and is used in important and +performance-critical code. C++ is a complex language and very permissive on formatting. + +In addition, formatting and styling from older standards (C++98, C++03) is very +different from modern C++ (C++11 and later). As a result, these guidelines will +not require old codebases to be reformatted, but will require new code to follow a +modern C++ style and formatting. + +Though not required, if time permits, refactoring old code to modern C++ is encouraged. + Version Support =============== -.. todo:: C++11, gcc. +All SO C++ code must compile as C++11 or later. C++11 introduced +RAII-based resource management, lambda expressions, move semantics, and +the ```` library, among other features that modern code relies +on. New code should target C++11 at minimum; individual repositories +may choose a newer standard (C++14, C++17) if their environment +guarantees it, and should document that choice in their build +configuration and README. + +The supported compilers are GCC 11 or later and Clang 10 or later. +Both provide full C++11 through C++17 support. Certain site computing resources +may have older compilers. In such cases, the minimum supported version should be +documented in the repository of the software. Style ===== -.. todo:: Identify the elements of formatting, and the numerous - formatting Argue about C/C++ formatting. +Although there are many C++ style guides, and there is no single "correct" way to +write C++, we adopt a modified Google C++ style guide. For any rule not explicitly +specified in this document, please refer to the `Google C++ style guide`_. + +In addition to the style description, we provide a :ref:`config file for clang-format ` +that can automatically format code. In case you find yourself working on code that is +not formatted according to the style, you can maintain the existing style. However, +when you are formatting the code, we highly recommend to use a branch which only contains +the formatting changes and submit a pull request. + Indentation ----------- -Proposal: +Indentation is one of the aspects of code formatting that is important to be consistent +across codebases, especially since we use multiple languages. + +We will use 2 or 4 spaces as the indentation for C++. + +Tabs are not allowed for indentation. + + +Line width +---------- + +The maximum line width allowed is 120 characters. -- The basic indent shall be 4 spaces (2 is hard to follow, 8 is too - wasteful; non-powers of 2 are too weird). -- Spaces, not tabs. Naming Conventions ------------------ +The name of a variable, function or class is one of the most important aspects of code +readability. It can immediately inform about the purpose of the named thing. Please avoid +single letter names, except for loop variables, even if it is a commonly understandable +variable. + +We will utilize the following naming conventions: +1. Class and struct names should be in PascalCase, e.g. `MyClass`. +2. Function names should be in camelCase, e.g. `myFunction`. +3. Variable names should be in snake_case, e.g. `my_variable`. +4. Constants should be in ALL_CAPS with underscores, e.g. `MAX_SIZE`. +5. Namespaces should be in snake_case, e.g. `my_namespace`. + + +Header Files +------------ + +All header files must guard against multiple inclusion. Use ``#pragma once`` at the +top of the file, rather than traditional ``#ifndef``/``#define``/``#endif`` guards:: + + #pragma once + + // header contents + +``#pragma once`` is supported by all compilers we target (GCC and Clang) and avoids +the maintenance burden and risk of typos or naming collisions inherent to manually +written include guard macros. + Use of Language Features ------------------------ +Guidance on modern C++ features is already covered by the `Google C++ style guide`_, +and we follow it without modification. + +.. _cpp-clang-format-config: + +Clang-format Config +------------------- +As formatting tool, we will use clang-format. The config file for the expected formatting +is: + +.. code-block:: yaml + + BasedOnStyle: Google + ColumnLimit: 120 + IndentWidth: 2 + +Please copy this in `.clang-format` file in the root of your repository. + +Note: Indentation width can be 2 or 4 spaces, but it should be consistent across the codebase. Documentation of Code ===================== +Documentation of the code provides information about the code to users and developers alike. +There are two types of documentation that are important: inline comments, and API docstrings. + +For comments `/*..*/` and `//` are acceptable, but try to be consistent within the +code. + +For API docstrings, we will use Doxygen style comments. The block starts with `/**` and +ends with `*/`. Each block should contain a `@brief` description, `@param` for each +parameter, and `@return` for the return value, unless it is a void. + +For example: + .. code-block:: cpp + + /** + * @brief Adds two integers and returns the result. + * + * @param a The first integer to add. + * @param b The second integer to add. + * @return The sum of a and b. + */ + int add(int a, int b) { + return a + b; + } + + Unit Testing ============ -https://github.com/catchorg/Catch2 +Unit testing is an important part of software development. It helps ensure that the code +is working as expected, helps catch bugs early and verify that the code is not regressing +when feature or changes are made. Testing suites are only expected to grow over time. + +Due to the importance of unit testing, we will require that all new code be accompanied by at +least one unit test. The unit test should be in a separate file, and should be named +`_test.cpp`, where `` is the name of the file being tested. + +`Catch2`_ is the unit testing framework for C++ we will use for SO as it is easy +to use, represents tests as normal boolean expressions and also allows benchmarking code. + +Please refer to the Catch2 documentation for more information on how to write unit tests. + + +Automatic Semantic Versioning +============================== + +`cmake-git-version-tracking`_ is the recommended tool for versioning. At configure +time CMake queries ``git describe``, writes the result into a generated C++ +header, and re-runs automatically whenever the git state changes. +There is no version string to maintain by hand. + +**Step 1 — fetch the module.** Copy ``git_watcher.cmake`` and +``git_version.h.in`` from the repository into your tree, e.g.:: + + cmake/ + git_watcher.cmake + git_version.h.in # provided by the library + +**Step 2 — wire it into** ``CMakeLists.txt``:: + + cmake_minimum_required(VERSION 3.14) + project(my_project) + + # Pull in the version-tracking module. + include(cmake/git_watcher.cmake) + + # This target re-runs whenever .git/HEAD or the index changes. + add_git_version_header(${PROJECT_NAME}_version + HEADER_FILE_NAME git_version.h + ) + + add_library(my_lib src/my_lib.cpp) + # Make the generated header visible to your targets. + target_link_libraries(my_lib PRIVATE ${PROJECT_NAME}_version) + +**Step 3 — use the version in C++.** Include the generated header:: + + #include "git_version.h" + + void printVersion() { + // GIT_RETRIEVED_STATE is false when building outside a git repo. + if (GIT_RETRIEVED_STATE) { + std::cout << "Version: " << GIT_DESCRIBE << "\n"; + // GIT_IS_DIRTY is true if there are uncommitted changes. + } + } + +The most useful macros exposed by the header are: + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Macro + - Description + * - ``GIT_DESCRIBE`` + - Output of ``git describe --tags --dirty`` (e.g. ``v1.2.3-4-gabcdef0-dirty``) + * - ``GIT_TAG`` + - Most recent tag (e.g. ``v1.2.3``) + * - ``GIT_COMMIT_DATE_ISO8601`` + - Commit timestamp + * - ``GIT_IS_DIRTY`` + - ``true`` if there are uncommitted changes + * - ``GIT_RETRIEVED_STATE`` + - ``false`` when built outside a git repository + + + +`cmake-git-semver`_ is a lightweight single-file alternative that parses a +``vMAJOR.MINOR.PATCH[-pre][+build]`` git tag directly into individual CMake +variables, which can be useful when you need to embed numeric version +components into build artefacts (shared library ``SOVERSION``, pkg-config +files, installers, etc.) rather than just exposing a raw ``git describe`` +string to C++ code. + +**Step 1 — fetch the module.** Copy ``git_semver.cmake`` into your tree:: + + cmake/ + git_semver.cmake + +**Step 2 — wire it into** ``CMakeLists.txt``:: + + cmake_minimum_required(VERSION 3.14) + project(my_project) + + include(cmake/git_semver.cmake) + git_semver(GIT_SEMVER) + + # Use the parsed components anywhere CMake variables are valid. + message(STATUS "Version: ${GIT_SEMVER}") + set_target_properties(my_lib PROPERTIES + VERSION "${GIT_SEMVER_MAJOR}.${GIT_SEMVER_MINOR}.${GIT_SEMVER_PATCH}" + SOVERSION "${GIT_SEMVER_MAJOR}" + ) + +The variables set after calling ``git_semver()`` are: + +.. list-table:: + :header-rows: 1 + :widths: 40 60 + + * - Variable + - Description + * - ```` + - Full version string (e.g. ``1.2.3-alpha+001``) + * - ``_MAJOR`` + - Major version component + * - ``_MINOR`` + - Minor version component + * - ``_PATCH`` + - Patch version component + * - ``_PRE_RELEASE`` + - Pre-release label (e.g. ``alpha``), empty if absent + * - ``_BUILD_METADATA`` + - Build metadata (e.g. ``001``), empty if absent + +.. note:: + + Tags must follow the ``vMAJOR.MINOR.PATCH`` format exactly. + ``cmake-git-semver`` will set all variables to ``0`` (and emit a + warning) if no conforming tag is found, so it is safe to use on a + fresh repository. + + +.. _cmake-git-version-tracking: https://github.com/andrew-hardin/cmake-git-version-tracking +.. _cmake-git-semver: https://github.com/nunofachada/cmake-git-semver +.. _Google C++ style guide: https://google.github.io/styleguide/cppguide.html +.. _Catch2: https://github.com/catchorg/Catch2 + +.. note:: + Portions of this page were drafted with the assistance of `Claude Code Sonnet 4.6`. \ No newline at end of file diff --git a/source/intro.rst b/source/intro.rst index 63f0f6f..d402f73 100644 --- a/source/intro.rst +++ b/source/intro.rst @@ -2,12 +2,43 @@ Introduction to the Developer Guide =================================== -Welcome to these lines. +Welcome to Simons Observatory (SO) Developer Guide. -This document is intended to establish rules but also to provide -guidance and tips for helping SO produce high quality code with an -effective workflow. +The purpose of this document is to establish the rules and guidelines for contributing +to SO's codebase across all repositories. It is intended to establish rules but also +provide guidance and tips for helping SO produce high quality code with an effective +workflow. -General best practices for coding, documentation and workflow are -provided in the first few chapters. Afterwards, special policies -relating to particular working groups are given. +General best practices for coding, documentation and workflow are provided in the first +few chapters. Afterwards, special policies relating to particular working groups are given. + +As code is a live entity, this document is also live. We will update the document as +needed and as coding practices evolve over time. If you have any suggestions or corrections, +please submit a pull request or open an issue in the appropriate repository. + + +Why have a Developer's Guide and Style Guide? +============================================== + +Code, especially open source code, is a collaborative effort. In addition, we all have +our own coding styles and preferences, and that's a good thing. Furthermore, software +code is a product that is distributed to the public and hopefully will be used by many +people outside of the collaboration. Incosistent code styles makes it harder for +contributors and users to read, understand and reuse code. A developer and style +guide aims to lower this friction. + +A style guide removes trivial decision-making from code review. When formatting and +naming are settled by convention, reviewers can focus on correctness, design, and +scientific validity. For this reason we require the use of source formatters. A diff +produced by a formatter-compliant change contains only the actual logical edit, not +incidental whitespace, indentation, or line-wrapping noise, keeping pull requests +small, focused, and easier on maintainers to review. + +A developer guide goes further: it captures the institutional knowledge that experienced +SO developers carry in their heads. Which testing framework do we use? How should a +new package be structured? Writing these decisions down means a new collaborator can be +productive in as little time as possble. + +The purpose of the guide is not to enforce uniformity just for the sake of uniformity. +Rather to reduce the time needed for new contributors to get up to speed, and reduce +review times so that we produce better and faster science.