Skip to content

Start

Use FairMQ in a CMake project

FairMQ installs a CMake package. Your project finds it with find_package(FairMQ) and links its programs to the imported target FairMQ::FairMQ. This page shows a complete project, the targets and the variables of the package, and the problems that can occur.

This project builds one device program. Make a folder with two files:

  • Directoryhello/
    • CMakeLists.txt
    • hello.cxx
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(Hello LANGUAGES CXX)
find_package(FairMQ 1.11 REQUIRED)
# FairMQConfig.cmake does not find the dependencies of FairMQ. Find them here.
foreach(dep IN LISTS FairMQ_PACKAGE_DEPENDENCIES)
find_package(${dep} ${FairMQ_${dep}_VERSION} REQUIRED COMPONENTS ${FairMQ_${dep}_COMPONENTS})
endforeach()
add_executable(hello hello.cxx)
target_link_libraries(hello PRIVATE FairMQ::FairMQ)
hello.cxx
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
#include <memory>
struct Hello : fair::mq::Device
{
bool ConditionalRun() override
{
LOG(info) << "Hello from " << GetId();
return false;
}
};
void addCustomOptions(boost::program_options::options_description&) {}
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions&)
{
return std::make_unique<Hello>();
}

Configure and build the project, and run the program:

Terminal window
cmake -S hello -B hello/build -DCMAKE_PREFIX_PATH="$HOME/fairmq_install"
cmake --build hello/build
hello/build/hello --id hello1 --control static

The device logs Hello from hello1. Then ConditionalRun() returns false, and the device leaves the state RUNNING. In the control mode static, the device then goes to EXITING, and the program ends. The device has no channels, so it also logs the warning No channels created after finishing initialization.

Your first device explains the code of a device.

find_package(FairMQ 1.11 REQUIRED)

The version is a minimum. The package accepts each installed version that is equal to it or newer, also a newer major version. You can also omit the version.

The package is in the folder lib/cmake/FairMQ-<version>/ of the installation prefix. On some systems, the folder is lib64/ instead of lib/. The folder contains FairMQConfig.cmake, FairMQConfigVersion.cmake and the files FairMQTargets*.cmake, which define the imported targets.

If FairMQ is not in a system directory, tell CMake where it is. Use one of these ways:

  • -DCMAKE_PREFIX_PATH=<prefix> gives the installation prefix. For more prefixes, separate them with ;.
  • The environment variable CMAKE_PREFIX_PATH also gives prefixes. On Linux, separate them with :. spack load fairmq and an active Spack environment set this variable.
  • -DFairMQ_ROOT=<prefix> gives the prefix of FairMQ only.
  • -DFairMQ_DIR=<prefix>/lib/cmake/FairMQ-1.11.0 gives the folder that contains FairMQConfig.cmake.
  • In your CMakeLists.txt, add a prefix with list(PREPEND CMAKE_PREFIX_PATH /path/to/fairmq_install) before find_package().

FairMQConfig.cmake does not find the dependencies of FairMQ. But the target FairMQ::FairMQ refers to targets of its dependencies, for example FairLogger::FairLogger and Boost::program_options. Your project must find these packages, or CMake stops with an error (see Problems that can occur).

The package gives the list of the dependencies, with the minimum versions and the components:

  • FairMQ_PACKAGE_DEPENDENCIES is the list, for example Threads FairLogger Boost. It can also contain the dependencies of FairLogger, for example fmt.
  • FairMQ_<dep>_VERSION is the minimum version of the dependency <dep>, for example FairMQ_Boost_VERSION.
  • FairMQ_<dep>_COMPONENTS is the list of the components of <dep>, for example FairMQ_Boost_COMPONENTS.

The loop in the minimal project finds each dependency with these values. Put the loop after find_package(FairMQ). Use the installations of the dependencies that FairMQ was built with.

If your project uses FairCMakeModules, its module FairFindPackage2 can do the same work:

