SpECTRE Documentation Coverage Report
Current view: top level - __w/spectre/spectre/docs/DevGuide - BuildSystem.md Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 0 1 0.0 %
Date: 2024-04-23 20:50:18
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : \cond NEVER
       2             : Distributed under the MIT License.
       3             : See LICENSE.txt for details.
       4             : \endcond
       5             : # Build System {#spectre_build_system}
       6             : 
       7             : \tableofcontents
       8             : 
       9             : # CMake {#cmake}
      10             : 
      11             : SpECTRE uses [CMake](https://cmake.org/) for the build system. In this
      12             : section of the guide we outline how to [add new source
      13             : files](#adding_source_files), [libraries](#adding_libraries), [unit
      14             : tests](#adding_unit_tests), [executables](#adding_executables), and
      15             : [external dependencies](#adding_external_dependencies).  We also
      16             : describe [commonly used CMake flags](#common_cmake_flags).
      17             : 
      18             : Note that in editing `CMakeLists.txt` files, it is conventional to
      19             : indent multiline commands by two spaces (except for the first line),
      20             : and to separate most commands by blank lines.
      21             : 
      22             : ## Adding Source Files {#adding_source_files}
      23             : 
      24             : SpECTRE organizes source files into subdirectories of `src` that are
      25             : compiled into libraries.  To add a new source file `FILE.cpp` to an
      26             : existing library in `src/PATH/DIR`, just edit
      27             : `src/PATH/DIR/CMakeLists.txt` and add `FILE.cpp` to the list of files
      28             : in
      29             : ```
      30             : set(LIBRARY_SOURCES
      31             :   <list_of_files>
      32             :   )
      33             : ```
      34             : such that the resulting `<list_of_files>` is in alphabetical order.
      35             : 
      36             : ### Adding Libraries {#adding_libraries}
      37             : 
      38             : To add a source file `FILE.cpp` that is compiled into a new library `LIB` in a
      39             : directory `src/PATH/DIR` (either in a new directory, or in an existing
      40             : directory that either does not have a `CMakeLists.txt` file, or does
      41             : not create a library in the existing `CMakeLists.txt`):
      42             : - Create (if necessary) a `CMakeLists.txt` file in `DIR`, with the following
      43             : two lines at the top:
      44             : ```
      45             : # Distributed under the MIT License.
      46             : # See LICENSE.txt for details.
      47             : ```
      48             : - In the parent directory (i.e. `src/PATH`), (if necessary) add the
      49             : following line to its `CMakeLists.txt` file (if necessary, recursively
      50             : do the previous step and this one until you reach a `CMakeLists.txt` that
      51             : adds the appropriate subdirectory):
      52             : ```
      53             : add_subdirectory(DIR)
      54             : ```
      55             : If there are already other `add_subdirectory()` lines in the file, place
      56             : the new one so that the subdirectories are in alphabetical order.
      57             : - Add the line:
      58             : ```
      59             : set(LIBRARY LIB)
      60             : ```
      61             : where convention is that `LIB` = `DIR`.  As library names must be
      62             : unique, this is not always possible, in which case the convention is to
      63             : prepend the parent directory to `DIR`.
      64             : - Add the lines
      65             : ```
      66             : set(LIBRARY_SOURCES
      67             :   FILE.cpp
      68             :   )
      69             : 
      70             : add_spectre_library(${LIBRARY} ${LIBRARY_SOURCES})
      71             : 
      72             : target_link_libraries(
      73             :   ${LIBRARY}
      74             :   PUBLIC
      75             :   <list_of_public_libraries>
      76             :   PRIVATE
      77             :   <list_of_private_libraries>
      78             :   INTERFACE
      79             :   <list_of_interface_libraries>
      80             :   )
      81             : ```
      82             : where each `<list_of_X_libraries>` is an alphabetized list
      83             : of libraries of the form
      84             : ```
      85             :   SomeLibrary
      86             :   SomeOtherLibrary
      87             :   YetAnotherLibrary
      88             : ```
      89             : The libraries listed under `INTERFACE` are those included in at
      90             : least one `.hpp` file in `LIB` but never used in any `.cpp` files
      91             : in `LIB`.  The libraries listed under `PRIVATE` are used in
      92             : at least one `.cpp` file in `LIB` but not in any `.hpp` file
      93             : in `LIB`.  The libraries listed under `PUBLIC` are used in at
      94             : least one `.hpp` file and at least one `.cpp` file in `LIB`.
      95             : Note that a library counts as being used in a `.cpp` file if the
      96             : corresponding `.hpp` file includes it. In other words, list a dependency
      97             : as `PRIVATE` if it is needed only to compile the library, but not for
      98             : including headers. List a dependency as `INTERFACE` if it is not needed
      99             : to compile the library, but is needed for including headers. List a
     100             : dependency as `PUBLIC` if it is needed for both.
     101             : 
     102             : ## Adding Unit Tests {#adding_unit_tests}
     103             : 
     104             : We use the [Catch](https://github.com/philsquared/Catch) testing
     105             : framework for unit tests. All unit tests are housed in `tests/Unit`
     106             : with subdirectories for each subdirectory of `src`. Add the `cpp` file
     107             : to the appropriate subdirectory and also to the `CMakeLists.txt` in
     108             : that subdirectory. Inside the source file you can create a new test by
     109             : adding a `SPECTRE_TEST_CASE("Unit.Dir.Component",
     110             : "[Unit][Dir][Tag]")`. The `[Tag]` is optional and you can have more
     111             : than one, but the tags should be used quite sparingly.  The purpose of
     112             : the tags is to be able to run all unit tests or all tests of a
     113             : particular set of components, e.g. `ctest -L Data` to run all tests
     114             : inside the `Data` directory. Please see \ref writing_unit_tests
     115             : "writing unit tests", other unit tests and the [Catch
     116             : documentation](https://github.com/philsquared/Catch) for more help on
     117             : writing tests. Unit tests should take as short a time as possible,
     118             : with a goal of less than two seconds.  Please also limit the number of
     119             : distinct cases (by using `SECTION`s).
     120             : 
     121             : You can check the unit test coverage of your code by installing all the optional
     122             : components and then running `make unit-test-coverage` (after re-running CMake).
     123             : This will create the
     124             : directory `BUILD_DIR/docs/html/unit-test-coverage/` which is where the coverage
     125             : information is located. Open the `index.html` file in your browser and make
     126             : sure that your tests are indeed checking all lines of your code. Your pull
     127             : requests might not be merged until your line coverage is over 90% (we are aiming
     128             : for 100% line coverage wherever possible). Unreachable lines of code can be
     129             : excluded from coverage analysis by adding the inline comment `LCOV_EXCL_LINE`
     130             : or a block can be excluded using `LCOV_EXCL_START` and `LCOV_EXCL_STOP`.
     131             : However, this should be used extremely sparingly since unreachable code paths
     132             : should be removed from the code base altogether.
     133             : 
     134             : ## Adding Executables {#adding_executables}
     135             : 
     136             : All general executables are found in `src/Executables`, while those
     137             : for specific evolution (elliptic) systems are found in
     138             : `src/Evolution/Executables` (`src/Elliptic/Executables`).  See \ref
     139             : dev_guide_creating_executables "how to create executables".
     140             : 
     141             : ## Adding External Dependencies {#adding_external_dependencies}
     142             : 
     143             : To add an external dependency, first add a `SetupDEPENDENCY.cmake`
     144             : file to the `cmake` directory. You should model this after the
     145             : existing one for `Brigand` if you're adding a header-only
     146             : library and `yaml-cpp` if the library is not header-only. If CMake
     147             : does not already support `find_package` for the library you're adding
     148             : you can write your own. These should be modeled after `FindBrigand`
     149             : for header-only libraries, and `FindYAMLCPP` for compiled
     150             : libraries. The `SetupDEPENDENCY.cmake` file must then be included in
     151             : the root `spectre/CMakeLists.txt`. Be sure to test both that setting
     152             : `LIBRARY_ROOT` works correctly for your library, and also that if the
     153             : library is required that CMake fails gracefully if the library is not
     154             : found.
     155             : 
     156             : ## Commonly Used CMake flags {#common_cmake_flags}
     157             : The following are the most common flags used to control building with
     158             : `CMake`. They are used by
     159             : ```
     160             : cmake -D FLAG1=OPT1 ... -D FLAGN=OPTN <SPECTRE_ROOT>
     161             : ```
     162             : - ASAN
     163             :   - Whether or not to turn on the address sanitizer compile flags
     164             :     (`-fsanitize=address`) (default is `OFF`)
     165             : - BLAZE_USE_ALWAYS_INLINE
     166             :   - Force Blaze inlining (default is `ON`)
     167             :   - If disabled or if the platform is unable to 100% guarantee inlining,
     168             :     falls back to `BLAZE_USE_STRONG_INLINE` (see below)
     169             :   - Forced inlining reduces function call overhead, and so generally reduces
     170             :     runtime. However, it does increase compile time and compile memory usage. It
     171             :     is also easier to use a debugger when forced inlining is disabled. If you
     172             :     are encountering debugger messages like `function inlined`, then forced
     173             :     inlining should be disabled.
     174             : - BLAZE_USE_STRONG_INLINE
     175             :   - Increase the likelihood of Blaze inlining (default is `ON`)
     176             :   - Strong inlining reduces function call overhead, and so generally reduces
     177             :     runtime. However, it does increase compile time and compile memory usage. It
     178             :     is also easier to use a debugger when strong inlining is disabled. If you
     179             :     are encountering debugger messages like `function inlined`, then strong
     180             :     inlining should be disabled.
     181             : - BOOTSTRAP_PY_DEPS and BOOTSTRAP_PY_DEV_DEPS
     182             :   - Install missing Python dependencies into the build directory, as listed in
     183             :     `support/Python/requirements.txt` and `support/Python/dev_requirements.txt`,
     184             :     respectively. This is an alternative to creating a Python environment and
     185             :     installing the packages yourself. If you run into problems with packages
     186             :     like h5py, numpy or scipy you can/should still install them yourself to make
     187             :     sure they use the correct HDF5, BLAS, etc.
     188             :     (default is `OFF`)
     189             : - BUILD_PYTHON_BINDINGS
     190             :   - Build python libraries to call SpECTRE C++ code from python
     191             :     (default is `ON`)
     192             : - BUILD_SHARED_LIBS
     193             :   - Whether shared libraries are built instead of static libraries
     194             :     (default is `OFF`)
     195             : - BUILD_TESTING
     196             :   - Enable building tests. (default is `ON`)
     197             : - BUILD_DOCS
     198             :   - Enable building documentation. (default is `ON`)
     199             : - DOCS_ONLY
     200             :   - Build _only_ documentation (default is `OFF`). Requires `BUILD_DOCS=ON`.
     201             : - CHARM_ROOT
     202             :   - The path to the build directory of `Charm++`
     203             : - CHARM_TRACE_PROJECTIONS
     204             :   - Enables tracing with Charm++ projections. Specifically, enables the link
     205             :     flag `-tracemode projections`. (default is `OFF`)
     206             : - CHARM_TRACE_SUMMARY
     207             :   - Enables trace summaries with Charm++ projections. Specifically, enables
     208             :     the link flag `-tracemode summary`. (default is `OFF`)
     209             : - CMAKE_BUILD_TYPE
     210             :   - Sets the build type.  Common options:
     211             :     - `Debug` (the default if the flag is not specified): sets flags
     212             :       that trigger additional error checking
     213             :     - `Release`
     214             : - CMAKE_C_COMPILER
     215             :   - The `C` compiler used (defaults to whatever is determined by
     216             :     `CMake/Modules/CMakeDetermineCCompiler.cmake`, usually `cc`)
     217             : - CMAKE_CXX_COMPILER
     218             :   - The `C++` compiler used (defaults to whatever is determined by
     219             :     `CMake/Modules/CMakeDetermineCXXCompiler.cmake`, usually `c++`)
     220             : - CMAKE_Fortran_COMPILER
     221             :   - The `Fortran` compiler used (defaults to whatever is determined by
     222             :     `CMake/Modules/CMakeDetermineFortranCompiler.cmake`)
     223             : - CMAKE_C_FLAGS
     224             :   - Additional flags passed to the `C` compiler.
     225             : - CMAKE_CXX_FLAGS
     226             :   - Additional flags passed to the `C++` compiler.
     227             : - CMAKE_Fortran_FLAGS
     228             :   - Additional flags passed to the `Fortran` compiler.
     229             : - CMAKE_RUNTIME_OUTPUT_DIRECTORY
     230             :   - Sets the directory where the library and executables are placed.
     231             :     By default libraries end up in `<BUILD_DIR>/lib` and executables
     232             :     in `<BUILD_DIR>/bin`.
     233             : - CMAKE_INSTALL_PREFIX
     234             :   - Location where the `install` target copies executables, libraries, etc. Make
     235             :     sure to set this variable before you `install`, or a default location such
     236             :     as `/usr/local` is used.
     237             : - COVERAGE
     238             :   - Enable code coverage with GCOV and LCOV (default `OFF`)
     239             : - DEBUG_SYMBOLS
     240             :   - Whether or not to use debug symbols (default is `ON`)
     241             :   - Disabling debug symbols will reduce compile time and total size of the build
     242             :     directory.
     243             : - ENABLE_OPENMP
     244             :   - Enable OpenMP parallelization in some parts of the code, such as Python
     245             :     bindings and interpolating volume data files. Note that simulations do not
     246             :     typically use OpenMP parallelization, so this flag only applies to tools.
     247             : - ENABLE_PARAVIEW
     248             :   - Try to find ParaView to enable 3D rendering tools (default is `OFF`)
     249             : - ENABLE_PROFILING
     250             :   - Enables various options to make profiling SpECTRE easier
     251             :     (default is `OFF`)
     252             : - ENABLE_SPECTRE_DEBUG
     253             :   - Defines `SPECTRE_DEBUG` macro to enable `ASSERT`s and other debug
     254             :     checks so they can be used in Release builds. That is, you get sanity checks
     255             :     and compiler optimizations. You cannot disable the checks in Debug builds,
     256             :     so this option has no effect in Debug builds.
     257             :     (default is `OFF` in release)
     258             : - ENABLE_WARNINGS
     259             :   - Whether or not warning flags are enabled (default is `ON`)
     260             : - FUKA_ROOT
     261             :   - Set to a path to a [FUKA](https://bitbucket.org/fukaws/fuka) installation to
     262             :     enable loading FUKA initial data into SpECTRE. Can be the FUKA repository
     263             :     root or the directory where `libkadath.a` was installed. Also requires FFTW
     264             :     to be installed (see FUKA docs on dependencies).
     265             : - KEEP_FRAME_POINTER
     266             :   - Whether to keep the frame pointer. Needed for profiling or other cases
     267             :     where you need to be able to figure out what the call stack is.
     268             :     (default is `OFF`)
     269             : - MACHINE
     270             :   - Select a machine that we know how to run on, such as a particular
     271             :     supercomputer. A file named MACHINE.yaml must exist in support/Machines and
     272             :     a submit script template named MACHINE.sh must exist in
     273             :     support/SubmitScripts.
     274             : - MEMORY_ALLOCATOR
     275             :   - Set which memory allocator to use. If there are unexplained segfaults or
     276             :     other memory issues, it would be worth setting `MEMORY_ALLOCATOR=SYSTEM` to
     277             :     see if that resolves the issue. It could be the case that different
     278             :     third-party libraries accidentally end up using different allocators, which
     279             :     is undefined behavior and will result in complete chaos.
     280             :     (default is `JEMALLOC`)
     281             : - PY_DEV_MODE
     282             :   - Enable development mode for the Python package, meaning that Python files
     283             :     are symlinked rather than copied to the build directory. Allows to edit and
     284             :     test Python code much easier, in particular when it uses compiled Python
     285             :     bindings, but doesn't replace CMake placeholders in the Python code such as
     286             :     the project version. (default is `OFF`)
     287             : - SPEC_ROOT
     288             :   - Set to a path to a SpEC installation (the SpEC repository root) to link in
     289             :     SpEC libraries. In particular, the SpEC::Exporter library is linked in and
     290             :     enables loading SpEC data into SpECTRE. See \ref installation for details.
     291             : - SPECTRE_INPUT_FILE_TEST_MIN_PRIORITY
     292             :   - Minimum priority of input file tests to run. Possible values are: `low` (not
     293             :     usually run on CI), `normal` (run at least once on CI), `high` (run always
     294             :     on CI). (default is `normal`)
     295             : - SPECTRE_LTO
     296             :   - Enable link-time optimization if the compiler supports it.
     297             : - SPECTRE_LTO_CORES
     298             :   - Specifies the number of cores to use for parallelizing LTO. Must be a
     299             :     positive integer or "auto". This is only available when `SPECTRE_LTO=ON` and
     300             :     the compiler supports LTO.
     301             : - SPECTRE_TEST_RUNNER
     302             :   - Run test executables through a wrapper.  This might be `charmrun`, for
     303             :     example.  (default is to not use one)
     304             : - SPECTRE_TEST_TIMEOUT_FACTOR (and specific overrides
     305             :   SPECTRE_X_TEST_TIMEOUT_FACTOR for X one of UNIT, STANDALONE, INPUT_FILE, or
     306             :   PYTHON)
     307             :   - Multiply the timeout for the respective set of tests by this factor (default
     308             :     is `1`).
     309             :   - This is useful to run tests on slower machines.
     310             : - SPECTRE_USE_ALWAYS_INLINE
     311             :   - Force SpECTRE inlining (default is `ON`)
     312             :   - Forced inlining reduces function call overhead, and so generally reduces
     313             :     runtime. However, it does increase compile time and compile memory usage. It
     314             :     is also easier to use a debugger when forced inlining is disabled. If you
     315             :     are encountering debugger messages like `function inlined`, then forced
     316             :     inlining should be disabled.
     317             : - STRIP_SYMBOLS
     318             :   - Whether or not to strip all symbols (default is `OFF`)
     319             :   - If enabled strips all extraneous symbols from libraries and executables,
     320             :     further reducing the size of them.
     321             : - STUB_EXECUTABLE_OBJECT_FILES
     322             :   - Replace object files from executables after linking with empty stubs
     323             :     (default is `OFF`)
     324             :   - This is useful for drastically reducing the build size in CI, but since the
     325             :     object files are replaced with empty stubs will generally cause linking
     326             :     problems if used during development.
     327             : - STUB_LIBRARY_OBJECT_FILES
     328             :   - Replace object files from libraries after linking with empty stubs
     329             :     (default is `OFF`)
     330             :   - This is useful for drastically reducing the build size in CI, but since the
     331             :     object files are replaced with empty stubs will generally cause linking
     332             :     problems if used during development.
     333             : - UBSAN_INTEGER
     334             :   - Whether or not to turn on the undefined behavior sanitizer
     335             :     [unsigned integer
     336             :     overflow](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) flag
     337             :     (`-fsanitize=integer`) (default is `OFF`)
     338             : - UBSAN_UNDEFINED
     339             :   - Whether or not to turn on the undefined behavior sanitizer
     340             :     [undefined
     341             :     behavior](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html)
     342             :     compile flags (`-fsanitize=undefined`) (default is `OFF`)
     343             : - UNIT_TESTS_IN_TEST_EXECUTABLES
     344             :   - Whether to build the `unit-tests` target as part of the `test-executables`
     345             :     target. This is used to build only the non-unit tests in the CI build
     346             :     that doesn't use the PCH. (default is `ON`)
     347             : - USE_CCACHE
     348             :   - Use ccache to cache build output so that rebuilding parts of the source tree
     349             :     is faster. The cache will use up space on disk, with the default being
     350             :     around 2-5GB. If you are performing a one time build to test something
     351             :     specific you should consider disabling ccache in order to avoid removing
     352             :     cached files that may be useful in other builds.
     353             :     (default is `ON`)
     354             : - USE_FORMALINE
     355             :   - Write the source tree into HDF5 files written to disk in order to increase
     356             :     reproducibility of results.
     357             :     (default is `ON`)
     358             : - USE_GIT_HOOKS
     359             :   - Use git hooks to perform some sanity checks so that small goofs are caught
     360             :     before they are committed. These checks are particularly useful because they
     361             :     also run automatically on \ref github_actions_guide "CI" and must pass
     362             :     before pull requests are merged.
     363             :     (default is `ON`)
     364             : - USE_IWYU
     365             :   - Enable [include-what-you-use (IWYU)](https://github.com/include-what-you-use/include-what-you-use)
     366             :     tools. (default is `OFF`)
     367             : - USE_LD
     368             :   - Override the automatically chosen linker. The options are `ld`, `gold`, and
     369             :     `lld`.
     370             :     (default is `OFF`)
     371             : - USE_PCH
     372             :   - Whether or not to use pre-compiled headers (default is `ON`)
     373             :   - This needs to be turned `OFF` in order to use
     374             :     [include-what-you-use
     375             :     (IWYU)](https://github.com/include-what-you-use/include-what-you-use)
     376             : - USE_SLEEF
     377             :   - Whether to use [Sleef](https://github.com/shibatch/sleef) with Blaze to
     378             :     vectorize addition math functions like `sin`, `cos`, and `exp`.
     379             :     (default is `OFF`)
     380             :   - \note Blaze isn't tested super thoroughly across different architectures so
     381             :     there's unfortunately no guarantee that Blaze+Sleef will work everywhere.
     382             : - USE_XSIMD
     383             :   - Whether to use [xsimd](https://github.com/xtensor-stack/xsimd) with Blaze to
     384             :     vectorize addition math functions like `sin`, `cos`, and `exp`.
     385             :     Defines the macro `SPECTRE_USE_XSIMD`, which can be check to enable manual
     386             :     vectorization where necessary.
     387             :     (default is `OFF`)
     388             : 
     389             : ## CMake targets
     390             : 
     391             : In addition to individual simulation executables, the following targets are
     392             : available to build with `make` or `ninja`:
     393             : 
     394             : - unit-tests
     395             :   - Build unit tests, which you can run with `ctest -L unit`. Available if
     396             :     `BUILD_TESTING` is `ON` (the default).
     397             : - test-executables
     398             :   - Build all tests, including executables, so you can run all tests with
     399             :     `ctest`. Available if `BUILD_TESTING` is `ON` (the default). To compile
     400             :     `test-executables` you may have to reduce the number of cores you build on
     401             :     in parallel to avoid running out of memory.
     402             : - all-pybindings
     403             :   - Build Python bindings. See \ref spectre_using_python for details.
     404             : - cli
     405             :   - Same as all-pybindings
     406             : - install
     407             :   - Install targets that have been built to the `CMAKE_INSTALL_PREFIX`. Doesn't
     408             :     try to build anything else.
     409             : 
     410             : ## Checking Dependencies
     411             : 
     412             : Getting dependencies of libraries correct is quite difficult. SpECTRE offers the
     413             : CMake function `check_spectre_libs_dependencies`, defined in
     414             : `cmake/SpectreCheckDependencies.cmake`, to check the dependencies for all
     415             : libraries in the `libs` target. Individual target dependencies can be checked
     416             : using the `check_target_dependencies` CMake function defined in
     417             : `cmake/SpectreCheckTargetDependencies.cmake`. Please see those functions in the
     418             : source tree for more details on how to use them.
     419             : 
     420             : ## Formaline
     421             : 
     422             : SpECTRE's implementation of Formaline is based on, but distinct in
     423             : implementation from, the original design by
     424             : [Erik Schnetter and Christian Ott](https://github.com/hypercott/formaline),
     425             : which embeds an archive of the source tree into the executable. The original
     426             : design creates a C/C++ file with a function that returns an array/vector of
     427             : `char`s (a byte stream). However, this results in a very large source file (50MB
     428             : or more), which is very slow to compile and ends up more than doubling the link
     429             : time. Instead, SpECTRE's Formaline implementation uses the linker `ld` to
     430             : encode a file into an object, which means
     431             : rather than creating a large source file, we can directly encode the source tree
     432             : archive into the binary at the linking stage.
     433             : 
     434             : Most of SpECTRE's Formaline is implemented
     435             : inside the `tools/WrapExecutableLinker.sh` script. Function declarations are
     436             : provided in `Utilities/Formaline.hpp` and a small function that writes the
     437             : source file to disk is defined in `Utilities/Formaline.cpp`. The first
     438             : Formaline-related thing done in `WrapExecutableLinker.sh` is to archive
     439             : everything in the source directory tracked by git. Once the archive is created
     440             : we run `ld -r -b binary -o object.o src.tar.gz` (with unique names for
     441             : `object.o` and `src.tar.gz` for each executable that is built to avoid name
     442             : collisions) to generate an object file with the source file encoded from
     443             : `_binary_src_tar_gz_start` to `_binary_src_tar_gz_end`. Next we write a C++
     444             : source file that defines a function `get_archive` to convert the byte stream
     445             : into a `std::vector<char>`. We also encode the output of `printenv`, the various
     446             : `PATH` environment variables, and the CMake generated `BuildInfo.txt` file
     447             : into the source file. Finally, the generated source file is built during the
     448             : linking phase and the object file containing the source archive is linked into
     449             : the executable.
     450             : 
     451             : To further aid in reproducibility, the `printenv` output and
     452             : `BuildInfo.txt` contents are written to HDF5 files as part of the
     453             : `h5::Header` object. The archive of the source tree is written using the
     454             : `h5::SourceArchive` object and can be extracted by running
     455             : ```
     456             : h5dump -d /src.tar.gz -b LE -o src.tar.gz /path/to/hdf5/file.h5
     457             : ```

Generated by: LCOV version 1.14