Escaping semicolons in CMAKE_CONFIGURE_DEPENDS?

The documentation for CMAKE_CONFIGURE_DEPENDS states:

Specify files as a semicolon-separated list of paths. Relative paths are interpreted as relative to the current source directory.

What should I do when the path itself contains a semicolon? How can I prevent CMake from incorrectly splitting it in two?

You can escape the semicolon with a backslash.

set(a "blue;red")
list(LENGTH a a_length)
set(b "blue\;red")
list(LENGTH b b_length)
message("${a_length} vs. ${b_length}")

Ah, so CMAKE_CONFIGURE_DEPENDS follows the list expansion rules, then. Thanks!

What if I want a list with an unbalanced number of [ and ] in a given item? For example, how can I represent a list where the first item is [ and the second is ]?

set(foo "[;]")
list(LENGTH foo foo_length)
message("foo_length = ${foo}")
foo_length = 1

The unbalanced [ causes the list expansion rules to skip over the ; separator.

You simply can’t…

There are two comments in the CMake code that make it very explicit:

  // Break the string at non-escaped semicolons not nested in [].

(https://gitlab.kitware.com/cmake/cmake/blob/v3.16.2/Source%2FcmStringAlgorithms.cxx#L93)

and

        // We only want to allow escaping of semicolons.  Other
        // escapes should not be processed here.

(https://gitlab.kitware.com/cmake/cmake/blob/v3.16.2/Source%2FcmStringAlgorithms.cxx#L100-101)

I’ve seen those comments, yeah. Was holding out hope for some arcane, undocumented workaround. :sweat:

What’s the purpose of this “feature”, anyway? I would understand if the brackets were stripped out and just functioned as a method of avoiding manually escaping the individual semicolons between them. I can’t think of a use case where you’d want a list item containing semicolons and surrounded by actual brackets.

EDIT: Answering my own question - tracked down the original commit responsible, and the answer is Windows registry keys, which are surrounded by [ ] and may contain ;.

https://gitlab.kitware.com/cmake/cmake/commit/2b4e802a947ad5fd86b1ed296ea2f31714270dfa

It just occurred to me that there’s no way to end a list item in a \, either, unless the item is at the very end of the list (so, better make sure no one passes in a Windows directory path with a trailing backslash). Oh, what a headache this is…

That happened to someone using a CMake module I wrote, and they were very confused (https://github.com/McMartin/FRUT/issues/533).

You can sanitize user input using file(TO_CMAKE_PATH "<path>" <variable>).

Thanks for the pointer toward TO_CMAKE_PATH. That helps a bit. Of course, it’d be better if CMake lists behaved in a reasonable way in the first place.

1 Like