In GetLinkInterface, GetLinkInterfaceLibraries, and
GetImportLinkInterface, lookup the HeadToLinkInterfaceMap for the
current configuration first, and then index it by head target. In
GetLinkImplementationLibrariesInternal, lookup the
HeadToLinkImplementationMap for the current configuration first, and
then index it by head target.
These use a huge amount of memory that accumulates as generation
proceeds. On the Unix Makefiles generator, only GetIncludeDirectories
and GetCompileDefinitions are even called more than once per target
(once for build files, once for dependency scanning preprocessor info).
Another approach will be needed to avoid duplicate computation in the
cases where it does occur.
These use a huge amount of memory that accumulates as generation
proceeds. On the Unix Makefiles generator, only GetIncludeDirectories
and GetCompileDefinitions are even called more than once per target
(once for build files, once for dependency scanning preprocessor info).
Another approach will be needed to avoid duplicate computation in the
cases where it does occur.
a9c9b66c cmTarget: use a hash_map for cmTargets typedef
bcb6dbc1 cmTarget: help the optimizer a bit
679f3dee cmTarget: use hash_set for sets of strings
23d6520d cmTarget: Allow caching of empty genex expansions
cd54f1db cmTarget: Only copy GenEx expansions when necessary
b75fc0e1 cmTarget: Don't set properties on custom targets
66076915 cmTarget: Use static strings for special property names
cebefa71 cmTarget: Sort special property checks
97ce676e cmTarget: Fast path for regular properties
4cfa918a cmTarget: Factor out common code
85242b7d cmTarget: Use else/if trees rather than an if tree
The LINK_LIBRARIES property is by *far* the most popular. Move it to the
top. TYPE is second, but with more generator expression usage, that may
change in the future.
Replace isLinkDependentProperty with a CompatibleInterfaces structure
that records all the compatible interface properties in a set for each
type. This avoids repeatedly traversing the link implementation closure
and asking every target for its compatible interface properties.
Split the library lists out of LinkImplementation and LinkInterface into
LinkImplementationLibraries and LinkInterfaceLibraries parent classes,
respectively. Return these from GetLinkImplementationLibraries and
GetLinkInterfaceLibraries, respectively, so that callers cannot access
parts of the structures that have not been populated.
Callers of cmTarget::GetLinkImplementationClosure are interested in the
set of targets whose interface properties propagate to the current
target. This excludes targets guarded by $<LINK_ONLY>.
Teach the CompatibleInterface test to cover suppression of interface
compatibility tests with $<LINK_ONLY>. Although this is not recommended
in practice, it is a way of covering the above behavior.
Previously this generator expression was used internally by the
target_link_libraries command to honor private linking requirements of
static libraries in their INTERFACE_LINK_LIBRARIES. Remove the check
that limits $<LINK_ONLY> to this use case to make it available for
project code to use too.
The old link dependency analysis is now needed only for the VS 6
generator code delimited by CM_USE_OLD_VS6 to support project-provided
project templates. Rename the related cmTarget members to be "ForVS6".
Create the map entry up front and store in it a boolean value indicating
whether the LinkInterface structure has been populated. This approach
leads to shorter code that is easier to follow too.
Create the map entry up front and store in it boolean values indicating
which pieces of the LinkInterface structure have been populated.
This approach leads to shorter code that is easier to follow too.
Fix cmTarget::GetSourceFiles to set EvaluateForBuildsystem on the
$<TARGET_PROPERTY:...,INTERFACE_SOURCES> generator expression so that
the $<TARGET_OBJECTS> generator expression is allowed within an
INTERFACE_SOURCES value.
Extend the InterfaceLibrary test to cover this case. Extend the
RunCMake.TargetObjects test to cover failure of $<TARGET_OBJECTS>
when used through $<TARGET_PROPERTY:...,INTERFACE_SOURCES> in a
non-buildsystem context.
In commit 7b0834e9 (cmTarget: Refactor internal LinkImplementation map,
2014-06-19) cmTarget::GetLinkImplementationLibrariesInternal was changed
accidentally to pass "this" to ComputeLinkImplementation instead of
"head". Change it back.
Use the AddInterfaceEntries helper to avoid duplication. In
TargetPropertyEntry, replace the TargetName string member with a
reference to the full cmLinkImplItem that produced the entry. This is
possible because the cmLinkImplItem is available in AddInterfaceEntries
(it was not available in GetIncludeDirectories). Having the full
cmLinkImplItem allows processIncludeDirectories to implement CMP0027 OLD
behavior without repeating the target name lookup.
Update the RunCMake.CompatibleInterface test DebugProperties case
expected output for the new order of the messages.
Evaluate and lookup the target name only once per TargetPropertyEntry
instead of repeating it for each include directory entry. Use a local
checkCMP0027 variable to record whether the policy should be checked.
Evaluate the target name as a generator expression only if it looks like
one. Lookup the target by name only after evaluation of generator
expressions.
Implementation of CMP0027 OLD behavior needs to know whether each entry
in LinkImplementation::Libraries came from a generator expression or
not. Add a FromGenex member to cmLinkImplItem to record this.
Create a cmTargetInternals::AddInterfaceEntries method to construct a
$<TARGET_PROPERTY:tgt,INTERFACE_XYZ> generator expression and evaluate
it for every target in the link implementation. This will be useful to
de-duplicate such evaluation for each usage requirement separately.
The new method will soon be used in the implementation of the
INTERFACE_* usage requirement lookup methods (GetSourceFiles,
GetCompileOptions, GetCompileDefinitions, GetCompileFeatures,
GetIncludeDirectories). It is necessary for these methods to determine
whether an expression in LinkImplementationPropertyEntries evaluates to
a target or not because generator expression evaluation reports an error
for non-targets and we construct a $<TARGET_PROPERTY:tgt,INTERFACE_XYZ>
expression for each entry that is a target.
The implementation of each usage requirement currently processes the
LinkImplementationPropertyEntries and evaluates all generator
expressions to determine targets. That is no longer necessary because
GetLinkImplementationLibraries now returns resolved and cached targets
together with their name. Use it to implement AddInterfaceEntries.
Create a cmLinkImplItem class derived from cmLinkItem so more
information can be added to link implementation entries than link
interface entries. Convert the LinkImplementation Libraries member to
hold it. Update client sites accordingly.
Commit v2.8.11~310^2~1 (Keep track of INCLUDE_DIRECTORIES as a vector of
structs., 2012-11-19) added special case of INCLUDE_DIRECTORIES
for the purpose of origin-tracking of individual entries in the property. It
introduced a bug in that it returned an empty string instead of '0' in the
case that no includes have been set.
Commit v2.8.11~289^2~2 (Handle INTERFACE properties transitively for includes
and defines., 2012-09-23) introduced transitive handling of the property
through the link implementation, together with a whitelist of properties
which would be evaluated transitively. Because of the bug introduced
previously, the 'prop' in TargetPropertyNode is non-null,
meaning that the content (the empty string) would be evaluated as a generator
expression. This was harmless as the follow-up code was only for 'INTERFACE_'
variants of target properties, so the effect was the same.
Commits v2.8.11~280^2~2 (Keep track of properties used to determine linker
libraries., 2012-11-05) and v2.8.11~280^2~1 (Add API to calculate
link-interface-dependent bool properties or error., 2013-01-06) added a way
to track and report errors on properties which both determine and are
determined by the link implementation. This was later used in generator
expression evaluation by commit v2.8.11~252^2~2 (Make INTERFACE determined
properties readable in generator expressions., 2013-01-19). If a property
is unset (null), and the link implementation of the target was not being
evaluated, this commit made it possible to evaluate the property from the
link implementation instead. If the link implementation was being evaluated,
an empty string was returned from the generator expression evaluation, which
might be later reported as an error.
The above logic was written for 'compatible interface' properties, but in
fact it should have also included other properties. Because of the
empty-string-instead-of-null bug, this code block is not entered for the
INCLUDE_DIRECTORIES property. At this point, however, the bug still does
not significantly affect behavior, because the follow-up code is still a
no-op for the INCLUDE_DIRECTORIES property, and an empty string is returned
regardless. Commit v2.8.11~189^2~6 (Use the link information as a source of
compile definitions and includes., 2013-02-12) refactored the logic, but also
without a change in behavior.
Commit v2.8.11~156^2~2 (Expand includes and defines transitively
in 'external' genexes., 2013-02-13) refactored the logic again, this time with
a change of behavior. The INCLUDE_DIRECTORIES property was then mapped to
INTERFACE_INCLUDE_DIRECTORIES during transitive generator expression
evaluation. Because the transitive evaluation involved evaluation of the
link implementation, this introduced a recursive loop and a segfault with
code like:
add_library(empty1 ...)
add_library(empty2 ...)
target_link_libraries(empty1
PRIVATE
$<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
As there is no real use-case for reading a target property like that while
evaluating the link implementation, this went unnoticed. The same pattern
was followed for other special-cased reads of transitive target properties
such as COMPILE_DEFINITIONS.
The segfault was fixed in the parent commit, but change the property to
return null when appropriate for other future uses.