summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/target_link_libraries.rst11
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/policy/CMP0079.rst40
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst2
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES.rst2
-rw-r--r--Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt10
-rw-r--r--Help/release/dev/out-of-dir-linking.rst6
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.cxx26
-rw-r--r--Source/cmExportFileGenerator.cxx9
-rw-r--r--Source/cmGeneratorExpressionNode.cxx4
-rw-r--r--Source/cmGeneratorTarget.cxx71
-rw-r--r--Source/cmGeneratorTarget.h7
-rw-r--r--Source/cmGlobalGenerator.cxx42
-rw-r--r--Source/cmGlobalGenerator.h17
-rw-r--r--Source/cmMakefile.cxx17
-rw-r--r--Source/cmMakefile.h10
-rw-r--r--Source/cmPolicies.h6
-rw-r--r--Source/cmTarget.cxx15
-rw-r--r--Source/cmTarget.h3
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx80
-rw-r--r--Tests/CMakeCommands/target_link_libraries/CMakeLists.txt12
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt15
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt15
-rw-r--r--Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c14
-rw-r--r--Tests/CMakeCommands/target_link_libraries/TopDir.c14
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt9
-rw-r--r--Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt6
-rw-r--r--Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c11
-rw-r--r--Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt4
-rw-r--r--Tests/ExportImport/Export/testTopDirLib.c11
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt11
-rw-r--r--Tests/ExportImport/Import/A/SubDirLink.c14
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt17
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface-common.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-result.txt (renamed from Tests/RunCMake/target_link_libraries/SubDirTarget-result.txt)0
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-NEW.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-OLD.cmake2
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-result.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-WARN.cmake1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link-common.cmake6
-rw-r--r--Tests/RunCMake/target_link_libraries/CMP0079-link/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/target_link_libraries/CMakeLists.txt2
-rw-r--r--Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake8
-rw-r--r--Tests/RunCMake/target_link_libraries/SubDirTarget-stderr.txt5
-rw-r--r--Tests/RunCMake/target_link_libraries/SubDirTarget.cmake3
-rw-r--r--Tests/RunCMake/target_link_libraries/SubDirTarget/CMakeLists.txt1
60 files changed, 529 insertions, 88 deletions
diff --git a/Help/command/target_link_libraries.rst b/Help/command/target_link_libraries.rst
index 1f0d69e..e1c374e 100644
--- a/Help/command/target_link_libraries.rst
+++ b/Help/command/target_link_libraries.rst
@@ -18,10 +18,13 @@ All of them have the general form::
target_link_libraries(<target> ... <item>... ...)
-The named ``<target>`` must have been created in the current directory by
-a command such as :command:`add_executable` or :command:`add_library` and
-must not be an :ref:`ALIAS target <Alias Targets>`.
-Repeated calls for the same ``<target>`` append items in the order called.
+The named ``<target>`` must have been created by a command such as
+:command:`add_executable` or :command:`add_library` and must not be an
+:ref:`ALIAS target <Alias Targets>`. If policy :policy:`CMP0079` is not
+set to ``NEW`` then the target must have been created in the current
+directory. Repeated calls for the same ``<target>`` append items in
+the order called.
+
Each ``<item>`` may be:
* **A library target name**: The generated link line will have the
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 32a0118..8ecca4d 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.13
.. toctree::
:maxdepth: 1
+ CMP0079: target_link_libraries allows use with targets in other directories. </policy/CMP0079>
CMP0078: UseSWIG generates standard target names. </policy/CMP0078>
CMP0077: option() honors normal variables. </policy/CMP0077>
CMP0076: target_sources() command converts relative paths to absolute. </policy/CMP0076>
diff --git a/Help/policy/CMP0079.rst b/Help/policy/CMP0079.rst
new file mode 100644
index 0000000..0244d6c
--- /dev/null
+++ b/Help/policy/CMP0079.rst
@@ -0,0 +1,40 @@
+CMP0079
+-------
+
+:command:`target_link_libraries` allows use with targets in other directories.
+
+Prior to CMake 3.13 the :command:`target_link_libraries` command did not
+accept targets not created in the calling directory as its first argument
+for calls that update the :prop_tgt:`LINK_LIBRARIES` of the target itself.
+It did accidentally accept targets from other directories on calls that
+only update the :prop_tgt:`INTERFACE_LINK_LIBRARIES`, but would simply
+add entries to the property as if the call were made in the original
+directory. Thus link interface libraries specified this way were always
+looked up by generators in the scope of the original target rather than
+in the scope that called :command:`target_link_libraries`.
+
+CMake 3.13 now allows the :command:`target_link_libraries` command to
+be called from any directory to add link dependencies and link interface
+libraries to targets created in other directories. The entries are added
+to :prop_tgt:`LINK_LIBRARIES` and :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+using a special (internal) suffix to tell the generators to look up the
+names in the calling scope rather than the scope that created the target.
+
+This policy provides compatibility with projects that already use
+:command:`target_link_libraries` with the ``INTERFACE`` keyword
+on a target in another directory to add :prop_tgt:`INTERFACE_LINK_LIBRARIES`
+entries to be looked up in the target's directory. Such projects should
+be updated to be aware of the new scoping rules in that case.
+
+The ``OLD`` behavior of this policy is to disallow
+:command:`target_link_libraries` calls naming targets from another directory
+except in the previously accidentally allowed case of using the ``INTERFACE``
+keyword only. The ``NEW`` behavior of this policy is to allow all such
+calls but use the new scoping rules.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior.
+Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW``
+explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
index 832d12b..bf7f72f 100644
--- a/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
+++ b/Help/prop_tgt/INTERFACE_LINK_LIBRARIES.rst
@@ -17,6 +17,8 @@ with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
manual for available expressions. See the :manual:`cmake-buildsystem(7)`
manual for more on defining buildsystem properties.
+.. include:: LINK_LIBRARIES_INDIRECTION.txt
+
Creating Relocatable Packages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/prop_tgt/LINK_LIBRARIES.rst b/Help/prop_tgt/LINK_LIBRARIES.rst
index aa4b9f5..d88e798 100644
--- a/Help/prop_tgt/LINK_LIBRARIES.rst
+++ b/Help/prop_tgt/LINK_LIBRARIES.rst
@@ -15,3 +15,5 @@ Contents of ``LINK_LIBRARIES`` may use "generator expressions" with the
syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
for available expressions. See the :manual:`cmake-buildsystem(7)` manual
for more on defining buildsystem properties.
+
+.. include:: LINK_LIBRARIES_INDIRECTION.txt
diff --git a/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
new file mode 100644
index 0000000..1fdb6ad
--- /dev/null
+++ b/Help/prop_tgt/LINK_LIBRARIES_INDIRECTION.txt
@@ -0,0 +1,10 @@
+.. note::
+ A call to :command:`target_link_libraries(<target> ...)` may update this
+ property on ``<target>``. If ``<target>`` was not created in the same
+ directory as the call then :command:`target_link_libraries` will add a
+ suffix of the form ``::@<directory-id>`` to each entry, where the
+ ``::@`` is a separator and the ``<directory-id>`` is unspecified.
+ This tells the generators that the named libraries must be looked up in
+ the scope of the caller rather than in the scope in which the
+ ``<target>`` was created. Valid directory ids are stripped on export
+ by the :command:`install(EXPORT)` and :command:`export` commands.
diff --git a/Help/release/dev/out-of-dir-linking.rst b/Help/release/dev/out-of-dir-linking.rst
new file mode 100644
index 0000000..6166be6
--- /dev/null
+++ b/Help/release/dev/out-of-dir-linking.rst
@@ -0,0 +1,6 @@
+out-of-dir-linking
+------------------
+
+* The :command:`target_link_libraries` command may now be called
+ to modify targets created outside the current directory.
+ See policy :policy:`CMP0079`.
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
index 3d32b84..d12ad7f 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -8,11 +8,8 @@
#include <utility>
#include "cmAlgorithms.h"
-#include "cmGeneratorExpression.h"
-#include "cmGeneratorExpressionDAGChecker.h"
#include "cmGeneratorTarget.h"
#include "cmLinkItem.h"
-#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmStateTypes.h"
@@ -104,27 +101,14 @@ void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties(
os << "LOCAL_CPP_FEATURES += ";
os << (property.second) << "\n";
} else if (property.first == "INTERFACE_LINK_LIBRARIES") {
- // evaluate any generator expressions with the current
- // build type of the makefile
- cmGeneratorExpression ge;
- cmGeneratorExpressionDAGChecker dagChecker(
- target, "INTERFACE_LINK_LIBRARIES", nullptr, nullptr);
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(property.second);
- std::string evaluated = cge->Evaluate(
- target->GetLocalGenerator(), config, false, target, &dagChecker);
- // need to look at list in pi->second and see if static or shared
- // FindTargetToLink
- // target->GetLocalGenerator()->FindGeneratorTargetToUse()
- // then add to LOCAL_CPPFLAGS
- std::vector<std::string> libraries;
- cmSystemTools::ExpandListArgument(evaluated, libraries);
std::string staticLibs;
std::string sharedLibs;
std::string ldlibs;
- for (std::string const& lib : libraries) {
- cmGeneratorTarget* gt =
- target->GetLocalGenerator()->FindGeneratorTargetToUse(lib);
+ cmLinkInterfaceLibraries const* linkIFace =
+ target->GetLinkInterfaceLibraries(config, target, false);
+ for (cmLinkItem const& item : linkIFace->Libraries) {
+ cmGeneratorTarget const* gt = item.Target;
+ std::string const& lib = item.AsStr();
if (gt) {
if (gt->GetType() == cmStateEnums::SHARED_LIBRARY ||
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 1c5040a..67df6fd 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -567,14 +567,17 @@ bool cmExportFileGenerator::AddTargetNamespace(
std::string& input, cmGeneratorTarget* target,
std::vector<std::string>& missingTargets)
{
- cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmGeneratorTarget::TargetOrString resolved =
+ target->ResolveTargetReference(input);
- cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(input);
+ cmGeneratorTarget* tgt = resolved.Target;
if (!tgt) {
+ input = resolved.String;
return false;
}
if (tgt->IsImported()) {
+ input = tgt->GetName();
return true;
}
if (this->ExportedTargets.find(tgt) != this->ExportedTargets.end()) {
@@ -584,6 +587,8 @@ bool cmExportFileGenerator::AddTargetNamespace(
this->HandleMissingTarget(namespacedTarget, missingTargets, target, tgt);
if (!namespacedTarget.empty()) {
input = namespacedTarget;
+ } else {
+ input = tgt->GetName();
}
}
return true;
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 1e51f09..16ac88c 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1054,7 +1054,9 @@ std::string getLinkedTargetsContent(
// Don't follow such link interface entries so as not to create a
// self-referencing loop.
if (l.Target && l.Target != target) {
- depString += sep + "$<TARGET_PROPERTY:" + l.Target->GetName() + "," +
+ std::string uniqueName =
+ target->GetGlobalGenerator()->IndexGeneratorTargetUniquely(l.Target);
+ depString += sep + "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," +
interfacePropertyName + ">";
sep = ";";
}
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index e8e7b90..efcfaf7 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -819,8 +819,11 @@ static void AddInterfaceEntries(
thisTarget->GetLinkImplementationLibraries(config)) {
for (cmLinkImplItem const& lib : impl->Libraries) {
if (lib.Target) {
+ std::string uniqueName =
+ thisTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
+ lib.Target);
std::string genex =
- "$<TARGET_PROPERTY:" + lib.AsStr() + "," + prop + ">";
+ "$<TARGET_PROPERTY:" + std::move(uniqueName) + "," + prop + ">";
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
@@ -840,7 +843,10 @@ static void AddObjectEntries(
for (cmLinkImplItem const& lib : impl->Libraries) {
if (lib.Target &&
lib.Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
- std::string genex = "$<TARGET_OBJECTS:" + lib.AsStr() + ">";
+ std::string uniqueName =
+ thisTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely(
+ lib.Target);
+ std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">";
cmGeneratorExpression ge(lib.Backtrace);
std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex);
cge->SetEvaluateForBuildsystem(true);
@@ -5639,24 +5645,65 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries(
}
}
+cmGeneratorTarget::TargetOrString cmGeneratorTarget::ResolveTargetReference(
+ std::string const& name) const
+{
+ cmLocalGenerator const* lg = this->LocalGenerator;
+ std::string const* lookupName = &name;
+
+ // When target_link_libraries() is called with a LHS target that is
+ // not created in the calling directory it adds a directory id suffix
+ // that we can use to look up the calling directory. It is that scope
+ // in which the item name is meaningful. This case is relatively rare
+ // so we allocate a separate string only when the directory id is present.
+ std::string::size_type pos = name.find(CMAKE_DIRECTORY_ID_SEP);
+ std::string plainName;
+ if (pos != std::string::npos) {
+ // We will look up the plain name without the directory id suffix.
+ plainName = name.substr(0, pos);
+
+ // We will look up in the scope of the directory id.
+ // If we do not recognize the id then leave the original
+ // syntax in place to produce an indicative error later.
+ cmDirectoryId const dirId =
+ name.substr(pos + sizeof(CMAKE_DIRECTORY_ID_SEP) - 1);
+ if (cmLocalGenerator const* otherLG =
+ this->GlobalGenerator->FindLocalGenerator(dirId)) {
+ lg = otherLG;
+ lookupName = &plainName;
+ }
+ }
+
+ TargetOrString resolved;
+
+ if (cmGeneratorTarget* tgt = lg->FindGeneratorTargetToUse(*lookupName)) {
+ resolved.Target = tgt;
+ } else if (lookupName == &plainName) {
+ resolved.String = std::move(plainName);
+ } else {
+ resolved.String = name;
+ }
+
+ return resolved;
+}
+
cmLinkItem cmGeneratorTarget::ResolveLinkItem(std::string const& name) const
{
- cmGeneratorTarget* tgt =
- this->LocalGenerator->FindGeneratorTargetToUse(name);
+ TargetOrString resolved = this->ResolveTargetReference(name);
+
+ if (!resolved.Target) {
+ return cmLinkItem(resolved.String);
+ }
// Skip targets that will not really be linked. This is probably a
// name conflict between an external library and an executable
// within the project.
- if (tgt && tgt->GetType() == cmStateEnums::EXECUTABLE &&
- !tgt->IsExecutableWithExports()) {
- tgt = nullptr;
- }
-
- if (tgt) {
- return cmLinkItem(tgt);
+ if (resolved.Target->GetType() == cmStateEnums::EXECUTABLE &&
+ !resolved.Target->IsExecutableWithExports()) {
+ return cmLinkItem(resolved.Target->GetName());
}
- return cmLinkItem(name);
+ return cmLinkItem(resolved.Target);
}
std::string cmGeneratorTarget::GetPDBDirectory(const std::string& config) const
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index a847e21..9d8c9f5 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -357,6 +357,13 @@ public:
cmOptionalLinkImplementation& impl,
const cmGeneratorTarget* head) const;
+ struct TargetOrString
+ {
+ std::string String;
+ cmGeneratorTarget* Target = nullptr;
+ };
+ TargetOrString ResolveTargetReference(std::string const& name) const;
+
cmLinkItem ResolveLinkItem(std::string const& name) const;
// Compute the set of languages compiled by the target. This is
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index 99135c8..24dc593 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -1139,11 +1139,14 @@ void cmGlobalGenerator::ClearEnabledLanguages()
void cmGlobalGenerator::CreateLocalGenerators()
{
+ this->LocalGeneratorSearchIndex.clear();
cmDeleteAll(this->LocalGenerators);
this->LocalGenerators.clear();
this->LocalGenerators.reserve(this->Makefiles.size());
for (cmMakefile* m : this->Makefiles) {
- this->LocalGenerators.push_back(this->CreateLocalGenerator(m));
+ cmLocalGenerator* lg = this->CreateLocalGenerator(m);
+ this->LocalGenerators.push_back(lg);
+ this->IndexLocalGenerator(lg);
}
}
@@ -1661,6 +1664,7 @@ void cmGlobalGenerator::ClearGeneratorMembers()
this->TargetSearchIndex.clear();
this->GeneratorTargetSearchIndex.clear();
this->MakefileSearchIndex.clear();
+ this->LocalGeneratorSearchIndex.clear();
this->ProjectMap.clear();
this->RuleHashes.clear();
this->DirectoryContentMap.clear();
@@ -2130,15 +2134,13 @@ cmMakefile* cmGlobalGenerator::FindMakefile(const std::string& start_dir) const
return nullptr;
}
-///! Find a local generator by its startdirectory
cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(
- const std::string& start_dir) const
+ cmDirectoryId const& id) const
{
- for (cmLocalGenerator* lg : this->LocalGenerators) {
- std::string sd = lg->GetCurrentSourceDirectory();
- if (sd == start_dir) {
- return lg;
- }
+ LocalGeneratorMap::const_iterator i =
+ this->LocalGeneratorSearchIndex.find(id.String);
+ if (i != this->LocalGeneratorSearchIndex.end()) {
+ return i->second;
}
return nullptr;
}
@@ -2168,6 +2170,24 @@ void cmGlobalGenerator::IndexGeneratorTarget(cmGeneratorTarget* gt)
}
}
+std::string cmGlobalGenerator::IndexGeneratorTargetUniquely(
+ cmGeneratorTarget const* gt)
+{
+ // Use the pointer value to uniquely identify the target instance.
+ // Use a "T" prefix to indicate that this identifier is for a target.
+ // We must satisfy cmGeneratorExpression::IsValidTargetName so use no
+ // other special characters.
+ char buf[64];
+ sprintf(buf, "::T%p",
+ static_cast<void const*>(gt)); // cast avoids format warning
+ std::string id = gt->GetName() + buf;
+ // We internally index pointers to non-const generator targets
+ // but our callers only have pointers to const generator targets.
+ // They will give up non-const privileges when looking up anyway.
+ this->GeneratorTargetSearchIndex[id] = const_cast<cmGeneratorTarget*>(gt);
+ return id;
+}
+
void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
{
// FIXME: add_subdirectory supports multiple build directories
@@ -2179,6 +2199,12 @@ void cmGlobalGenerator::IndexMakefile(cmMakefile* mf)
MakefileMap::value_type(mf->GetCurrentSourceDirectory(), mf));
}
+void cmGlobalGenerator::IndexLocalGenerator(cmLocalGenerator* lg)
+{
+ cmDirectoryId id = lg->GetMakefile()->GetDirectoryId();
+ this->LocalGeneratorSearchIndex[id.String] = lg;
+}
+
cmTarget* cmGlobalGenerator::FindTargetImpl(std::string const& name) const
{
TargetMap::const_iterator i = this->TargetSearchIndex.find(name);
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index c06ac52..f240f1d 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -26,6 +26,9 @@
# include "cmFileLockPool.h"
#endif
+#define CMAKE_DIRECTORY_ID_SEP "::@"
+
+class cmDirectoryId;
class cmExportBuildFileGenerator;
class cmExternalMakefileProjectGenerator;
class cmGeneratorTarget;
@@ -284,8 +287,7 @@ public:
bool NameResolvesToFramework(const std::string& libname) const;
cmMakefile* FindMakefile(const std::string& start_dir) const;
- ///! Find a local generator by its startdirectory
- cmLocalGenerator* FindLocalGenerator(const std::string& start_dir) const;
+ cmLocalGenerator* FindLocalGenerator(cmDirectoryId const& id) const;
/** Append the subdirectory for the given configuration. If anything is
appended the given prefix and suffix will be appended around it, which
@@ -305,6 +307,10 @@ public:
void IndexTarget(cmTarget* t);
void IndexGeneratorTarget(cmGeneratorTarget* gt);
+ // Index the target using a name that is unique to that target
+ // even if other targets have the same name.
+ std::string IndexGeneratorTargetUniquely(cmGeneratorTarget const* gt);
+
static bool IsReservedTarget(std::string const& name);
virtual const char* GetAllTargetName() const { return "ALL_BUILD"; }
@@ -514,6 +520,7 @@ private:
typedef std::unordered_map<std::string, cmGeneratorTarget*>
GeneratorTargetMap;
typedef std::unordered_map<std::string, cmMakefile*> MakefileMap;
+ typedef std::unordered_map<std::string, cmLocalGenerator*> LocalGeneratorMap;
// Map efficiently from target name to cmTarget instance.
// Do not use this structure for looping over all targets.
// It contains both normal and globally visible imported targets.
@@ -525,6 +532,11 @@ private:
// It may not contain all of them (see note in IndexMakefile method).
MakefileMap MakefileSearchIndex;
+ // Map efficiently from source directory path to cmLocalGenerator instance.
+ // Do not use this structure for looping over all directories.
+ // Its order is not deterministic.
+ LocalGeneratorMap LocalGeneratorSearchIndex;
+
cmMakefile* TryCompileOuterMakefile;
// If you add a new map here, make sure it is copied
// in EnableLanguagesFromGenerator
@@ -583,6 +595,7 @@ private:
std::string const& reason) const;
void IndexMakefile(cmMakefile* mf);
+ void IndexLocalGenerator(cmLocalGenerator* lg);
virtual const char* GetBuildIgnoreErrorsFlag() const { return nullptr; }
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index dce7bd0..fdcf0a8 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -11,6 +11,7 @@
#include <iterator>
#include <memory> // IWYU pragma: keep
#include <sstream>
+#include <stdio.h>
#include <stdlib.h>
#include <utility>
@@ -48,6 +49,11 @@
class cmMessenger;
+cmDirectoryId::cmDirectoryId(std::string s)
+ : String(std::move(s))
+{
+}
+
// default is not to be building executables
cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
cmStateSnapshot const& snapshot)
@@ -111,6 +117,17 @@ cmMakefile::~cmMakefile()
cmDeleteAll(this->EvaluationFiles);
}
+cmDirectoryId cmMakefile::GetDirectoryId() const
+{
+ // Use the instance pointer value to uniquely identify this directory.
+ // If we ever need to expose this to CMake language code we should
+ // add a read-only property in cmMakefile::GetProperty.
+ char buf[32];
+ sprintf(buf, "<%p>",
+ static_cast<void const*>(this)); // cast avoids format warning
+ return std::string(buf);
+}
+
void cmMakefile::IssueMessage(cmake::MessageType t,
std::string const& text) const
{
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index 0ab4371..54730b5 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -47,6 +47,14 @@ class cmTest;
class cmTestGenerator;
class cmVariableWatch;
+/** A type-safe wrapper for a string representing a directory id. */
+class cmDirectoryId
+{
+public:
+ cmDirectoryId(std::string s);
+ std::string String;
+};
+
/** \class cmMakefile
* \brief Process the input CMakeLists.txt file.
*
@@ -75,6 +83,8 @@ public:
*/
~cmMakefile();
+ cmDirectoryId GetDirectoryId() const;
+
bool ReadListFile(const char* filename);
bool ReadDependentFile(const char* filename, bool noPolicyScope = true);
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 91ed924..4ffe803 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -230,7 +230,11 @@ class cmMakefile;
SELECT(POLICY, CMP0077, "option() honors normal variables.", 3, 13, 0, \
cmPolicies::WARN) \
SELECT(POLICY, CMP0078, "UseSWIG generates standard target names.", 3, 13, \
- 0, cmPolicies::WARN)
+ 0, cmPolicies::WARN) \
+ SELECT( \
+ POLICY, CMP0079, \
+ "target_link_libraries allows use with targets in other directories.", 3, \
+ 13, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index cfcb31a..cd40223 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -745,20 +745,27 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const
void cmTarget::AddLinkLibrary(cmMakefile& mf, const std::string& lib,
cmTargetLinkLibraryType llt)
{
- cmTarget* tgt = this->Makefile->FindTargetToUse(lib);
+ this->AddLinkLibrary(mf, lib, lib, llt);
+}
+
+void cmTarget::AddLinkLibrary(cmMakefile& mf, std::string const& lib,
+ std::string const& libRef,
+ cmTargetLinkLibraryType llt)
+{
+ cmTarget* tgt = mf.FindTargetToUse(lib);
{
const bool isNonImportedTarget = tgt && !tgt->IsImported();
const std::string libName =
(isNonImportedTarget && llt != GENERAL_LibraryType)
- ? targetNameGenex(lib)
- : lib;
+ ? targetNameGenex(libRef)
+ : libRef;
this->AppendProperty(
"LINK_LIBRARIES",
this->GetDebugGeneratorExpressions(libName, llt).c_str());
}
- if (cmGeneratorExpression::Find(lib) != std::string::npos ||
+ if (cmGeneratorExpression::Find(lib) != std::string::npos || lib != libRef ||
(tgt &&
(tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
tgt->GetType() == cmStateEnums::OBJECT_LIBRARY)) ||
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 7a3ab65..1f380df 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -142,6 +142,9 @@ public:
void AddLinkLibrary(cmMakefile& mf, const std::string& lib,
cmTargetLinkLibraryType llt);
+ void AddLinkLibrary(cmMakefile& mf, std::string const& lib,
+ std::string const& libRef, cmTargetLinkLibraryType llt);
+
enum TLLSignature
{
KeywordTLLSignature,
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 1bbcf46..ad33f98 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -359,30 +359,53 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
}
}
+ bool warnRemoteInterface = false;
+ bool rejectRemoteLinking = false;
+ bool encodeRemoteReference = false;
+ if (this->Makefile != this->Target->GetMakefile()) {
+ // The LHS target was created in another directory.
+ switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0079)) {
+ case cmPolicies::WARN:
+ warnRemoteInterface = true;
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ rejectRemoteLinking = true;
+ break;
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::NEW:
+ encodeRemoteReference = true;
+ break;
+ }
+ }
+
+ std::string libRef;
+ if (encodeRemoteReference && !cmSystemTools::FileIsFullPath(lib)) {
+ // This is a library name added by a caller that is not in the
+ // same directory as the target was created. Add a suffix to
+ // the name to tell ResolveLinkItem to look up the name in the
+ // caller's directory.
+ cmDirectoryId const dirId = this->Makefile->GetDirectoryId();
+ libRef = lib + CMAKE_DIRECTORY_ID_SEP + dirId.String;
+ } else {
+ // This is an absolute path or a library name added by a caller
+ // in the same directory as the target was created. We can use
+ // the original name directly.
+ libRef = lib;
+ }
+
// Handle normal case where the command was called with another keyword than
// INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES"
// property of the target on the LHS shall be populated.)
if (this->CurrentProcessingState != ProcessingKeywordLinkInterface &&
this->CurrentProcessingState != ProcessingPlainLinkInterface) {
- // Assure that the target on the LHS was created in the current directory.
- cmTarget* t =
- this->Makefile->FindLocalNonAliasTarget(this->Target->GetName());
- if (!t) {
- const std::vector<cmTarget*>& importedTargets =
- this->Makefile->GetOwnedImportedTargets();
- for (cmTarget* importedTarget : importedTargets) {
- if (importedTarget->GetName() == this->Target->GetName()) {
- t = importedTarget;
- break;
- }
- }
- }
- if (!t) {
+ if (rejectRemoteLinking) {
std::ostringstream e;
e << "Attempt to add link library \"" << lib << "\" to target \""
<< this->Target->GetName()
- << "\" which is not built in this directory.";
+ << "\" which is not built in this directory.\n"
+ << "This is allowed only when policy CMP0079 is set to NEW.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
return false;
}
@@ -404,7 +427,20 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
}
- this->Target->AddLinkLibrary(*this->Makefile, lib, llt);
+ this->Target->AddLinkLibrary(*this->Makefile, lib, libRef, llt);
+ }
+
+ if (warnRemoteInterface) {
+ std::ostringstream w;
+ /* clang-format off */
+ w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0079) << "\n"
+ "Target\n " << this->Target->GetName() << "\nis not created in this "
+ "directory. For compatibility with older versions of CMake, link "
+ "library\n " << lib << "\nwill be looked up in the directory in "
+ "which the target was created rather than in this calling "
+ "directory.";
+ /* clang-format on */
+ this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
}
// Handle (additional) case where the command was called with PRIVATE /
@@ -415,9 +451,9 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
this->CurrentProcessingState == ProcessingPlainPrivateInterface) {
if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
std::string configLib =
- this->Target->GetDebugGeneratorExpressions(lib, llt);
- if (cmGeneratorExpression::IsValidTargetName(lib) ||
- cmGeneratorExpression::Find(lib) != std::string::npos) {
+ this->Target->GetDebugGeneratorExpressions(libRef, llt);
+ if (cmGeneratorExpression::IsValidTargetName(libRef) ||
+ cmGeneratorExpression::Find(libRef) != std::string::npos) {
configLib = "$<LINK_ONLY:" + configLib + ">";
}
this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
@@ -431,7 +467,7 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
// property of the target on the LHS shall be populated.)
this->Target->AppendProperty(
"INTERFACE_LINK_LIBRARIES",
- this->Target->GetDebugGeneratorExpressions(lib, llt).c_str());
+ this->Target->GetDebugGeneratorExpressions(libRef, llt).c_str());
// Stop processing if called without any keyword.
if (this->CurrentProcessingState == ProcessingLinkLibraries) {
@@ -464,12 +500,12 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
for (std::string const& dc : debugConfigs) {
prop = "LINK_INTERFACE_LIBRARIES_";
prop += dc;
- this->Target->AppendProperty(prop, lib.c_str());
+ this->Target->AppendProperty(prop, libRef.c_str());
}
}
if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) {
// Put in the non-DEBUG configuration interfaces.
- this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str());
+ this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", libRef.c_str());
// Make sure the DEBUG configuration interfaces exist so that the
// general one will not be used as a fall-back.
diff --git a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
index e11f980..85ce1f7 100644
--- a/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
+++ b/Tests/CMakeCommands/target_link_libraries/CMakeLists.txt
@@ -130,3 +130,15 @@ target_link_libraries(newsignature1 PRIVATE depC INTERFACE depD PUBLIC depB PRIV
assert_property(newsignature1 INTERFACE_LINK_LIBRARIES "depD;depB")
assert_property(newsignature1 LINK_LIBRARIES "depC;depB;subdirlib")
+
+#----------------------------------------------------------------------------
+# Test cross-directory linking.
+cmake_policy(PUSH)
+cmake_policy(SET CMP0079 NEW)
+add_executable(TopDir TopDir.c)
+add_subdirectory(SubDirA)
+add_subdirectory(SubDirB)
+target_link_libraries(SubDirB TopDirImported)
+add_library(TopDirImported IMPORTED INTERFACE)
+target_compile_definitions(TopDirImported INTERFACE DEF_TopDirImported)
+cmake_policy(POP)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt
new file mode 100644
index 0000000..4dae103
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirA/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_executable(SubDirA SubDirA.c)
+
+# Link to a target imported in this directory that would not normally
+# be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC SameNameImported)
+
+# Link SubDirA to a target imported in this directory that has the same
+# name as a target imported in SubDirB's directory. SubDirB will also
+# tell us to link its copy. At compile time we verify both are linked.
+target_link_libraries(SubDirA PRIVATE SameNameImported)
+
+# Import a target with the same name as a target imported in SubDirB.
+# Distinguish this copy by having a unique usage requirement.
+add_library(SameNameImported IMPORTED INTERFACE)
+target_compile_definitions(SameNameImported INTERFACE DEF_SameNameImportedSubDirA)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c b/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c
new file mode 100644
index 0000000..4706bb9
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirA/SubDirA.c
@@ -0,0 +1,14 @@
+#ifndef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is not defined but should be!"
+#endif
+#ifndef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is not defined but should be!"
+#endif
+#ifdef DEF_TopDirImported
+# error "DEF_TopDirImported is defined but should not be!"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
new file mode 100644
index 0000000..7c918e6
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_executable(SubDirB SubDirB.c)
+
+# Link to a target imported in this directory that would not normally
+# be visible to the directory in which TopDir is defined.
+target_link_libraries(TopDir PUBLIC SameNameImported)
+
+# Link SubDirA to a target imported in this directory that has the same
+# name as a target imported in SubDirA's directory. We verify when
+# compiling SubDirA that it sees our target and its own.
+target_link_libraries(SubDirA PRIVATE SameNameImported)
+
+# Import a target with the same name as a target imported in SubDirA.
+# Distinguish this copy by having a unique usage requirement.
+add_library(SameNameImported IMPORTED INTERFACE)
+target_compile_definitions(SameNameImported INTERFACE DEF_SameNameImportedSubDirB)
diff --git a/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c b/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c
new file mode 100644
index 0000000..6e56729
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/SubDirB/SubDirB.c
@@ -0,0 +1,14 @@
+#ifdef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is defined but should not be!"
+#endif
+#ifdef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is defined but should not be!"
+#endif
+#ifndef DEF_TopDirImported
+# error "DEF_TopDirImported is not defined but should be!"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_libraries/TopDir.c b/Tests/CMakeCommands/target_link_libraries/TopDir.c
new file mode 100644
index 0000000..4706bb9
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_libraries/TopDir.c
@@ -0,0 +1,14 @@
+#ifndef DEF_SameNameImportedSubDirA
+# error "DEF_SameNameImportedSubDirA is not defined but should be!"
+#endif
+#ifndef DEF_SameNameImportedSubDirB
+# error "DEF_SameNameImportedSubDirB is not defined but should be!"
+#endif
+#ifdef DEF_TopDirImported
+# error "DEF_TopDirImported is defined but should not be!"
+#endif
+
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index fdb2fa1..cb048be 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -155,6 +155,13 @@ add_library(testStaticLibRequiredPrivate testStaticLibRequiredPrivate.c)
target_link_libraries(testLibDepends PRIVATE testStaticLibRequiredPrivate)
cmake_policy(POP)
+cmake_policy(PUSH)
+cmake_policy(SET CMP0079 NEW)
+add_library(TopDirLib STATIC testTopDirLib.c)
+add_subdirectory(SubDirLinkA)
+add_subdirectory(SubDirLinkB)
+cmake_policy(POP)
+
macro(add_include_lib _libName)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c" "/* no content */\n")
add_library(${_libName} "${CMAKE_CURRENT_BINARY_DIR}/${_libName}.c")
@@ -508,6 +515,7 @@ install(
testLibCycleA testLibCycleB
testLibNoSONAME
cmp0022NEW cmp0022OLD
+ TopDirLib SubDirLinkA
systemlib
EXPORT exp
RUNTIME DESTINATION $<1:bin>$<0:/wrong>
@@ -566,6 +574,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
testSharedLibRequired testSharedLibRequiredUser testSharedLibRequiredUser2
testSharedLibDepends renamed_on_export
cmp0022NEW cmp0022OLD
+ TopDirLib SubDirLinkA
systemlib
NAMESPACE bld_
FILE ExportBuildTree.cmake
diff --git a/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
new file mode 100644
index 0000000..1c3c9dc
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkA/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(SubDirLinkAImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForExport)
+
+target_link_libraries(TopDirLib PUBLIC SubDirLinkAImported)
+
+add_library(SubDirLinkA STATIC SubDirLinkA.c)
diff --git a/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c b/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c
new file mode 100644
index 0000000..abf76f5
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkA/SubDirLinkA.c
@@ -0,0 +1,11 @@
+#ifdef DEF_SubDirLinkAImportedForExport
+# error "DEF_SubDirLinkAImportedForExport is defined but should not be!"
+#endif
+#ifndef DEF_SubDirLinkBImportedForExport
+# error "DEF_SubDirLinkBImportedForExport is not defined but should be!"
+#endif
+
+int testSubDirLinkA(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt b/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt
new file mode 100644
index 0000000..22e168f
--- /dev/null
+++ b/Tests/ExportImport/Export/SubDirLinkB/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(SubDirLinkBImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkBImported INTERFACE DEF_SubDirLinkBImportedForExport)
+
+target_link_libraries(SubDirLinkA PUBLIC SubDirLinkBImported)
diff --git a/Tests/ExportImport/Export/testTopDirLib.c b/Tests/ExportImport/Export/testTopDirLib.c
new file mode 100644
index 0000000..1ec68de
--- /dev/null
+++ b/Tests/ExportImport/Export/testTopDirLib.c
@@ -0,0 +1,11 @@
+#ifndef DEF_SubDirLinkAImportedForExport
+# error "DEF_SubDirLinkAImportedForExport is not defined but should be!"
+#endif
+#ifdef DEF_SubDirLinkBImportedForExport
+# error "DEF_SubDirLinkBImportedForExport is defined but should not be!"
+#endif
+
+int testTopDirLib(void)
+{
+ return 0;
+}
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 7510d7e..8791a19 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -1,3 +1,9 @@
+# Prepare imported targets that the exported project itself imported.
+add_library(SubDirLinkAImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkAImported INTERFACE DEF_SubDirLinkAImportedForImport)
+add_library(SubDirLinkBImported IMPORTED INTERFACE)
+target_compile_definitions(SubDirLinkBImported INTERFACE DEF_SubDirLinkBImportedForImport)
+
# Import targets from the exported build tree.
include(${Import_BINARY_DIR}/../Export/ExportBuildTree.cmake)
@@ -158,6 +164,11 @@ target_link_libraries(cmp0022OLD_exp_test exp_cmp0022OLD)
add_executable(cmp0022NEW_exp_test cmp0022NEW_test_vs6_2.cpp)
target_link_libraries(cmp0022NEW_exp_test exp_cmp0022NEW)
+add_executable(SubDirLink_bld SubDirLink.c)
+target_link_libraries(SubDirLink_bld PRIVATE bld_TopDirLib bld_SubDirLinkA)
+add_executable(SubDirLink_exp SubDirLink.c)
+target_link_libraries(SubDirLink_exp PRIVATE exp_TopDirLib exp_SubDirLinkA)
+
# Try building a plugin to an executable imported from the build tree.
add_library(imp_mod1b MODULE imp_mod1.c)
target_link_libraries(imp_mod1b bld_testExe2)
diff --git a/Tests/ExportImport/Import/A/SubDirLink.c b/Tests/ExportImport/Import/A/SubDirLink.c
new file mode 100644
index 0000000..eb4b860
--- /dev/null
+++ b/Tests/ExportImport/Import/A/SubDirLink.c
@@ -0,0 +1,14 @@
+#ifndef DEF_SubDirLinkAImportedForImport
+# error "DEF_SubDirLinkAImportedForImport is not defined but should be!"
+#endif
+#ifndef DEF_SubDirLinkBImportedForImport
+# error "DEF_SubDirLinkBImportedForImport is not defined but should be!"
+#endif
+
+extern int testTopDirLib(void);
+extern int testSubDirLinkA(void);
+
+int main(void)
+{
+ return (testTopDirLib() + testSubDirLinkA() + 0);
+}
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
new file mode 100644
index 0000000..89cd806
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW-stdout.txt
@@ -0,0 +1 @@
+-- INTERFACE_LINK_LIBRARIES='foo::@<[Xx0-9A-Fa-f]+>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW.cmake
new file mode 100644
index 0000000..82486c4
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0079 NEW)
+include(CMP0079-iface-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
new file mode 100644
index 0000000..e575e16
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD-stdout.txt
@@ -0,0 +1 @@
+-- INTERFACE_LINK_LIBRARIES='foo'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD.cmake
new file mode 100644
index 0000000..e04a2bb
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0079 OLD)
+include(CMP0079-iface-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
new file mode 100644
index 0000000..6dd7d30
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stderr.txt
@@ -0,0 +1,17 @@
+^CMake Warning \(dev\) at CMP0079-iface/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+ Policy CMP0079 is not set: target_link_libraries allows use with targets in
+ other directories. Run "cmake --help-policy CMP0079" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Target
+
+ top
+
+ is not created in this directory. For compatibility with older versions of
+ CMake, link library
+
+ foo
+
+ will be looked up in the directory in which the target was created rather
+ than in this calling directory.
+This warning is for project developers. Use -Wno-dev to suppress it.$
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
new file mode 100644
index 0000000..e575e16
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN-stdout.txt
@@ -0,0 +1 @@
+-- INTERFACE_LINK_LIBRARIES='foo'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN.cmake
new file mode 100644
index 0000000..2041893
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0079-iface-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface-common.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-iface-common.cmake
new file mode 100644
index 0000000..3982ff2
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface-common.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_executable(top empty.c)
+add_subdirectory(CMP0079-iface)
+get_property(libs TARGET top PROPERTY INTERFACE_LINK_LIBRARIES)
+message(STATUS "INTERFACE_LINK_LIBRARIES='${libs}'")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
new file mode 100644
index 0000000..4b15b32
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-iface/CMakeLists.txt
@@ -0,0 +1 @@
+target_link_libraries(top INTERFACE foo)
diff --git a/Tests/RunCMake/target_link_libraries/SubDirTarget-result.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-result.txt
index d00491f..d00491f 100644
--- a/Tests/RunCMake/target_link_libraries/SubDirTarget-result.txt
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-result.txt
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
new file mode 100644
index 0000000..b9fe3f6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus-stderr.txt
@@ -0,0 +1,6 @@
+^CMake Error at CMP0079-link-NEW-bogus.cmake:[0-9]+ \(add_executable\):
+ Target "top" links to target "foo::@<0xdeadbeef>" but the target was not
+ found. Perhaps a find_package\(\) call is missing for an IMPORTED target, or
+ an ALIAS target is missing\?
+Call Stack \(most recent call first\):
+ CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
new file mode 100644
index 0000000..8622f14
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-bogus.cmake
@@ -0,0 +1,6 @@
+cmake_policy(SET CMP0028 NEW)
+cmake_policy(SET CMP0079 NEW)
+enable_language(C)
+
+add_executable(top empty.c)
+set_property(TARGET top APPEND PROPERTY LINK_LIBRARIES "foo::@<0xdeadbeef>")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
new file mode 100644
index 0000000..84b30bd
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW-stdout.txt
@@ -0,0 +1 @@
+-- LINK_LIBRARIES='foo::@<[Xx0-9A-Fa-f]+>'
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW.cmake
new file mode 100644
index 0000000..72e4574
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-NEW.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0079 NEW)
+include(CMP0079-link-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-result.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt
new file mode 100644
index 0000000..0b4c4c6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at CMP0079-link/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+ Attempt to add link library "foo" to target "top" which is not built in
+ this directory.
+
+ This is allowed only when policy CMP0079 is set to NEW.$
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD.cmake
new file mode 100644
index 0000000..caa7231
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-OLD.cmake
@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0079 OLD)
+include(CMP0079-link-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-result.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-stderr.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-stderr.txt
new file mode 100644
index 0000000..0b4c4c6
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at CMP0079-link/CMakeLists.txt:[0-9]+ \(target_link_libraries\):
+ Attempt to add link library "foo" to target "top" which is not built in
+ this directory.
+
+ This is allowed only when policy CMP0079 is set to NEW.$
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN.cmake
new file mode 100644
index 0000000..e83818a
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-WARN.cmake
@@ -0,0 +1 @@
+include(CMP0079-link-common.cmake)
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link-common.cmake b/Tests/RunCMake/target_link_libraries/CMP0079-link-common.cmake
new file mode 100644
index 0000000..4f9454f
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link-common.cmake
@@ -0,0 +1,6 @@
+enable_language(C)
+
+add_executable(top empty.c)
+add_subdirectory(CMP0079-link)
+get_property(libs TARGET top PROPERTY LINK_LIBRARIES)
+message(STATUS "LINK_LIBRARIES='${libs}'")
diff --git a/Tests/RunCMake/target_link_libraries/CMP0079-link/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/CMP0079-link/CMakeLists.txt
new file mode 100644
index 0000000..8b2b3c9
--- /dev/null
+++ b/Tests/RunCMake/target_link_libraries/CMP0079-link/CMakeLists.txt
@@ -0,0 +1 @@
+target_link_libraries(top PUBLIC foo)
diff --git a/Tests/RunCMake/target_link_libraries/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/CMakeLists.txt
index 12cd3c7..8f85fbf 100644
--- a/Tests/RunCMake/target_link_libraries/CMakeLists.txt
+++ b/Tests/RunCMake/target_link_libraries/CMakeLists.txt
@@ -1,3 +1,3 @@
cmake_minimum_required(VERSION 2.8.4)
project(${RunCMake_TEST} NONE)
-include(${RunCMake_TEST}.cmake)
+include(${RunCMake_TEST}.cmake NO_POLICY_SCOPE)
diff --git a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
index 97b0888..a041d6d 100644
--- a/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
+++ b/Tests/RunCMake/target_link_libraries/RunCMakeTest.cmake
@@ -4,11 +4,17 @@ run_cmake(CMP0023-WARN)
run_cmake(CMP0023-NEW)
run_cmake(CMP0023-WARN-2)
run_cmake(CMP0023-NEW-2)
+run_cmake(CMP0079-iface-WARN)
+run_cmake(CMP0079-iface-OLD)
+run_cmake(CMP0079-iface-NEW)
+run_cmake(CMP0079-link-WARN)
+run_cmake(CMP0079-link-OLD)
+run_cmake(CMP0079-link-NEW)
+run_cmake(CMP0079-link-NEW-bogus)
run_cmake(ImportedTarget)
run_cmake(ImportedTargetFailure)
run_cmake(MixedSignature)
run_cmake(Separate-PRIVATE-LINK_PRIVATE-uses)
-run_cmake(SubDirTarget)
run_cmake(SharedDepNotTarget)
run_cmake(StaticPrivateDepNotExported)
run_cmake(StaticPrivateDepNotTarget)
diff --git a/Tests/RunCMake/target_link_libraries/SubDirTarget-stderr.txt b/Tests/RunCMake/target_link_libraries/SubDirTarget-stderr.txt
deleted file mode 100644
index 5cd1f23..0000000
--- a/Tests/RunCMake/target_link_libraries/SubDirTarget-stderr.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-^CMake Error at SubDirTarget.cmake:[0-9]+ \(target_link_libraries\):
- Attempt to add link library "m" to target "subexe" which is not built in
- this directory.
-Call Stack \(most recent call first\):
- CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/target_link_libraries/SubDirTarget.cmake b/Tests/RunCMake/target_link_libraries/SubDirTarget.cmake
deleted file mode 100644
index 32431ce..0000000
--- a/Tests/RunCMake/target_link_libraries/SubDirTarget.cmake
+++ /dev/null
@@ -1,3 +0,0 @@
-enable_language(C)
-add_subdirectory(SubDirTarget)
-target_link_libraries(subexe m)
diff --git a/Tests/RunCMake/target_link_libraries/SubDirTarget/CMakeLists.txt b/Tests/RunCMake/target_link_libraries/SubDirTarget/CMakeLists.txt
deleted file mode 100644
index b0b2380..0000000
--- a/Tests/RunCMake/target_link_libraries/SubDirTarget/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-add_executable(subexe ../empty.c)