Jump to content

Guidelines and HOWTOs/CMake/FAQs

From KDE Community Wiki

Can I safely change the cmake_minimum_required version?

Maybe.

Your two main considerations, of course, are that if you set it to a too-recent version, your users will not have a recent enough CMake (especially if they are using the one provided by their Linux distribution), and that if you set it to a too-old version, you won't be able to use new features.

Bear in mind that you may be able to optionally use new features by doing something like

if (NOT CMAKE_VERSION VERSION_LESS 3.0)
  # do stuff that requires CMake 3.0 or later
endif()

However, cmake_minimum_required also sets some CMake Policies to NEW, changing CMake's behaviour in some corner cases. Normally, CMake should have been warning you about these Policies if you have done something that would be affected by them, so you if don't get any warnings when you build with CMake version X or later, you should be safe to set the minimum required version to X.

Why isn't find_package working?

If a find_package call isn't finding something you think it should, there are a few things to check. First, the obvious things:

  • Was the package name spelled correctly? Case is important!
  • Do you have the right version installed?

Of course, it may not be obvious what the "correct" spelling of the package name is, especially when it comes to upper- or lower-case letters.

At this point, it is useful to know what a find_package call actually does. The CMake documentation contains a complete description, but it is long and rather daunting. So here is a simplified description.

find_package has two ways of finding the information it needs. The first method is called the module search. If you do find_package(Foo), it progresses like this:

  • CMake searches for a file called FindFoo.cmake in the same places it looks for files when you use the include command (the entries in CMAKE_MODULE_PATH followed by the CMake installation).
  • It sets some variables describing what you are looking for (such as what version you want).
  • CMake effectively includes the FindFoo.cmake file, as though you had copied the text in place of the find_package call.
  • After this, it unsets the variables it set at the start, but any variables set by the FindFoo.cmake file remain (which is how the results of the search are communicated back to your CMakeLists.txt.

These find modules are intended to be provided by CMake directly, by Extra CMake Modules or by your project directly (typically in a cmake subfolder, but don't forget to add it to CMAKE_MODULE_PATH).

The second search method is called the config search. This uses files installed by the packages you are looking for. In other words, CMake expects the files to exist if the package is installed, and to not exist if it is not. It progresses like this:

  • CMake searches for the files FooConfig.cmake and FooConfigVersion.cmake in one of a few standard locations:
    • It constructs a list of prefixes to search in using several bits of information. The easiest to affect are CMAKE_PREFIX_PATH and PATH (the parent directories of entries in PATH are used, so /usr for /usr/bin and so on).
    • Within those prefixes, it looks in some subdirectories; the full list is in the documentation, but in practice they tend to be in share/Foo or <libdir>/cmake/Foo on UNIX systems.
  • The FooConfigVersion.cmake is used to determine whether the package version is compatible with the requested version.
  • FooConfig.cmake is included (in much the same way as for find modules).

It is possible to force CMake to use only one mode or the other. Passing the MODULE argument to find_package will cause it to only use find modules, and passing NO_MODULE or CONFIG will cause it to only use config files.

How can I make my package packager-friendly?

Avoid REQUIRED in find_package()

The preferred way is to avoid REQUIRED in find_package() calls and use instead set_package_properties() to set what is required, and what is optional:

include(FeatureSummary)

[...]
find_package(foo)
set_package_properties(foo PROPERTIES TYPE REQUIRED PURPOSE "Required
to bar the foo.")

[... at the end of the CMakeLists.txt]
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)

The advantage? CMake will configure things till the end and *then* list *all* the missing dependencies in one fell swoop. Much easier for packaging, too.