[cmake-developers] conditionals in generator expressions
Stephen Kelly
steveire at gmail.com
Mon Aug 20 16:25:26 EDT 2012
Brad King wrote:
> 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.
Thanks for the feedback. I've updated the branch.
>
>> 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.
<snip>
I've implemented it like that now. That will also work for
compile_definitions, but I think it won't work for link_libraries. I'm also
not sure about link_directories, compiler_flags and linker_flags. For
link_libraries it is quite unfortunate, because it would make things like
$<${USE_FOO}:${FOO_LIBRARIES}>
not work as expected:
/usr/lib/icecc/bin/c++ CMakeFiles/fooex.dir/newex.cpp.o -o fooex -
rdynamic libfoo.so libfoo.so $<1:Qt5::Widgets -lQt5::Sql> -Wl,-
rpath,/home/stephen/dev/src/playground/cmake/build
g++: error: $<1:Qt5::Widgets: No such file or directory
I think this needs to be fixed, but I get the feeling it might require
deeper redesign of the link libraries logic?
>> 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.
Done. It's also not ideal because it means the user has to potentially pre-
process the contents of all properties to replace the literal with the
RANGLE. I don't see any better solution though.
>> 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.
Ok, I'm sure there can be a solution to the rest of (1).
>> 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.
Great, thanks.
>
>> 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.
I tried this, but it made (5) below not work anymore. The generator
expression was evaluated too early it seems for Qt5::Core, and at that point
TYPE == SHARED_LIBRARY.
>
>> 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.
Done.
>> 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.
I created a separate branch for that in my clone (use-generator-target). I
think it's a good idea but a separate topic which should be run to
completion.
Thanks,
Steve.
More information about the cmake-developers
mailing list