[cmake-developers] conditionals in generator expressions

Stephen Kelly steveire at gmail.com
Thu Aug 30 04:33:02 EDT 2012


Brad King wrote:

> On 08/29/2012 09:25 AM, Brad King wrote:
>>> I've pushed a generator-expression-refactor branch to my clone. It needs
>>> some clean-up, de-duplication etc, but I'm looking for feedback on the
>>> approach.
>>>
>>> In my branch, all parameters must be separated by ','. All commas and
>>> colons must appear literally in the expression. This makes escaping
>>> not-needed, and multiple-parameter-separators consistent accross all
>>> generators.
>> 
>> Great.  I'll take a look when I get a chance.
> 
> That looks like a good start.  Pre-parsing the entire expression tree
> is the right approach.
> 
> While quoting/escaping expanded values is not needed we still need
> it for the input, like STREQUAL comparing to "," for example.

The first solution that comes to mind within the current implementation is a 
<COMMA> or similar.

Reading on...

> 
> When we first designed generator expressions it was just for the
> basic "$<TARGET_FILE:tgt>"-type expressions.  The format for target
> names was restricted so we didn't need to think about handling
> arbitrary content.  The $<0:...> and $<1:...> expressions can
> have arbitrary content other than ">" but they always have exactly
> one "parameter" so there is no real parsing involved.
> 
> When I mentioned the "$<RANGLE>" expression it was just as an example
> of what the current approach can do (a better name might be ANGLE-R).
> However, now that you're writing a real lexer/parser we need to think
> about how this new mini-language will work syntactically.  There should
> be no need for $<ANGLE-R> if we have proper quoting rules.  Consider
> bash syntax like
> 
>  echo $(echo 'nested command with )')
> 
> where the quoting protects the close-parenthesis inside $(...) syntax.
> In order to allow more readable inputs we could consider allowing
> arbitrary whitespace to separate arguments, as in:
> 
>  $<STREQUAL "$<TARGET_PROPERTY:TYPE>"
>             "EXECUTABLE">
> 
> just like the CMake language itself.  If quoting is parsed as part
> of the syntax then it can be used for '>' too e.g.
> 
>  $<STREQUAL "a" ">">
> 
> where quoting protects argument contents as in bash.

Other examples:

$<STREQUAL "a" " ">

$<STREQUAL "a" "\"">

Which looks like a fairly 'normal' escaping scheme from a c++ point of view.

However, the problem is that these generator expressions are in strings 
already. Which means we'll have this:

set_target_properties(foolib 
  PROPERTIES INCLUDE_DIRECTORIES
  "$<$<STREQUAL \"a b\" \"\\\",\"> \"/bar bat/bag\">"
)

because that set_target_properties signature can only take one argument 
(there are other bug reports about this I think, but I don't recall if it's 
changable). 

I don't think it's very readable.

In my branch it would be this instead:

set_target_properties(foolib 
  PROPERTIES INCLUDE_DIRECTORIES
  "$<$<STREQUAL:a b,\"$<COMMA>>:/bar bat/bag>"
)

which is also not perfect, but is better.

In the case of:

set_property(TARGET foolib 
  [APPEND] PROPERTY INCLUDE_DIRECTORIES
  $<$<STREQUAL "a" "\""> "/bar bat/bag">
)

it will create a list of strings. So the const char *input to the generator 
expression will contain a ';' separated list of strings.

> 
> One way to distinguish expressions with free-form arguments from
> those without is whether there is a ':' or whitespace after the
> expression name.

I don't think that benefits readability.

So the options are either: 

1) Require the use of $<ANGLE-R> or $<COMMA> inside generator expressions
2) Introduce proper quoting rules. I don't think the current proposal for 
that is readable enough to be beneficial, but with a different 
parsing/quoting scheme not based on whitespace and "\"", it might be 
workable.

I think that (1) is cheap and worth it. One unfortunate place where it 
doesn't fit and where $<COMMA> would have to be broadly used would be this:

set_target_properties(foolib 
  PROPERTIES COMPILE_OPTIONS
  "$<$<CONFIG:Debug>:-Wl$<COMMA>no-undefined>"
)

That is fixable if we choose a different parameter separation character (and 
port $<AND> and $<OR> to it too).

Colon is not an option because it makes the language more confusing, and 
would require a $<COLON>, which would need to be broadly used to escape 
'Qt5::Core' etc.

Looking at my keyboard, how about '?' '|' '\'' '#' or '*'?

$<AND:$<STREQUAL:a*b>*$<TARGET_PROPERTY:TYPE*EXECUTABLE>>

$<AND:$<STREQUAL:a|b>|$<TARGET_PROPERTY:TYPE|EXECUTABLE>>

$<AND:$<STREQUAL:a'b>'$<TARGET_PROPERTY:TYPE'EXECUTABLE>>

$<AND:$<STREQUAL:a#b>#$<TARGET_PROPERTY:TYPE#EXECUTABLE>>

$<AND:$<STREQUAL:a?b>?$<TARGET_PROPERTY:TYPE?EXECUTABLE>>

I prefer '*' because '?' doesn't stand out enough and :a?b seems wrong.
'|' means OR more strongly to me than '*' would mean multiply in this 
context, and stands out well.

'#' might work too, but I think it would be parsed as a comment if the whole 
expression was not surrounded in quotes?

Thanks,

Steve.





More information about the cmake-developers mailing list