[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