find_package(FairCMakeModules 0.2 REQUIRED)
include(FairFindPackage2)
find_package2(PRIVATE FairMQ VERSION 1.11 REQUIRED)
find_package2_implicit_dependencies()

find_package2_implicit_dependencies() finds the dependencies of all packages that your project found with find_package2(). This way needs an installed FairCMakeModules. The bundled copy that the FairMQ build uses is not part of the FairMQ installation.

Target What it is
FairMQ::FairMQ The library libfairmq. Link your programs to this target.
FairMQ::fairmq-bsampler, FairMQ::fairmq-merger, FairMQ::fairmq-multiplier, FairMQ::fairmq-proxy, FairMQ::fairmq-sink, FairMQ::fairmq-splitter The built-in devices.
FairMQ::fairmq-shmmonitor The tool fairmq-shmmonitor.
FairMQ::fairmq-uuid-gen The tool fairmq-uuid-gen.
FairMQ::fairmq-tidy The tool fairmq-tidy. Only in an installation that was built with BUILD_TIDY_TOOL=ON.

Use the targets of the programs in custom commands and tests. For example, $<TARGET_FILE:FairMQ::fairmq-sink> gives the path of fairmq-sink.

  • Include directories. <prefix>/include and <prefix>/include/fairmq. Include the headers as fairmq/<Name>.h, for example #include <fairmq/Device.h>.
  • C++17. The target has the compile feature cxx_std_17. CMake compiles your target with C++17 or a later standard.
  • Compile definitions. BOOST_ERROR_CODE_HEADER_ONLY, BOOST_ASIO_HAS_HAS_STD_CHRONO, and FAIRMQ_HAS_STD_FILESYSTEM and FAIRMQ_HAS_STD_PMR with the value 0 or 1. An installation with FAIRMQ_DEBUG_MODE=ON adds FAIRMQ_DEBUG_MODE. An installation with FAIRMQ_CHANNEL_DEFAULT_AUTOBIND adds FAIRMQ_CHANNEL_DEFAULT_AUTOBIND with the value true or false.
  • Libraries. FairLogger::FairLogger, Boost::boost, Boost::container, Boost::program_options, Boost::filesystem, Boost::regex, Threads::Threads, dl, and rt on Linux.

ZeroMQ and PicoSHA2 are private dependencies of libfairmq. Your project does not find or link them.

After find_package(FairMQ), these variables are set:

Variable Value
FairMQ_VERSION The version, for example 1.11.0.
FairMQ_GIT_VERSION The output of git describe --tags --dirty --match "v*" at build time, without the v. For example 1.11.0, or 1.11.0-4-g1a2b3c4 for a commit after the tag.
FairMQ_GIT_DATE The date of the last commit at build time (git log -1 --format=%cd). The value is a CMake list: CMake splits the date at the spaces.
FairMQ_VERSION_HOTFIX Empty for a version with three numbers, for example 1.11.0.
FairMQ_PREFIX The installation prefix.
FairMQ_BINDIR The folder of the programs, <prefix>/bin.
FairMQ_INCDIR The folder of the headers, <prefix>/include.
FairMQ_LIBDIR The folder of the library, for example <prefix>/lib.
FairMQ_DATADIR <prefix>/share/fairmq.
FairMQ_CMAKEMODDIR <prefix>/share/fairmq/cmake, the folder of FindZeroMQ.cmake, and of FairMQTidy.cmake if the build had BUILD_TIDY_TOOL=ON.
FairMQ_BUILD_TYPE The CMAKE_BUILD_TYPE of the FairMQ build, for example Release.
FairMQ_BUILD_TYPE_UPPER The same value in upper case, for example RELEASE.
FairMQ_CXX_FLAGS The CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_<BUILD_TYPE> of the FairMQ build, as a CMake list.
FairMQ_PACKAGE_DEPENDENCIES The public dependencies, see Find the dependencies of FairMQ.
FairMQ_<dep>_VERSION The minimum version of the dependency <dep>.
FairMQ_<dep>_COMPONENTS The components of the dependency <dep>.
FairMQ_<component>_FOUND TRUE for each component that the FairMQ build had. See Components.

