CMake for FleCSI client applications
The FleCSI installation provides multiple CMake files to support
writing new software. While the FleCSI
CMake package is used to
build software on top of FleCSI, the additional CMake files
provide common CMake code and macros for adding dependencies, building
documentation, unit-testing and other utilities that might be useful
for clients.
The CMake package is installed either when you build and install
FleCSI manually via CMake to CMAKE_INSTALL_PREFIX
or when using a
Spack installation.
If you installed FleCSI in a Spack environment the necessary environment variables will be automatically set.
After manual compilation and installation of FleCSI via CMake, you will
have to prepend the installation prefix to the CMAKE_PREFIX_PATH
environment variable to make it available.
export CMAKE_PREFIX_PATH=/path/to/your/flecsi/install:$CMAKE_PREFIX_PATH
FleCSI CMake files
FleCSI-based applications often need common CMake code to enable
features and/or add dependencies. The FleCSI
package also exposes
utility CMake files that are meant to be included in new projects. It
does so by adding its installation parent folder to the CMake’s search
path when you add the package:
find_package(FleCSI REQUIRED)
Once added, you can include
the CMake files provided by this
package.
For example, if you want to use the provided documentation.cmake
,
you can add it as follows:
include(FleCSI/documentation)
Documentation
FleCSI uses both Sphinx and Doxygen for its documentation system. The following CMake files can be included to utilize the same documentation system for your own projects.
FleCSI/documentation
Adds the
flecsi_set_doc_target_name(target)
macro, which is used to define the name of a generic documentation targetFLECSI_DOC_TARGET
. This target collects and runs all other later defined documentation targets. If no name is set, it defaults todoc
. This target itself is created during the first call of eitherflecsi_add_doxygen_target
orflecsi_add_sphinx_target
.This file also adds the
flecsi_add_doc_deployment()
function. It takes two parameters: the target name andGITHUB_PAGES_REPO
which is a Git repository URL. Running the target checks out thegh-pages
branch of that repository, clears it and puts the result of all documentation targets into it. Files are only added, but not committed or pushed. These are left as manual steps.FleCSI/sphinx
Adds the
flecsi_set_sphinx_target_name
macro, which is used to define the name of a generic Sphinx targetFLECSI_SPHINX_TARGET
. This target collects and runs all other later defined Sphinx targets. If no name is set, it defaults tosphinx
. The target itself is created during the first call offlecsi_add_sphinx_target
.Sphinx builds are defined with the
flecsi_add_sphinx_target
function. It takes three parameters: the target name, which will be prefixed with${FLECSI_SPHINX_TARGET}-
, aCONFIG
directory, andOUTPUT
directory. The providedCONFIG
directory must contain aconf.py.in
file. This template will be processed withconfigure_file
to produce the final Sphinx configuration fileconf.py
. This configuration file as well as the_static
and_templates
directories will be copied to theOUTPUT
directory, where the target will be built.Usage:
include(FleCSI/documentation) include(FleCSI/sphinx) flecsi_set_doc_target_name(mydoc) flecsi_set_sphinx_target_name(mysphinx) flecsi_add_sphinx_target(main # custom target name CONFIG ${CMAKE_SOURCE_DIR}/doc/sphinx # folder containing conf.py.in OUTPUT ${CMAKE_BINARY_DIR}/doc # output directory ) flecsi_add_doc_deployment(deploy-docs GITHUB_PAGES_REPO git@github.com:flecsi/flecsi.git) # the following targets will be defined: # - mydoc # - mysphinx # - mysphinx-main # - deploy-docs
FleCSI/doxygen
Adds the
flecsi_set_doxygen_target_name
macro, which is used to define the name of a generic Doxygen targetFLECSI_DOXYGEN_TARGET
. This target collects and runs all other later defined Doxygen targets. If no name is set, it defaults todoxygen
. The target itself is created during the first call offlecsi_add_doxygen_target
.Doxygen builds are defined with the
flecsi_add_doxygen_target
function. It takes two parameters: the target name, which will be prefixed with${FLECSI_DOXYGEN_TARGET}-
, and one or more file names inCONFIGS
. Each of the configuration files will be processed withconfigure_file
. The final output location is controlled by what is defined in these configuration files. E.g. by definingOUTPUT_DIRECTORY
relative to theCMAKE_BINARY_DIR
:OUTPUT_DIRECTORY = @CMAKE_BINARY_DIR@/doc/api
See
doc/doxygen/conf.in
in the FleCSI source repository as an example configuration.
Coverage and Unit Testing
FleCSI uses its own unit-testing framework and installs the necessary CMake files to allow using it in your own applications.
FleCSI/coverage
Adds the
flecsi_enable_coverage
macro, which adds compiler and linker flags to enable capturing coverage information.FleCSI/unit
Adds the
flecsi_enable_testing
macro, which turns on CMake’s testing capabilities throughctest
and adds atest
target.The
test
target will runctest
, executing all added tests.While you can define your own test executables manually with add_test, this CMake file also defines its own
flecsi_add_test
andflecsi_add_target_test
functions.flecsi_add_test
is for writing tests based on FleCSI Unit Test framework and has the following signature:flecsi_add_test(test-name # name of test and target SOURCES src1 src2 ... srcN # list of source files LIBRARIES lib1 lib2 ... libN # libraries linked to test target DEFINES define1 define2 ... defineN # defines added to test target INPUTS in1 in2 ... inN # list of input files ARGUMENTS arg1 arg2 ... argN # command arguments TESTLABELS label1 label2 ... labelN # labels added to test target PROCS nprocs1 nprocs2 ... nprocsN # number(s) of MPI processes LAUNCHER app # launcher application for entire command-line LAUNCHER_ARGUMENTS arg1 ... argN # arguments passed to launcher )
flecsi_add_test
will take the sources files inSOURCES
and compile them together with a predefinedmain()
function. It will link to FleCSI and any specifiedLIBRARIES
, and addDEFINES
as compile definitions.If the test uses input files, they can be specified as list of files in
INPUTS
. This ensures they are copied to the execution folder of the test.The
ARGUMENTS
option can be used to supply command-line options interpreted byflecsi::getopt
.You can also control the number of MPI processes with
PROCS
. If you provide more than one value inPROCS
, this will define one test per value with a name<test-name>_<value>
.Note
Tests added with
flecsi_add_test
will be run with GPU support if appropriate.The final command-line of each test is assembled from these arguments into the following format:
${MPIEXEC_EXECUTABLE} ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG} ${PROCS} ${TARGET} ${MPIEXEC_POSTFLAGS} ${BACKEND_ARGUMENTS} ${ARGUMENTS}
The
MPIEXEC_*
cache variables are defined via the CMake FindMPI module, whileBACKEND_ARGUMENTS
are defaults provided for each FleCSI backend.In some cases you may wish to pass this entire command-line to a launcher command along with some launcher specific arguments. A typical application of this is a wrapper that executes the command-line, captures relevant information and presents some analysis result. This can be achieved via the
LAUNCHER
andLAUNCHER_ARGUMENTS
options and turns the complete test command-line into:${LAUNCHER} ${LAUNCHER_ARGS} ${FULL_TEST_COMMAND_LINE}
TESTLABELS
can be added to your test to allow filtering based on label when usingctest
.The first of these tests creates a
unit_tests
target which collects all of the unit tests defined viaflecsi_add_test
. Using this target will build all of these tests and their dependencies.Its name can be customized with the
flecsi_set_unit_tests_target_name(name)
macro, prior to callingflecsi_enable_testing
.flecsi_add_target_test
allows defining a test using an existing target. This is useful for defining regression/run tests of complete FleCSI applications. The function signature is similar toflecsi_add_test
and supports all its operations, but doesn’t useSOURCES
,LIBRARIES
andDEFINES
. Instead, it requires the name of an existing target. By default, it will look for a target with the same name as the test name. A target with a different name can be specified via the TARGET option. Given that these tests typically are not unit tests, they are not automatically added to theunit_tests
target as dependencies.flecsi_add_target_test(test-name # name of test (and of existing target) TARGET name # name of an existing target INPUTS in1 in2 ... inN # list of input files ARGUMENTS arg1 arg2 ... argN # command arguments TESTLABELS label1 label2 ... labelN # labels added to test target PROCS nprocs1 nprocs2 ... nprocsN # number(s) of MPI processes LAUNCHER app # launcher application for entire command-line LAUNCHER_ARGUMENTS arg1 ... argN # arguments passed to launcher )
Usage:
Here is an example unit test file
mytest.cc
:#include <flecsi/data.hh> #include <flecsi/utilities.hh> using namespace flecsi; template<typename T> using single = field<T, data::single>; const single<int>::definition<topo::index> ifield; void init(single<int>::accessor<wo> iv, int v) { iv = v / 39; } int verify(single<int>::accessor<ro> iv) { UNIT() { ASSERT_EQ(iv, 42); }; } int mytest_driver() { UNIT() { topo::index::slot my_topology; my_topology.allocate(4); execute<init>(ifield(my_topology), 1669); EXPECT_TRUE(true); EXPECT_EQ(test<verify>(ifield(my_topology)), 0); }; } // mytest_driver util::unit::driver<mytest_driver> driver;
Which can be compiled with the following
CMakeLists.txt
:cmake_minimum_required(VERSION 3.20) project(myproject LANGUAGES CXX C) set(CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 17) find_package(FleCSI REQUIRED) include(FleCSI/unit) flecsi_enable_testing() flecsi_add_test(mytest SOURCES mytest.cc)
To configure and compile:
mkdir build cd build cmake .. make
Once compiled, you can run the tests with:
make test # OR ctest
Code Formatting
FleCSI/format
Adds the
flecsi_enable_format
macro, which takes a requiredclang-format
version as parameter.It defines a
format
target that depends on bothgit
andclang-format
to be present. It also requires the source tree to be a Git checkout. Running this target will find all.hh
and.cc
files and apply the style defined in the project’s.clang-format
.
Dependencies
Some projects might want to explicitly link to dependencies that FleCSI uses itself. External libraries used by FleCSI are added via their own CMake file and the macros they define.
The general structure in these files is that they add a
flecsi_enable_<PACKAGE>
macro, which adds the necessary defines,
include folders and libraries to a given target.
FleCSI/hdf5
FleCSI/hpx
FleCSI/kokkos
FleCSI/legion
FleCSI/mpi
FleCSI/openmp
FleCSI/parmetis
FleCSI/boost
FleCSI/caliper
Other files
FleCSI/colors
Defines several ASCII color codes for colored console output.
FLECSI_ColorReset
FLECSI_ColorBold
FLECSI_Red
FLECSI_Green
FLECSI_Yellow
FLECSI_Brown
FLECSI_Blue
FLECSI_Magenta
FLECSI_Cyan
FLECSI_White
FLECSI_BoldGrey
FLECSI_BoldRed
FLECSI_BoldGreen
FLECSI_BoldYellow
FLECSI_BoldBlue
FLECSI_BoldMagenta
FLECSI_BoldCyan
FLECSI_BoldWhite
FleCSI/summary
Defines multiple macros to generate a (colored) configuration summary. Each of these macros appends to the global
_summary
. At the end of your CMake file you can then print this summary usingmessage(STATUS ${_summary})
.flecsi_summary_header
will add a header.flecsi_summary_info(name info allow_split)
will take a givenname
and add its valueinfo
next to it. Ifinfo
is a space-separated list of values,allow_split
controls if each value should be in its own line.flecsi_summary_option(name state extra)
is used for adding Boolean values to the summary. Ifstate
evaluates toTRUE
the option state will be shown in a bright green color, followed by what is inextra
. Otherwise, thestate
will be shown in gray.