[cmake-developers] conditionals in generator expressions
Brad King
brad.king at kitware.com
Mon Aug 20 09:11:19 EDT 2012
On 08/19/2012 05:43 PM, Stephen Kelly wrote:
> 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:
Thanks for working on this.
> 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.
It's not the generator expression parsing that can't handle ';'. It's
that the division on ';' occurs before generator expressions are processed.
Try evaluating them in the original INCLUDE_DIRECTORIES property string
*before* parsing it out as a list. In this hunk:
- cmSystemTools::ExpandListArgument(prop, includes);
+ std::vector<std::string> unProcessedIncludes;
+ cmSystemTools::ExpandListArgument(prop, unProcessedIncludes);
put the ge.Process() in the first argument of 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.
We could create a generator expression such as "$<RANGLE>" that expands
to right-angle. The expanded values are not re-processed by the parser
so if it expands to '>' it would be accepted literally.
> 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?
I consider this a feature, and with my answer to (1) you would not have
boundaries to test anyway.
> 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?
It would work just fine. The first "$<" token will be kept as a boundary
on the stack of opening tokens by the parser until after the other two
are expanded. When the last ">" is reached then the expression will be
either "$<0:/include/dirs>" or "$<1:/include/dirs>" and will be evaluated
as one of those expressions.
> 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.
It should be in cmTarget::ComputeLinkImplementation at this line:
// The entry is meant for this configuration.
impl.Libraries.push_back(item);
Process the value of the item string and use ExpandListArgument on the
result to append to impl.Libraries.
Also in cmTarget::ComputeLinkInterface in the "if(explicitLibraries)"
block between these two lines:
// The interface libraries have been explicitly set.
cmSystemTools::ExpandListArgument(explicitLibraries, iface.Libraries);
Process the value of explicitLibraries before expanding as a list.
Generator expressions should be processed directly after reading the
original string value from the user interface that provides it.
> 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.
Nice. BTW, I think the TARGET_PROPERTY_STREQUAL expression can use
"==" instead of "," as the separator between property name and value.
> 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.
This has been pretty messy in the past. Recently I created the
cmGeneratorTarget class to hold information/interfaces for a target
that only make sense at generate time. You could move the method
over there.
-Brad
More information about the cmake-developers
mailing list