find_package(FairMQ) also puts FairMQ_CMAKEMODDIR at the front of CMAKE_MODULE_PATH. Then include(FairMQTidy) finds the module of FairMQ.

For all build options of FairMQ, see CMake options and variables.

The package has these components. A component is present only if the FairMQ build had it:

Component Build option of FairMQ What it contains
fairmq BUILD_FAIRMQ (default ON) The library, the built-in devices and the tools.
tests BUILD_TESTING (default OFF) The tests. They are not installed.
examples BUILD_EXAMPLES (default ON) The examples and their start scripts.
tidy_tool BUILD_TIDY_TOOL (default OFF) The tool fairmq-tidy and the module FairMQTidy.cmake.

To require a component, give it to find_package():

find_package(FairMQ 1.11 REQUIRED COMPONENTS tidy_tool)

If the component is missing, CMake stops. The message says that FairMQConfig.cmake set FairMQ_FOUND to FALSE.

An installation with the component tidy_tool gives the CMake function fairmq_target_tidy(). It runs fairmq-tidy on the source files of a target:

CMakeLists.txt
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(FairMQ 1.11 REQUIRED COMPONENTS tidy_tool)
# ... the loop over FairMQ_PACKAGE_DEPENDENCIES, add_executable(hello hello.cxx) ...
include(FairMQTidy)
fairmq_target_tidy(TARGET hello)

The function adds the target fairmq-tidy-hello to the default build. After CMake builds hello, it runs fairmq-tidy on each .cxx and .cpp file of hello. fairmq-tidy reads the compile commands from compile_commands.json in the build directory.

Argument What it does
TARGET <target> The target to check. Required.
EXTRA_ARGS <arg> One more argument for fairmq-tidy. With GCC, do not use it: the function adds its own argument, and two arguments break the command. This is a known defect.
CLANG_EXECUTABLE <clang> The program clang. If your compiler is GCC, the function runs clang -print-resource-dir to find the Clang headers. Without this argument, it uses the target clang if it exists, or clang from PATH.

The function needs CMAKE_EXPORT_COMPILE_COMMANDS set to ON. If it is not ON, the function writes a warning and adds no target. See Check code with fairmq-tidy for the checks and the output.

The supported way is the one on this page: build FairMQ, install it, and find the installation with find_package(FairMQ). The CMake code of FairMQ does not support a build tree, add_subdirectory() or FetchContent.

Way Works Reason
find_package(FairMQ) of an installation Yes The installation contains the targets file.
find_package(FairMQ) of a build tree No The build tree has no targets file. See The build tree.
add_subdirectory() of a FairMQ source tree No FairMQ must be the top-level project. See add_subdirectory() and FetchContent.
FetchContent No FetchContent_MakeAvailable() calls add_subdirectory().
ExternalProject_Add() Yes, in two steps FairMQ is the top-level project of its own CMake run. See ExternalProject.

The configure step writes FairMQConfig.cmake and FairMQConfigVersion.cmake to the top of the build directory. But no CMake file of FairMQ calls export(), so the build directory has no FairMQTargets.cmake. FairMQConfig.cmake includes this file with a path for the layout of an installation, relative to its own folder. For a build directory, this path does not exist.

If FairMQ_DIR or CMAKE_PREFIX_PATH points to a build directory, find_package(FairMQ) stops with include could not find requested file and the path of FairMQTargets.cmake. Install FairMQ into a prefix (see Install), and give this prefix to your project.

The CMake code of FairMQ uses CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR for its own source and build directories. These variables always give the directories of the top-level project. When your project adds FairMQ with add_subdirectory(), they give the directories of your project. The configure step stops at the first use, in line 14 of the top-level CMakeLists.txt of FairMQ. For a FairMQ source in the folder fairmq/ of your project, the error is:

CMake Error at fairmq/CMakeLists.txt:14 (include):
include could not find requested file:
GitHelper

