System · CMake Flags, Expressions, Debug Tricks

Jul 21, 2024 | Tech Software

Preface

I frequently use certain CMake flags, expressions, and debug tricks, but sometimes I forget their meanings or distinctions. To save myself from repeatedly searching on Google or StackOverflow, I'm compiling a list of these commonly used ones in this post for quick reference.

Useful command line arguments

For more information, see CMake's official documentation, some useful ones are listed below.

Flag Function
--debug-find Debug find_package
--trace Track CMake execution process
--trace-expand Track and expand variables and expressions
--warn-unused-vars Warn about unused variables
--log-level=DEBUG Set log level to ERROR, WARNING, NOTICE, STATUS(default), VERBOSE, DEBUG, or TRACE.
--graphviz=foo.dot Generate a dependency graph and save to file foo.dot, which can be visualized by graphviz tools
--profiling-output Generate a performance analysis file
--fresh Clear cache and reconfigure

The add_library with STATIC, SHARED, INTERFACE

The add_library with ALIAS

The target_link_libraries and target_include_directories with PUBLIC, SHARED, INTERFACE

According to CMake.org:

Libraries and targets following PUBLIC are linked to, and are made part of the link interface. Libraries and targets following PRIVATE are linked to, but are not made part of the link interface. Libraries following INTERFACE are appended to the link interface and are not used for linking target.

Which is a bit opaque. So, in layman's terms:

The target_include_directories with SYSTEM

If SYSTEM is specified, the compiler will be told the directories are meant as system include directories on some platforms. This may have effects such as suppressing warnings or skipping the contained headers in dependency calculations. Additionally, system include directories are searched after normal include directories regardless of the order specified. If SYSTEM is used together with PUBLIC or INTERFACE, the INTERFACE_SYSTEM_INCLUDE_DIRECTORIES target property will be populated with the specified directories.

The target_include_directories with $<BUILD_INTERFACE:>, $<INSTALL_INTERFACE:>

Include directories usage requirements commonly differ between the build-tree and the install-tree, for example, some test headers, generated code headers are only needed for building, no need to install them. The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions can be used to describe separate usage requirements based on the usage location.

Note that:

  • relative paths are allowed within the INSTALL_INTERFACE expression and are interpreted as relative to the installation prefix;
  • relative paths should NOT be used in BUILD_INTERFACE expressions because they will not be converted to absolute;
  • vendor cannot know where clients install the package, so INSTALL_INTERFACE should use relative path to help clients generate the absolute paths with some prefix specified by clients.

You can include directories with generator expression above one by one, or you can use list variable format as follows.

I prefer the first fashion since it's easier for cmake-format to break long lines (when you list goes too long), so you code doesn't contain over-sized lines that look very awkward. You can also do something like below to make the code more cmake-format-friendly.

The install and configure_file

For the package to be used by clients via CMake with find_package, below are some typically steps.

Find package debug tricks

When you need to find how to link against a package found by find_package(qpOASES REQUIRED) for example, you can add in your CMakeLists.txt the following.

Then, you can run cmake .. --debug-find for example, and the last section of the output will look like something below.

With the cmake config file found, you can look into /usr/local/lib/cmake/qpOASES/qpOASESConfig.cmake for example and see how variables are defined and how to link against and include them.