From 9b366224ba52990a10453dc20a40290e5d5d18ab Mon Sep 17 00:00:00 2001 From: Kyle Nelli Date: Fri, 19 Jul 2024 15:12:22 -0700 Subject: [PATCH] Reorganize build system docs --- docs/Installation/BuildSystem.md | 335 +++++++++++++++++------------- docs/Installation/Installation.md | 2 +- docs/Main.md | 3 +- 3 files changed, 192 insertions(+), 148 deletions(-) diff --git a/docs/Installation/BuildSystem.md b/docs/Installation/BuildSystem.md index cd24cba005eeb..ede41ec7f35f3 100644 --- a/docs/Installation/BuildSystem.md +++ b/docs/Installation/BuildSystem.md @@ -2,163 +2,57 @@ Distributed under the MIT License. See LICENSE.txt for details. \endcond -# Build System {#spectre_build_system} +# Build System - CMake {#spectre_build_system} \tableofcontents -# CMake {#cmake} - SpECTRE uses [CMake](https://cmake.org/) for the build system. In this -section of the guide we outline how to [add new source -files](#adding_source_files), [libraries](#adding_libraries), [unit -tests](#adding_unit_tests), [executables](#adding_executables), and -[external dependencies](#adding_external_dependencies). We also -describe [commonly used CMake flags](#common_cmake_flags). - -Note that in editing `CMakeLists.txt` files, it is conventional to -indent multiline commands by two spaces (except for the first line), -and to separate most commands by blank lines. - -## Adding Source Files {#adding_source_files} - -SpECTRE organizes source files into subdirectories of `src` that are -compiled into libraries. To add a new source file `FILE.cpp` to an -existing library in `src/PATH/DIR`, just edit -`src/PATH/DIR/CMakeLists.txt` and add `FILE.cpp` to the list of files -in -``` -set(LIBRARY_SOURCES - - ) -``` -such that the resulting `` is in alphabetical order. +guide we'll outline how to configure SpECTRE and +describe some [commonly used CMake flags](#common_cmake_flags). +We'll also go over how to +[add new source files](#adding_source_files), +[libraries](#adding_libraries), +[unit tests](#adding_unit_tests), [executables](#adding_executables), and +[external dependencies](#adding_external_dependencies). -### Adding Libraries {#adding_libraries} - -To add a source file `FILE.cpp` that is compiled into a new library `LIB` in a -directory `src/PATH/DIR` (either in a new directory, or in an existing -directory that either does not have a `CMakeLists.txt` file, or does -not create a library in the existing `CMakeLists.txt`): -- Create (if necessary) a `CMakeLists.txt` file in `DIR`, with the following -two lines at the top: -``` -# Distributed under the MIT License. -# See LICENSE.txt for details. -``` -- In the parent directory (i.e. `src/PATH`), (if necessary) add the -following line to its `CMakeLists.txt` file (if necessary, recursively -do the previous step and this one until you reach a `CMakeLists.txt` that -adds the appropriate subdirectory): -``` -add_subdirectory(DIR) -``` -If there are already other `add_subdirectory()` lines in the file, place -the new one so that the subdirectories are in alphabetical order. -- Add the line: -``` -set(LIBRARY LIB) -``` -where convention is that `LIB` = `DIR`. As library names must be -unique, this is not always possible, in which case the convention is to -prepend the parent directory to `DIR`. -- Add the lines -``` -set(LIBRARY_SOURCES - FILE.cpp - ) +# Configuring -add_spectre_library(${LIBRARY} ${LIBRARY_SOURCES}) +The command to configure SpECTRE will look like this -target_link_libraries( - ${LIBRARY} - PUBLIC - - PRIVATE - - INTERFACE - - ) ``` -where each `` is an alphabetized list -of libraries of the form -``` - SomeLibrary - SomeOtherLibrary - YetAnotherLibrary +cmake -D FLAG1=OPT1 ... -D FLAGN=OPTN ``` -The libraries listed under `INTERFACE` are those included in at -least one `.hpp` file in `LIB` but never used in any `.cpp` files -in `LIB`. The libraries listed under `PRIVATE` are used in -at least one `.cpp` file in `LIB` but not in any `.hpp` file -in `LIB`. The libraries listed under `PUBLIC` are used in at -least one `.hpp` file and at least one `.cpp` file in `LIB`. -Note that a library counts as being used in a `.cpp` file if the -corresponding `.hpp` file includes it. In other words, list a dependency -as `PRIVATE` if it is needed only to compile the library, but not for -including headers. List a dependency as `INTERFACE` if it is not needed -to compile the library, but is needed for including headers. List a -dependency as `PUBLIC` if it is needed for both. - -## Adding Unit Tests {#adding_unit_tests} - -We use the [Catch](https://github.com/philsquared/Catch) testing -framework for unit tests. All unit tests are housed in `tests/Unit` -with subdirectories for each subdirectory of `src`. Add the `cpp` file -to the appropriate subdirectory and also to the `CMakeLists.txt` in -that subdirectory. Inside the source file you can create a new test by -adding a `SPECTRE_TEST_CASE("Unit.Dir.Component", -"[Unit][Dir][Tag]")`. The `[Tag]` is optional and you can have more -than one, but the tags should be used quite sparingly. The purpose of -the tags is to be able to run all unit tests or all tests of a -particular set of components, e.g. `ctest -L Data` to run all tests -inside the `Data` directory. Please see \ref writing_unit_tests -"writing unit tests", other unit tests and the [Catch -documentation](https://github.com/philsquared/Catch) for more help on -writing tests. Unit tests should take as short a time as possible, -with a goal of less than two seconds. Please also limit the number of -distinct cases (by using `SECTION`s). - -You can check the unit test coverage of your code by installing all the optional -components and then running `make unit-test-coverage` (after re-running CMake). -This will create the -directory `BUILD_DIR/docs/html/unit-test-coverage/` which is where the coverage -information is located. Open the `index.html` file in your browser and make -sure that your tests are indeed checking all lines of your code. Your pull -requests might not be merged until your line coverage is over 90% (we are aiming -for 100% line coverage wherever possible). Unreachable lines of code can be -excluded from coverage analysis by adding the inline comment `LCOV_EXCL_LINE` -or a block can be excluded using `LCOV_EXCL_START` and `LCOV_EXCL_STOP`. -However, this should be used extremely sparingly since unreachable code paths -should be removed from the code base altogether. -## Adding Executables {#adding_executables} +where `FLAG{1..N}` are CMake flags that are detailed in the section on +[commonly used CMake flags](#common_cmake_flags). -All general executables are found in `src/Executables`, while those -for specific evolution (elliptic) systems are found in -`src/Evolution/Executables` (`src/Elliptic/Executables`). See \ref -dev_guide_creating_executables "how to create executables". +CMake will look in your `$PATH` environment variable for all of the +[build dependencies](installation.html#build_dependencies) and will use the +first one it finds that satisfies the requirements. However, if a dependency is +not in your `$PATH`, there are multiple versions of a dependency, or you just +want to customize your configuration, you'll have to tell CMake which dependency +you want to use and where it is using CMake flags. To that end, even though the +[commonly used CMake flags](#common_cmake_flags) section has a more detailed +list of the flags available, the following list has the *most common* CMake +flags you'll need to customize your configuration (e.g. compilers, charm, build +type, and library types): -## Adding External Dependencies {#adding_external_dependencies} +- CMAKE_C_COMPILER +- CMAKE_CXX_COMPILER +- CMAKE_Fortran_COMPILER +- CHARM_ROOT +- CMAKE_BUILD_TYPE +- BUILD_SHARED_LIBS -To add an external dependency, first add a `SetupDEPENDENCY.cmake` -file to the `cmake` directory. You should model this after the -existing one for `Brigand` if you're adding a header-only -library and `yaml-cpp` if the library is not header-only. If CMake -does not already support `find_package` for the library you're adding -you can write your own. These should be modeled after `FindBrigand` -for header-only libraries, and `FindYAMLCPP` for compiled -libraries. The `SetupDEPENDENCY.cmake` file must then be included in -the root `spectre/CMakeLists.txt`. Be sure to test both that setting -`LIBRARY_ROOT` works correctly for your library, and also that if the -library is required that CMake fails gracefully if the library is not -found. +\note If you are on a cluster, take a look at the +[installation on clusters](installation_on_clusters.html) +instructions. If you are on a cluster we support, we will already have an +environment setup and an easy way for you to configure the build without having +to specify flags yourself. ## Commonly Used CMake flags {#common_cmake_flags} -The following are the most common flags used to control building with -`CMake`. They are used by -``` -cmake -D FLAG1=OPT1 ... -D FLAGN=OPTN -``` +The following are common flags used to control building SpECTRE with CMake (in +alphabetical order): - ASAN - Whether or not to turn on the address sanitizer compile flags (`-fsanitize=address`) (default is `OFF`) @@ -392,8 +286,15 @@ cmake -D FLAG1=OPT1 ... -D FLAGN=OPTN ## CMake targets -In addition to individual simulation executables, the following targets are -available to build with `make` or `ninja`: +To see all possible build targets, once you configure SpECTRE run + +``` +make list +``` + +This will be a long list of all libraries, test executables, simulation +executables, and custom build targets. The custom targets that are +available to build with `make` or `ninja` are: - unit-tests - Build unit tests, which you can run with `ctest -L unit`. Available if @@ -411,6 +312,148 @@ available to build with `make` or `ninja`: - Install targets that have been built to the `CMAKE_INSTALL_PREFIX`. Doesn't try to build anything else. +# Editing the build system + +\note When editing `CMakeLists.txt` files, it is conventional to +indent multiline commands by two spaces (except for the first line), +and to separate most commands by blank lines. + +## Adding Source Files {#adding_source_files} + +SpECTRE organizes source files into subdirectories of `src` that are +compiled into libraries. To add a new source file `FILE.cpp` to an +existing library in `src/PATH/DIR`, just edit +`src/PATH/DIR/CMakeLists.txt` and add `FILE.cpp` to the list of files +in +``` +set(LIBRARY_SOURCES + + ) +``` +such that the resulting `` is in alphabetical order. + +## Adding Libraries {#adding_libraries} + +To add a source file `FILE.cpp` that is compiled into a new library `LIB` in a +directory `src/PATH/DIR` (either in a new directory, or in an existing +directory that either does not have a `CMakeLists.txt` file, or does +not create a library in the existing `CMakeLists.txt`): +- Create (if necessary) a `CMakeLists.txt` file in `DIR`, with the following +two lines at the top: +``` +# Distributed under the MIT License. +# See LICENSE.txt for details. +``` +- In the parent directory (i.e. `src/PATH`), (if necessary) add the +following line to its `CMakeLists.txt` file (if necessary, recursively +do the previous step and this one until you reach a `CMakeLists.txt` that +adds the appropriate subdirectory): +``` +add_subdirectory(DIR) +``` +If there are already other `add_subdirectory()` lines in the file, place +the new one so that the subdirectories are in alphabetical order. +- Add the line: +``` +set(LIBRARY LIB) +``` +where convention is that `LIB` = `DIR`. As library names must be +unique, this is not always possible, in which case the convention is to +prepend the parent directory to `DIR`. +- Add the lines +``` +set(LIBRARY_SOURCES + FILE.cpp + ) + +add_spectre_library(${LIBRARY} ${LIBRARY_SOURCES}) + +target_link_libraries( + ${LIBRARY} + PUBLIC + + PRIVATE + + INTERFACE + + ) +``` +where each `` is an alphabetized list +of libraries of the form +``` + SomeLibrary + SomeOtherLibrary + YetAnotherLibrary +``` +The libraries listed under `INTERFACE` are those included in at +least one `.hpp` file in `LIB` but never used in any `.cpp` files +in `LIB`. The libraries listed under `PRIVATE` are used in +at least one `.cpp` file in `LIB` but not in any `.hpp` file +in `LIB`. The libraries listed under `PUBLIC` are used in at +least one `.hpp` file and at least one `.cpp` file in `LIB`. +Note that a library counts as being used in a `.cpp` file if the +corresponding `.hpp` file includes it. In other words, list a dependency +as `PRIVATE` if it is needed only to compile the library, but not for +including headers. List a dependency as `INTERFACE` if it is not needed +to compile the library, but is needed for including headers. List a +dependency as `PUBLIC` if it is needed for both. + +## Adding Unit Tests {#adding_unit_tests} + +We use the [Catch](https://github.com/philsquared/Catch) testing +framework for unit tests. All unit tests are housed in `tests/Unit` +with subdirectories for each subdirectory of `src`. Add the `cpp` file +to the appropriate subdirectory and also to the `CMakeLists.txt` in +that subdirectory. Inside the source file you can create a new test by +adding a `SPECTRE_TEST_CASE("Unit.Dir.Component", +"[Unit][Dir][Tag]")`. The `[Tag]` is optional and you can have more +than one, but the tags should be used quite sparingly. The purpose of +the tags is to be able to run all unit tests or all tests of a +particular set of components, e.g. `ctest -L Data` to run all tests +inside the `Data` directory. Please see \ref writing_unit_tests +"writing unit tests", other unit tests and the [Catch +documentation](https://github.com/philsquared/Catch) for more help on +writing tests. Unit tests should take as short a time as possible, +with a goal of less than two seconds. Please also limit the number of +distinct cases (by using `SECTION`s). + +You can check the unit test coverage of your code by installing all the optional +components and then running `make unit-test-coverage` (after re-running CMake). +This will create the +directory `BUILD_DIR/docs/html/unit-test-coverage/` which is where the coverage +information is located. Open the `index.html` file in your browser and make +sure that your tests are indeed checking all lines of your code. Your pull +requests might not be merged until your line coverage is over 90% (we are aiming +for 100% line coverage wherever possible). Unreachable lines of code can be +excluded from coverage analysis by adding the inline comment `LCOV_EXCL_LINE` +or a block can be excluded using `LCOV_EXCL_START` and `LCOV_EXCL_STOP`. +However, this should be used extremely sparingly since unreachable code paths +should be removed from the code base altogether. + +## Adding Executables {#adding_executables} + +All general executables are found in `src/Executables`, while those +for specific evolution (elliptic) systems are found in +`src/Evolution/Executables` (`src/Elliptic/Executables`). See \ref +dev_guide_creating_executables "how to create executables". + +## Adding External Dependencies {#adding_external_dependencies} + +To add an external dependency, first add a `SetupDEPENDENCY.cmake` +file to the `cmake` directory. You should model this after the +existing one for `Brigand` if you're adding a header-only +library and `yaml-cpp` if the library is not header-only. If CMake +does not already support `find_package` for the library you're adding +you can write your own. These should be modeled after `FindBrigand` +for header-only libraries, and `FindYAMLCPP` for compiled +libraries. The `SetupDEPENDENCY.cmake` file must then be included in +the root `spectre/CMakeLists.txt`. Be sure to test both that setting +`LIBRARY_ROOT` works correctly for your library, and also that if the +library is required that CMake fails gracefully if the library is not +found. + +# Dependencies + ## Checking Dependencies Getting dependencies of libraries correct is quite difficult. SpECTRE offers the @@ -424,8 +467,8 @@ source tree for more details on how to use them. ## Formaline SpECTRE's implementation of Formaline is based on, but distinct in -implementation from, the original design by -[Erik Schnetter and Christian Ott](https://github.com/hypercott/formaline), +implementation from, the +[original design](https://github.com/hypercott/formaline) which embeds an archive of the source tree into the executable. The original design creates a C/C++ file with a function that returns an array/vector of `char`s (a byte stream). However, this results in a very large source file (50MB diff --git a/docs/Installation/Installation.md b/docs/Installation/Installation.md index f514e4e4d309e..616c717bf4ad9 100644 --- a/docs/Installation/Installation.md +++ b/docs/Installation/Installation.md @@ -48,7 +48,7 @@ working development environment, a good place to start is our \subpage dev_guide_quick_start_docker_vscode. If you prefer setting up your development environment differently, read on! -### Dependencies +### Dependencies {#build_dependencies} **Note**: You don't need to install any of these dependencies by hand, or by using yum, apt, or other package managers; it is much easier diff --git a/docs/Main.md b/docs/Main.md index ab9c087eaea43..292ce78996d2d 100644 --- a/docs/Main.md +++ b/docs/Main.md @@ -80,7 +80,8 @@ accessed by links in the menu bar at the top. - For instructions on **installing SpECTRE** on personal computers and clusters consult the \ref installation "Installation" and \ref installation_on_clusters - "Installation on clusters" pages, respectively. + "Installation on clusters" pages, respectively. See the + \ref spectre_build_system "build system" page for how to configure SpECTRE. - If you are looking to **run simulations with SpECTRE** we recommend starting with the \ref tutorials "User Tutorials". The tutorials are designed to get users up and running with a simulation, as well as analyzing and visualizing