Meson

Author

Lars Pastewka

Introduction

Meson is a tool that helps with compilation of C/C++ of more than just a few standalone files. We have seen in “Organizing code in C++” that compiling C++ files is usually done in two stages, the creation of object files and the linking of those objects. Meson will generate these compilation steps for you, provided you give it the right information about your project. In addition, Meson has the following advantages:

  • Cross-platform: the workflow to compile Meson project is identical accross platforms, Meson will automatically identify the relevant compilers, dependencies, etc., to use for your particular platform.
  • It correctly handles library dependencies: these can be hard to setup manually, especially in high-performance cluster environments.
  • Many IDEs recognize Meson projects: among them CLion and VScode.

Adding subdirectories with separate executables

For organizing your milestone codes, it can be useful to have seperate main.cpp files in seperate subdirectories that correspond to each milestone. A possible directory structure could look like this:

milestones/
  meson.build
  01/
    meson.build
    main.cpp
  ...
  04/
    meson.build
    main.cpp
    lj54.xyz
  ...

Each subdirectory contains a meson.build that tells Meson what to do. You can tell Meson to add a subdirectory using the subdir command. The toplevel meson.build requires an additional statement

subdir('milestones')

and meson.build in the milestones subdirectory looks as follows:

subdir('01')
subdir('02')
subdir('03')
...

In each of the milestone directories we need to tell Meson to compile an executable and that main.cpp (in this directory) contains the main function. Additionally, it is useful to tell Meson about dependent files, e.g. the file lj54.xyz that is required to execute Milestone 04. The corresponding meson.build looks like this:

executable(
  'milestone04',
  'main.cpp',
  include_directories : [md_incdirs],
  link_with : [md_lib],
  dependencies : [eigen, mpi]
)

fs = import('fs')
fs.copyfile('lj54.xyz')

The statement executable contains all source and headers files required to compile the code. The variables eigen and mpi are defined in the toplevel meson.build and can be used here.

In CLion, these additional executables should show up as build targets:

Debug vs. release builds

By default, CLion (and Meson) will configure debug builds. These builds are useful for development purposes, but their performance can be terrible. For running longer calculations it is useful to switch to a release build. This behavior is controlled by the --buildtype= option of the Meson build system. From the command line, it can be set by executing

meson setup builddir --buildtype=debug

In CLion, you can configure this in the menu option File->Settings->Build, Execution, Deployment->Meson. You should see the following dialog:

Add the build type to Setup options.

Kokkos

Warning

You need at least Meson 1.8.0 for the below instructions to work. Versions earlier than Meson 1.3.0 do not support CMake subprojects; see release notes for 1.3.0. Additionally, older version of Meson have issues with the compilers that come with the NVIDIA HPC SDK.

To install Kokkos as a dependency, create a subprojects directory and place the following file in it

[wrap-git]
url = https://github.com/kokkos/kokkos.git
revision = 4.6.01
depth = 1
method = cmake

[provide]
kokkoscore = kokkoscore_dep
kokkosalgorithms = kokkosalgorithms_dep
```meson
You can then use
```meson
kokkoscore = dependency('kokkoscore')

to define Kokkos as dependency of your code. Our C++ skeleton has this already set up.

If you want to enable or disable specific features of Kokkos, use the following Meson configuration

# Configure Kokkos
cmake = import('cmake')
kokkos_options = cmake.subproject_options()
kokkos_options.add_cmake_defines({
  'Kokkos_ENABLE_SERIAL': true, # Serial execution
  'Kokkos_ENABLE_THREADS': true, # Threads
  'Kokkos_ENABLE_OPENMP': false, # OpenMP support
  'Kokkos_ENABLE_CUDA': false, # CUDA support
#  'Kokkos_ARCH_AMPERE80': true, # Specify NVIDIA hardware architecture
  'Kokkos_ENABLE_HIP': false, # HIP support
})
kokkos = cmake.subproject('kokkos', options: kokkos_options)

# Get dependencies
kokkoscore = kokkos.dependency('kokkoscore')

The options specified with add_cmake_defines are passed to the Kokkos CMake project. The available compile options are listed in the Kokkos documentation.

Note that you need to tell Kokkos about the specific hardware architecture. Kokkos has architecture-specific keywords compile options for this. The above example shows the option for A100 GPUs (“AMPERE80”).

Upgrading Meson

Meson is written in Python. The easiest way to upgrade Meson is through a pip install. On Ubuntu, you need to make sure pip and venv are installed:

apt install python3-pip python3-venv

Create a virtual environment in your home directory

python3 -m venv ~/venv

Activate it and install Meson into It

source ~/venv/bin/activate
python3 -m pip install --upgrade Meson

This will bump you to the latest Meson version. Note that you need to always activate the venv when you open a new shell.