Why are square brackets special in lists? / Problem with cmake_parse_arguments

I tried to use cmake_parse_arguments to parse some options given to a function command. One of those options gets as value a string which contains a single opening square bracket.

As a result all other options/values following become part of that value up until either a closing square bracket is encountered or till the end of the arguments to cmake_parse_arguments.

By digging into the parsing code I realized that function cmExpandList (from Source/cmStringAlgorithms.cxx) is used internally to parse the given arguments. That function has some special handling for semicolons, in particular if occurring after opening square brackets.

That would explain the observed behavior. However, I get the impression that is not what was originally intended.

Why such a special handling? If this code is looking for bracket arguments then it is doing it wrong. (It ignores the optional = and second [.)

Can anyone of the developers shed some light on this?

The lists documentation calls this out:

splitting on ; characters not following an unequal number of [ and ] characters

The reason is historical. Prior to the introduction of ;-separated lists, the find_* commands already had a feature that used ; inside [ and ] that was supported in unquoted arguments. The feature is still there and used by find modules, though it is not well documented. It is for referencing Windows registry entries:

find_program(SOME_EXE NAMES some PATHS
  [HKEY_LOCAL_MACHINE\\SOFTWARE\\Some\\Exe;Prefix]/bin
  )

When ;-separated lists were introduced we needed a way to retain compatibility with such uses. Since ;-separated lists were only meant for lists of source files at the time, special treatment of [ and ] didn’t matter. Since then it has been kept for compatibility.

Yes, I already found this. But I could not make any sense out of it. And it looked like some ancient relic to me.

Thanks for your further explanation, though. Indeed, that confirms that I was not too wrong with it being ancient.
It must have come from an even older CMake version than 2.6?

Is the compatibility with that still really needed? Shouldn’t it be enough to just escape the semicolon in the Windows registry string?

Or the other way around and escape the opening square bracket? (Although that looks less intuitive.)

The compatibility is needed because projects in the wild have logic that depends on this behavior.

So, in order to not break that dependency, the only possible extension would be to allow escaping opening square brackets and ignore these for this feature?
Or is that something that should not be allowed?

I don’t think we can make any change to the list representation at all without introducing subtle problems for the ecosystem. We can’t even do it with a policy because the policy setting would have to be stored along with the value, which would be a huge performance hit. You’ll have to work around the problem another way. Some projects substitute placeholders for [ and ] in intermediate logic.