CMake Language Pitfalls

From Qt Wiki
Jump to navigation Jump to search

This is a collection of pitfalls you might encounter when writing CMake code for Qt's build system.

Initializing Empty Variables

Initialize variables that are supposed to be empty with set(foo "") never with set(foo).

Why? set(foo) is equivalent to unset(foo). A normal variable expansion ${foo} will fall back to the cache variable expansion $CACHE{foo} if foo is unset.

This is especially unpleasant for the variable name result which is cache-set by our feature system.

set(foo ON CACHE BOOL "")
set(foo)
message("\${foo}: ${foo}")      # prints ${foo}: ON
set(foo "")
message("\${foo}: ${foo}")      # prints ${foo}:

Brackets in Strings

Mind CMake's special handling of brackets in lists.

set(lines "foo" "bar" "baz")
list(JOIN lines "\n" content)
message("this is fine:\n${content}")
set(lines "foo" "bar [" "baz")
list(JOIN lines "\n" content)
message("----------")
message("this is unexpected:\n${content}")

prints

this is fine:
foo
bar
baz
----------
this is unexpected:
foo
bar [;baz

This happens, because

Although all values in CMake are stored as strings, a string may be treated as a list in certain contexts, such as during evaluation of an Unquoted Argument. In such contexts, a string is divided into list elements by splitting on ; characters not following an unequal number of [ and ] characters and not immediately preceded by a \. The sequence \; does not divide a value but is replaced by ; in the resulting element.

If you need to generate a string with brackets, for example JSON code, do not join lists. Directly append to a string.

Property names should start with an underscore

When creating new target property names, always prefix them with an underscore.

Popular prefixes are _qt_ and _qt_internal_

This is needed to avoid issues with INTERFACE_LIBRARY targets with CMake version 3.18 or lower.