CMakeLists.txt looks for its modules in ${CMAKE_SOURCE_DIR}/cmake. If your project adds this folder to CMAKE_MODULE_PATH, the configure step stops at a later use. These uses also depend on the top-level directories:

  • cmake/GitHelper.cmake reads the version with git describe in CMAKE_SOURCE_DIR, and only if ${CMAKE_SOURCE_DIR}/.git exists. The version then comes from the Git repository of your project, or it is 0.0.0.0.
  • cmake/FairMQBundlePackageHelper.cmake looks for the bundled packages in ${CMAKE_SOURCE_DIR}/extern/.
  • cmake/FairMQPackage.cmake reads ${CMAKE_SOURCE_DIR}/cmake/FairMQConfig.cmake.in.
  • fairmq/CMakeLists.txt writes Version.h to ${CMAKE_BINARY_DIR}/fairmq/, and adds CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR to the include directories of the library.
  • The tests and the examples look for the programs of FairMQ in ${CMAKE_BINARY_DIR}/fairmq/.

The build also has no target FairMQ::FairMQ. The library target is FairMQ. Only the installed package gives it the namespace FairMQ::.

FetchContent_MakeAvailable(FairMQ) adds the downloaded source with add_subdirectory(). Thus it stops with the same error. This is true for a Git clone (GIT_REPOSITORY) and for a release archive (URL). In your build directory, the error names the file _deps/fairmq-src/CMakeLists.txt.

A release archive from GitHub has no .git folder, and the folders of the Git submodules in extern/ are empty. A standalone build of such an archive gets the version 0.0.0.0. If FairCMakeModules is not installed, its configure step stops when it tries to build the bundled copy: git submodule update fails with fatal: not a git repository. The log is extern/FairCMakeModules/build.log in the build directory. Use a Git clone with the tags (see Install).

ExternalProject_Add() configures, builds and installs FairMQ at the build time of your project, in a CMake run of its own. FairMQ is then the top-level project, and a Git clone gets the version from its tags:

CMakeLists.txt
include(ExternalProject)
ExternalProject_Add(FairMQ
GIT_REPOSITORY https://github.com/FairRootGroup/FairMQ
GIT_TAG v1.11.0
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/fairmq_install
)

Give the options of the FairMQ build in CMAKE_ARGS, for example the prefixes of the dependencies (see Dependencies in other directories).

The installation exists only after the build step. find_package() runs at configure time, so the same CMake run cannot find this installation (CMake behavior). Put the programs that use FairMQ into a separate CMake project. Configure it after the install step, for example as a second ExternalProject_Add() with DEPENDS FairMQ. Give it the prefix of the installation in CMAKE_PREFIX_PATH.

  • Could not find a package configuration file provided by "FairMQ". CMake does not find the installation. Give the installation prefix with CMAKE_PREFIX_PATH, or the package folder with FairMQ_DIR.
  • Could not find a configuration file for package "FairMQ" that is compatible with requested version. The installed version is older than the version in find_package(). The message shows each package that CMake found, with its version. The version 0.0.0.0 comes from a FairMQ build without the git tags (see Install).
  • The link interface of target "FairMQ::FairMQ" contains: … but the target was not found. Your project did not find the dependencies of FairMQ. The message names a target of a dependency, for example FairLogger::FairLogger. Add the loop over FairMQ_PACKAGE_DEPENDENCIES after find_package(FairMQ).
  • CMake does not find a dependency in the loop. Add the installation prefix of the dependency to CMAKE_PREFIX_PATH.
  • include could not find requested file: with the path of FairMQTargets.cmake. FairMQ_DIR or CMAKE_PREFIX_PATH points to a build directory of FairMQ. Give the installation prefix. See The build tree.
  • include could not find requested file: GitHelper. Your project adds FairMQ with add_subdirectory() or FetchContent. FairMQ must be a top-level project. See Other ways to add FairMQ.
  • CMAKE_EXPORT_COMPILE_COMMANDS is not enabled. Skipping. Set CMAKE_EXPORT_COMPILE_COMMANDS to ON before you call fairmq_target_tidy().