[cmake-developers] Setting includes, defines and other usage requirements with one command
Stephen Kelly
steveire at gmail.com
Fri Feb 8 15:16:35 EST 2013
Brad King wrote:
> Currently the code
>
> target_link_libraries(foo $<$<CONFIG:Debug>:not_a_target>)
>
> will put a giant generator expression in the include directories
> and compile definitions properties and it will be exported, right?
Yes.
>
> I do not like this. Since we decided not to use a new target-only
> command we need to deal with it somehow though.
How would the situation be different with a new command?
target_use_interfaces(foo INTERFACE $<$<CONFIG:Debug>:not_a_target>)
would have had to write the same string to the property. As far as I see, no
matter what porcelain is used, the effect on the plumbing values will be the
same (as TARGET_PROPERTY and LINKED are currently defined).
TARGET_PROPERTY requires an actual target and errors otherwise, so
$<TARGET_PROPERTY:$<$<CONFIG:Debug>:not_a_target>,IFACE_INCLUDE_DIRS>
wouldn't work for non-Debug. It is deliberately strict.
> Can we still use
> the $<LINKED:${whole_expression}> approach?
Currently, LINKED expects a literal non-generator-expression. That fact is
used to extract target names while exporting. If we change LINKED to allow
generator expression content, then yes we might be able to use it instead of
the big string. I haven't investigated though.
> I think it should be
> possible when processing out $<LINKED:...> expressions to dig
> into the contained expression to see if there are any real targets.
Hmm, yes, that would be needed for proper exporting as we don't generate
LINKED expressions on export.
I'm not sure that's easy or worth it. Especially as the genex language
allows things like mylib$<$<CONFIG:Debug>:_debug>. There may be other dark
corners where that would break.
If we can't determine all targets, then we'd end up exporting properties
with TARGET_DEFINED anyway. That would mean longer strings on export than we
currently have as currently LINKED requires literal target names - no need
for TARGET_DEFINED.
> Actually such digging might be useful anyway because it would help
> diagnose and warn/error when users write something non-sensical
> like
>
> tll(foo $<TARGET_PROPERTY:bar,INTERFACE_INCLUDE_DIRECTORIES>)
>
> by hand. One thing that tll does know is that its arguments must
> be target names or non-target libraries.
> Other strings make no sense.
Either I'm not clear what you're referring to, or I don't think that's true
of tll. The docs say
"Item names starting with '-', but not '-l' or '-framework', are "
"treated as linker flags."
and at least KDE uses a GSSAPI module whose _LIBRARIES variable is a string
like "-Wl,-Bsymbolic-functions -Wl,-z,relro -lgssapi_krb5 -lkrb5 -lk5crypto
-lcom_err".
Anyway, I haven't seen any problems resulting from the length of the string.
I also don't have any solution to your error code above. There are many
other ways to shoot in the foot or otherwise create obfuscated code:
tll(foo $<TARGET_PROPERTY:bar,SOMETHING>)
set_property(TARGET foo PROPERTY SOMETHING bing)
We probably can't catch all of them without harming legitimate uses which we
have not thought of.
An option would be to not populate the includes and defines properties at
all in tll if generator expressions are used. For actual targets, that means
using generator expressions in tll is less functional (by not also
populating the includes and defines properties). For non-targets it means no
long and ultimately useless strings in those properties.
If that route is taken, the solution to this code:
tll(foo INTERFACE $<$<CONFIG:Debug>:some_target>)
becomes this in the future:
add_library(myIface INTERFACE)
# Special-case tll with INTERFACE_LIBRARY to also
# populate the includes and defines properties as
# currently, including the TARGET_DEFINED
tll(myIFACE INTERFACE $<$<CONFIG:Debug>:maybe_a_target>)
tll(foo INTERFACE myIface)
That at least means that if you want to use generator expressions with
something that is definitely not a target, use tll directly. If using tll
with a genex which may be either a target or not, use an intermediate
INTERFACE_LIBRARY. Also an ugly solution imo actually.
My preference currently is to leave things as they are including the long
and useless string.
Thanks,
Steve.
More information about the cmake-developers
mailing list