[cmake-developers] conditionals in generator expressions

Stephen Kelly steveire at gmail.com
Sun Aug 19 17:43:35 EDT 2012


Brad King wrote:

> On 08/14/2012 05:11 AM, Stephen Kelly wrote:
>> Thanks, I'll see what I can figure out.
>> 
>> I think at this point, I'm more interested in linking to a library based
>> on the content of a target property (ie, linking QT_QTMAIN_LIBRARY based
>> on whether WIN32_EXECUTABLE is set), so I may need to expand it along the
>> lines you did for $<CONFIG:> first.
> 
> I rebased the topic after the sweeping changes and merged it to next.
> Please fetch "generator-expression-conditions" from the topic stage
> and base your work on that instead.

Thanks, here are my findings so far, which relate to my extension of that 
branch at git at gitorious.org:~steveire/cmake/steveires-cmake.git:

1) The result string of the $<CONFIG:...> expression does not allow lists. 
That means we can't do anything like this:

include_directories("$<$<CONFIG:Release>:/foo;/bar/bat>")
include_directories("$<$<CONFIG:Release>:${somedirs}>") 
# somedirs might contain a list

I fixed that in my branch by modifying cmSystemTools::ExpandListArgument. 

2) Because of the way generator expressions are parsed, the > character 
can't be part of the result string. This is an unlikely but possible 
character to appear in include directories for example. 

This seems to be because the generator expression can start and end anywhere 
in the input string to the Process method, instead of assuming that the 
start of the string is the start of the generator expression, and the end is 
the end of it. The latter probably makes more sense in the context of target 
property generator expressions. Eg, I'd prefer this to be illegal:

include_directories("/tmp/$<$<CONFIG:Release>:foo/>bar") 
# Could include /tmp/bar or /tmp/foo/bar, but not very readable.

Can this be changed? If it would break existing users of generator 
expressions, maybe we can enforce complete-string-generator-expressions if 
it is being used on a target (eg if (this->Target) inside Process() on my 
branch).

3) I can add something like $<TARGET_INTERFACE_INCLUDE_DIRS:tgt> in the 
future to expand to the interface include directories of a target (currently 
cmake has no such concept, but I'm thinking in the future).

However, I don't think something like 

$<$<CONFIG:Release>:$<TARGET_INTERFACE_INCLUDE_DIRS:tgt>> 

would work, would it? The 'right hand side' of the expressions must be the 
final string?

That was mostly just a thought experiment though. There wouldn't be any real 
need for TARGET_INTERFACE_INCLUDE_DIRS to be a generator expression instead 
of a static property on a target. If that is to be conditional on something 
like CONFIG:Release, that can just be in a generator expression in that 
TARGET_INTERFACE_INCLUDE_DIRS  property anyway.

I can't really think of a situation that that would be needed, but it is an 
interesting point which might be worth documenting.

4) I'm really not certain if I've implemented the patch for conditional link 
libraries in the right place. I tried a few different locations. I'm also 
not sure if there is logic at configure time which can't be implemented in 
terms of the generator expressions which are not evaluated by then. I tried 
using it with imported targets which had entries in their 
IMPORTED_LINK_INTERFACE_LIBRARIES, which seemed to work, so that's 
encouraging.

5) I think it's quite cool that I can add something like 

set(_WIN32_EXE "$<AND:$<TARGET_PROPERTY_STREQUAL:TYPE,EXECUTABLE>,
$<TARGET_PROPERTY_BOOL:WIN32_EXECUTABLE>>")
target_link_libraries(Qt5::Core
  LINK_INTERFACE_LIBRARIES
   "$<${_WIN32_EXE}:Qt5::WinMain>"
)

and it will lie dormant and not have any effect on any shared libraries 
until it is finally linked to an executable :). Several features come 
together nicely there.

6) In my new implementation of cmTarget::GetIncludeDirectories, it is now 
necessary for that method to only be called at generate-time. As far as I 
can see, that is already true for that method, but for maintenance it is a 
bit difficult. Are there other examples of similar requirements of when an 
API can be meaningfully called? It seems to be something that could benefit 
from refactoring throughout cmake if so.

Thanks, 

Steve.





More information about the cmake-developers mailing list