LINK_DIRECTORIES: Add new properties and commands

These new capabilities enable to manage link directories

Two new properties:
* target properties: LINK_DIRECTORIES and INTERFACE_LINK_DIRECTORIES

One new command
* target_link_directories(): to populate target properties

Fixes: #17215
This commit is contained in:
Marc Chevrier 2018-09-14 17:48:20 +02:00 committed by Craig Scott
parent 5ca130e223
commit a71caab46b
41 changed files with 662 additions and 62 deletions

View File

@ -1,19 +1,45 @@
link_directories
----------------
Specify directories in which the linker will look for libraries.
Add directories in which the linker will look for libraries.
::
link_directories(directory1 directory2 ...)
link_directories(directory1 [directory2 ...])
Specify the paths in which the linker should search for libraries.
The command will apply only to targets created after it is called.
Add the paths in which the linker should search for libraries.
Relative paths given to this command are interpreted as relative to
the current source directory, see :policy:`CMP0015`.
Note that this command is rarely necessary. Library locations
returned by :command:`find_package` and :command:`find_library` are
absolute paths. Pass these absolute library file paths directly to the
:command:`target_link_libraries` command. CMake will ensure the linker finds
them.
The directories are added to the :prop_dir:`LINK_DIRECTORIES` directory
property for the current ``CMakeLists.txt`` file, converting relative
paths to absolute as needed.
The command will apply only to targets created after it is called.
Arguments to ``link_directories`` 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.
.. note::
This command is rarely necessary and should be avoided where there are
other choices. Prefer to pass full absolute paths to libraries where
possible, since this ensures the correct library will always be linked.
The :command:`find_library` command provides the full path, which can
generally be used directly in calls to :command:`target_link_libraries`.
Situations where a library search path may be needed include:
- Project generators like Xcode where the user can switch target
architecture at build time, but a full path to a library cannot
be used because it only provides one architecture (i.e. it is not
a universal binary).
- Libraries may themselves have other private library dependencies
that expect to be found via ``RPATH`` mechanisms, but some linkers
are not able to fully decode those paths (e.g. due to the presence
of things like ``$ORIGIN``).
If a library search path must be provided, prefer to localize the effect
where possible by using the :command:`target_link_directories` command
rather than ``link_directories()``. The target-specific command can also
control how the search directories propagate to other dependent targets.

View File

@ -0,0 +1,55 @@
target_link_directories
-----------------------
Add link directories to a target.
::
target_link_directories(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
Specify the paths in which the linker should search for libraries when
linking a given target. Each item can be an absolute or relative path,
with the latter being interpreted as relative to the current source
directory. These items will be added to the link command.
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>`.
The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
specify the scope of the items that follow them. ``PRIVATE`` and
``PUBLIC`` items will populate the :prop_tgt:`LINK_DIRECTORIES` property
of ``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
:prop_tgt:`INTERFACE_LINK_DIRECTORIES` property of ``<target>``
(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items).
Each item specifies a link directory and will be converted to an absolute
path if necessary before adding it to the relevant property. Repeated
calls for the same ``<target>`` append items in the order called.
If ``BEFORE`` is specified, the content will be prepended to the relevant
property instead of being appended.
Arguments to ``target_link_directories`` 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.
.. note::
This command is rarely necessary and should be avoided where there are
other choices. Prefer to pass full absolute paths to libraries where
possible, since this ensures the correct library will always be linked.
The :command:`find_library` command provides the full path, which can
generally be used directly in calls to :command:`target_link_libraries`.
Situations where a library search path may be needed include:
- Project generators like Xcode where the user can switch target
architecture at build time, but a full path to a library cannot
be used because it only provides one architecture (i.e. it is not
a universal binary).
- Libraries may themselves have other private library dependencies
that expect to be found via ``RPATH`` mechanisms, but some linkers
are not able to fully decode those paths (e.g. due to the presence
of things like ``$ORIGIN``).

View File

@ -111,6 +111,7 @@ These commands are available only in CMake projects.
/command/target_compile_features
/command/target_compile_options
/command/target_include_directories
/command/target_link_directories
/command/target_link_libraries
/command/target_link_options
/command/target_sources

View File

@ -228,6 +228,7 @@ Properties on Targets
/prop_tgt/INTERFACE_COMPILE_OPTIONS
/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
/prop_tgt/INTERFACE_LINK_DEPENDS
/prop_tgt/INTERFACE_LINK_DIRECTORIES
/prop_tgt/INTERFACE_LINK_LIBRARIES
/prop_tgt/INTERFACE_LINK_OPTIONS
/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
@ -252,6 +253,7 @@ Properties on Targets
/prop_tgt/LINK_DEPENDS_NO_SHARED
/prop_tgt/LINK_DEPENDS
/prop_tgt/LINKER_LANGUAGE
/prop_tgt/LINK_DIRECTORIES
/prop_tgt/LINK_FLAGS_CONFIG
/prop_tgt/LINK_FLAGS
/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG

View File

@ -3,6 +3,15 @@ LINK_DIRECTORIES
List of linker search directories.
This read-only property specifies the list of directories given so far
to the link_directories command. It is intended for debugging
purposes.
This property holds a :ref:`;-list <CMake Language Lists>` of directories
and is typically populated using the :command:`link_directories` command.
It gets its initial value from its parent directory, if it has one.
The directory property is used to initialize the :prop_tgt:`LINK_DIRECTORIES`
target property when a target is created. That target property is used
by the generators to set the library search directories for the linker.
Contents of ``LINK_DIRECTORIES`` 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.

View File

@ -0,0 +1,9 @@
INTERFACE_LINK_DIRECTORIES
--------------------------
.. |property_name| replace:: link directories
.. |command_name| replace:: :command:`target_link_directories`
.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_DIRECTORIES``
.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_DIRECTORIES`
.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_DIRECTORIES>``
.. include:: INTERFACE_BUILD_PROPERTY.txt

View File

@ -0,0 +1,18 @@
LINK_DIRECTORIES
----------------
List of directories to use for the link step of shared library, module
and executable targets.
This property holds a :ref:`;-list <CMake Language Lists>` of directories
specified so far for its target. Use the :command:`target_link_directories`
command to append more search directories.
This property is initialized by the :prop_dir:`LINK_DIRECTORIES` directory
property when a target is created, and is used by the generators to set
the search directories for the linker.
Contents of ``LINK_DIRECTORIES`` 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.

View File

@ -0,0 +1,9 @@
LINK_DIRECTORIES
----------------
* CMake gained new capabilities to manage link directories:
* :prop_tgt:`LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DIRECTORIES`
target properties.
* :command:`target_link_directories` command to add link directories to
targets.

View File

@ -579,6 +579,8 @@ set(SRCS
cmTargetIncludeDirectoriesCommand.h
cmTargetLinkOptionsCommand.cxx
cmTargetLinkOptionsCommand.h
cmTargetLinkDirectoriesCommand.cxx
cmTargetLinkDirectoriesCommand.h
cmTargetLinkLibrariesCommand.cxx
cmTargetLinkLibrariesCommand.h
cmTargetPropCommandBase.cxx

View File

@ -171,7 +171,7 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
" for directory ", d);
return;
}
t->AddLinkDirectory(d);
t->InsertLinkDirectory(d, mf->GetBacktrace());
}
void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,

View File

@ -101,6 +101,7 @@
# include "cmRemoveDefinitionsCommand.h"
# include "cmSourceGroupCommand.h"
# include "cmSubdirDependsCommand.h"
# include "cmTargetLinkDirectoriesCommand.h"
# include "cmTargetLinkOptionsCommand.h"
# include "cmUseMangledMesaCommand.h"
# include "cmUtilitySourceCommand.h"
@ -278,6 +279,8 @@ void GetProjectCommands(cmState* state)
state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand);
state->AddBuiltinCommand("target_link_options",
new cmTargetLinkOptionsCommand);
state->AddBuiltinCommand("target_link_directories",
new cmTargetLinkDirectoriesCommand);
state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand);
state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand);
state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand);

View File

@ -357,10 +357,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
}
// Add the search path entries requested by the user to path ordering.
this->OrderLinkerSearchPath->AddUserDirectories(
this->Target->GetLinkDirectories());
this->OrderRuntimeSearchPath->AddUserDirectories(
this->Target->GetLinkDirectories());
std::vector<std::string> directories;
this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
this->OrderLinkerSearchPath->AddUserDirectories(directories);
this->OrderRuntimeSearchPath->AddUserDirectories(directories);
// Set up the implicit link directories.
this->LoadImplicitLinkInfo();
@ -387,8 +387,7 @@ cmComputeLinkInformation::cmComputeLinkInformation(
if (this->OldLinkDirMode) {
// Construct a mask to not bother with this behavior for link
// directories already specified by the user.
std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
this->OldLinkDirMask.insert(directories.begin(), directories.end());
}
this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(

View File

@ -98,6 +98,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);

View File

@ -451,6 +451,37 @@ void cmExportFileGenerator::PopulateLinkDependsInterface(
}
}
void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
{
cmGeneratorTarget* gt = tei->Target;
assert(preprocessRule == cmGeneratorExpression::InstallInterface);
const char* propName = "INTERFACE_LINK_DIRECTORIES";
const char* input = gt->GetProperty(propName);
if (!input) {
return;
}
if (!*input) {
properties[propName].clear();
return;
}
std::string prepro =
cmGeneratorExpression::Preprocess(input, preprocessRule, true);
if (!prepro.empty()) {
this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
if (!checkInterfaceDirs(prepro, gt, propName)) {
return;
}
properties[propName] = prepro;
}
}
void cmExportFileGenerator::PopulateInterfaceProperty(
const std::string& propName, cmGeneratorTarget* target,
cmGeneratorExpression::PreprocessContext preprocessRule,

View File

@ -147,6 +147,10 @@ protected:
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
void PopulateLinkDirectoriesInterface(
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
void PopulateLinkDependsInterface(
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,

View File

@ -106,6 +106,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
properties, missingTargets);
this->PopulateLinkDirectoriesInterface(
te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
this->PopulateLinkDependsInterface(
te, cmGeneratorExpression::InstallInterface, properties, missingTargets);

View File

@ -28,6 +28,7 @@ class cmGeneratorTarget;
SELECT(F, EvaluatingSources, SOURCES) \
SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \
SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \
SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \
SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS)
#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \

View File

@ -103,6 +103,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
, DebugCompileFeaturesDone(false)
, DebugCompileDefinitionsDone(false)
, DebugLinkOptionsDone(false)
, DebugLinkDirectoriesDone(false)
, DebugSourcesDone(false)
, LinkImplementationLanguageIsContextDependent(true)
, UtilityItemsDone(false)
@ -133,6 +134,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
t->GetLinkOptionsBacktraces(),
this->LinkOptionsEntries);
CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
t->GetLinkDirectoriesBacktraces(),
this->LinkDirectoriesEntries);
CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
t->GetSourceBacktraces(),
this->SourceEntries, true);
@ -150,6 +155,7 @@ cmGeneratorTarget::~cmGeneratorTarget()
cmDeleteAll(this->CompileFeaturesEntries);
cmDeleteAll(this->CompileDefinitionsEntries);
cmDeleteAll(this->LinkOptionsEntries);
cmDeleteAll(this->LinkDirectoriesEntries);
cmDeleteAll(this->SourceEntries);
cmDeleteAll(this->LinkInformation);
}
@ -1704,11 +1710,6 @@ cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
return this->Target->GetBacktrace();
}
const std::vector<std::string>& cmGeneratorTarget::GetLinkDirectories() const
{
return this->Target->GetLinkDirectories();
}
const std::set<std::string>& cmGeneratorTarget::GetUtilities() const
{
return this->Target->GetUtilities();
@ -3067,6 +3068,102 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
cmDeleteAll(entries);
}
namespace {
void processLinkDirectories(
cmGeneratorTarget const* tgt,
const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
std::vector<std::string>& directories,
std::unordered_set<std::string>& uniqueDirectories,
cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
bool debugDirectories, std::string const& language)
{
for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
cmLinkImplItem const& item = entry->LinkImplItem;
std::string const& targetName = item.AsStr();
std::vector<std::string> entryDirectories;
cmSystemTools::ExpandListArgument(
entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
dagChecker, language),
entryDirectories);
std::string usedDirectories;
for (std::string& entryDirectory : entryDirectories) {
if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
std::ostringstream e;
if (!targetName.empty()) {
/* clang-format off */
e << "Target \"" << targetName << "\" contains relative "
"path in its INTERFACE_LINK_DIRECTORIES:\n"
" \"" << entryDirectory << "\"";
/* clang-format on */
tgt->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str());
return;
}
}
// Sanitize the path the same way the link_directories command does
// in case projects set the LINK_DIRECTORIES property directly.
cmSystemTools::ConvertToUnixSlashes(entryDirectory);
if (uniqueDirectories.insert(entryDirectory).second) {
directories.push_back(entryDirectory);
if (debugDirectories) {
usedDirectories += " * " + entryDirectory + "\n";
}
}
}
if (!usedDirectories.empty()) {
tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
cmake::LOG,
std::string("Used link directories for target ") + tgt->GetName() +
":\n" + usedDirectories,
entry->ge->GetBacktrace());
}
}
}
}
void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const
{
std::unordered_set<std::string> uniqueDirectories;
cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
nullptr);
std::vector<std::string> debugProperties;
const char* debugProp =
this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
if (debugProp) {
cmSystemTools::ExpandListArgument(debugProp, debugProperties);
}
bool debugDirectories = !this->DebugLinkDirectoriesDone &&
std::find(debugProperties.begin(), debugProperties.end(),
"LINK_DIRECTORIES") != debugProperties.end();
if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
this->DebugLinkDirectoriesDone = true;
}
processLinkDirectories(this, this->LinkDirectoriesEntries, result,
uniqueDirectories, &dagChecker, config,
debugDirectories, language);
std::vector<cmGeneratorTarget::TargetPropertyEntry*>
linkInterfaceLinkDirectoriesEntries;
AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES",
linkInterfaceLinkDirectoriesEntries);
processLinkDirectories(this, linkInterfaceLinkDirectoriesEntries, result,
uniqueDirectories, &dagChecker, config,
debugDirectories, language);
cmDeleteAll(linkInterfaceLinkDirectoriesEntries);
}
namespace {
void processLinkDepends(
cmGeneratorTarget const* tgt,

View File

@ -273,8 +273,6 @@ public:
cmListFileBacktrace GetBacktrace() const;
const std::vector<std::string>& GetLinkDirectories() const;
std::set<std::string> const& GetUtilities() const;
cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const;
@ -435,6 +433,10 @@ public:
const std::string& config,
const std::string& language) const;
void GetLinkDirectories(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const;
void GetLinkDepends(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const;
@ -825,6 +827,7 @@ private:
std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
std::vector<TargetPropertyEntry*> LinkOptionsEntries;
std::vector<TargetPropertyEntry*> LinkDirectoriesEntries;
std::vector<TargetPropertyEntry*> SourceEntries;
mutable std::set<std::string> LinkImplicitNullProperties;
@ -874,6 +877,7 @@ private:
mutable bool DebugCompileFeaturesDone;
mutable bool DebugCompileDefinitionsDone;
mutable bool DebugLinkOptionsDone;
mutable bool DebugLinkDirectoriesDone;
mutable bool DebugSourcesDone;
mutable bool LinkImplementationLanguageIsContextDependent;
mutable bool UtilityItemsDone;

View File

@ -4,6 +4,7 @@
#include <sstream>
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmSystemTools.h"
@ -29,7 +30,8 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
{
std::string unixPath = dir;
cmSystemTools::ConvertToUnixSlashes(unixPath);
if (!cmSystemTools::FileIsFullPath(unixPath)) {
if (!cmSystemTools::FileIsFullPath(unixPath) &&
!cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
bool convertToAbsolute = false;
std::ostringstream e;
/* clang-format off */
@ -41,6 +43,7 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
case cmPolicies::WARN:
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0015);
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
break;
case cmPolicies::OLD:
// OLD behavior does not convert
break;
@ -61,5 +64,5 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
unixPath = tmp;
}
}
this->Makefile->AppendProperty("LINK_DIRECTORIES", unixPath.c_str());
this->Makefile->AddLinkDirectory(unixPath);
}

View File

@ -243,6 +243,17 @@ cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
}
cmStringRange cmMakefile::GetLinkDirectoriesEntries() const
{
return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
}
cmBacktraceRange cmMakefile::GetLinkDirectoriesBacktraces() const
{
return this->StateSnapshot.GetDirectory()
.GetLinkDirectoriesEntryBacktraces();
}
cmListFileBacktrace cmMakefile::GetBacktrace() const
{
return this->Backtrace;
@ -1237,6 +1248,11 @@ void cmMakefile::AddLinkOption(std::string const& option)
this->AppendProperty("LINK_OPTIONS", option.c_str());
}
void cmMakefile::AddLinkDirectory(std::string const& directory)
{
this->AppendProperty("LINK_DIRECTORIES", directory.c_str());
}
bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
{
// Create a regular expression to match valid definitions.
@ -1335,10 +1351,6 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
// link libraries
this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
// link directories
this->SetProperty("LINK_DIRECTORIES",
parent->GetProperty("LINK_DIRECTORIES"));
// the initial project name
this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
@ -1872,17 +1884,6 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
return;
default:;
}
if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
std::vector<std::string> linkDirs;
cmSystemTools::ExpandListArgument(linkDirsProp, linkDirs);
for (std::string& linkDir : linkDirs) {
// Sanitize the path the same way the link_directories command does
// in case projects set the LINK_DIRECTORIES property directly.
cmSystemTools::ConvertToUnixSlashes(linkDir);
target.AddLinkDirectory(linkDir);
}
}
if (const char* linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
std::vector<std::string> linkLibs;

View File

@ -182,6 +182,7 @@ public:
void AddCompileDefinition(std::string const& definition);
void AddCompileOption(std::string const& option);
void AddLinkOption(std::string const& option);
void AddLinkDirectory(std::string const& directory);
/** Create a new imported target with the name and type given. */
cmTarget* AddImportedTarget(const std::string& name,
@ -802,6 +803,8 @@ public:
cmBacktraceRange GetCompileDefinitionsBacktraces() const;
cmStringRange GetLinkOptionsEntries() const;
cmBacktraceRange GetLinkOptionsBacktraces() const;
cmStringRange GetLinkDirectoriesEntries() const;
cmBacktraceRange GetLinkDirectoriesBacktraces() const;
std::set<std::string> const& GetSystemIncludeDirectories() const
{

View File

@ -284,6 +284,8 @@ cmStateSnapshot cmState::Reset()
it->CompileOptionsBacktraces.clear();
it->LinkOptions.clear();
it->LinkOptionsBacktraces.clear();
it->LinkDirectories.clear();
it->LinkDirectoriesBacktraces.clear();
it->DirectoryEnd = pos;
it->NormalTargetNames.clear();
it->Properties.clear();
@ -660,6 +662,7 @@ cmStateSnapshot cmState::CreateBaseSnapshot()
pos->CompileDefinitionsPosition = 0;
pos->CompileOptionsPosition = 0;
pos->LinkOptionsPosition = 0;
pos->LinkDirectoriesPosition = 0;
pos->BuildSystemDirectory->DirectoryEnd = pos;
pos->Policies = this->PolicyStack.Root();
pos->PolicyRoot = this->PolicyStack.Root();
@ -813,6 +816,8 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot)
prevPos->BuildSystemDirectory->CompileOptions.size();
prevPos->LinkOptionsPosition =
prevPos->BuildSystemDirectory->LinkOptions.size();
prevPos->LinkDirectoriesPosition =
prevPos->BuildSystemDirectory->LinkDirectories.size();
prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
if (!pos->Keep && this->SnapshotData.IsLast(pos)) {

View File

@ -396,6 +396,43 @@ void cmStateDirectory::ClearLinkOptions()
this->Snapshot_.Position->LinkOptionsPosition);
}
cmStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
{
return GetPropertyContent(this->DirectoryState->LinkDirectories,
this->Snapshot_.Position->LinkDirectoriesPosition);
}
cmBacktraceRange cmStateDirectory::GetLinkDirectoriesEntryBacktraces() const
{
return GetPropertyBacktraces(
this->DirectoryState->LinkDirectories,
this->DirectoryState->LinkDirectoriesBacktraces,
this->Snapshot_.Position->LinkDirectoriesPosition);
}
void cmStateDirectory::AppendLinkDirectoriesEntry(
const std::string& vec, const cmListFileBacktrace& lfbt)
{
AppendEntry(this->DirectoryState->LinkDirectories,
this->DirectoryState->LinkDirectoriesBacktraces,
this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
}
void cmStateDirectory::SetLinkDirectories(const std::string& vec,
const cmListFileBacktrace& lfbt)
{
SetContent(this->DirectoryState->LinkDirectories,
this->DirectoryState->LinkDirectoriesBacktraces,
this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
}
void cmStateDirectory::ClearLinkDirectories()
{
ClearContent(this->DirectoryState->LinkDirectories,
this->DirectoryState->LinkDirectoriesBacktraces,
this->Snapshot_.Position->LinkDirectoriesPosition);
}
void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt)
{
@ -431,6 +468,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
this->SetLinkOptions(value, lfbt);
return;
}
if (prop == "LINK_DIRECTORIES") {
if (!value) {
this->ClearLinkDirectories();
return;
}
this->SetLinkDirectories(value, lfbt);
return;
}
this->DirectoryState->Properties.SetProperty(prop, value);
}
@ -455,6 +500,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop,
this->AppendLinkOptionsEntry(value, lfbt);
return;
}
if (prop == "LINK_DIRECTORIES") {
this->AppendLinkDirectoriesEntry(value, lfbt);
return;
}
this->DirectoryState->Properties.AppendProperty(prop, value, asString);
}
@ -542,6 +591,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
output = cmJoin(this->GetLinkOptionsEntries(), ";");
return output.c_str();
}
if (prop == "LINK_DIRECTORIES") {
output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
return output.c_str();
}
const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
if (!retVal && chain) {

View File

@ -65,6 +65,14 @@ public:
void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
void ClearLinkOptions();
cmStringRange GetLinkDirectoriesEntries() const;
cmBacktraceRange GetLinkDirectoriesEntryBacktraces() const;
void AppendLinkDirectoriesEntry(std::string const& vec,
cmListFileBacktrace const& lfbt);
void SetLinkDirectories(std::string const& vec,
cmListFileBacktrace const& lfbt);
void ClearLinkDirectories();
void SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt);
void AppendProperty(const std::string& prop, const char* value,

View File

@ -43,6 +43,7 @@ struct cmStateDetail::SnapshotDataType
std::vector<std::string>::size_type CompileDefinitionsPosition;
std::vector<std::string>::size_type CompileOptionsPosition;
std::vector<std::string>::size_type LinkOptionsPosition;
std::vector<std::string>::size_type LinkDirectoriesPosition;
};
struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
@ -88,6 +89,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType
std::vector<std::string> LinkOptions;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
std::vector<std::string> LinkDirectories;
std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> NormalTargetNames;
std::string ProjectName;

View File

@ -398,6 +398,13 @@ void cmStateSnapshot::InitializeFromParent()
this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
this->Position->LinkOptionsPosition);
InitializeContentFromParent(
parent->BuildSystemDirectory->LinkDirectories,
this->Position->BuildSystemDirectory->LinkDirectories,
parent->BuildSystemDirectory->LinkDirectoriesBacktraces,
this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces,
this->Position->LinkDirectoriesPosition);
const char* include_regex =
parent->BuildSystemDirectory->Properties.GetPropertyValue(
"INCLUDE_REGULAR_EXPRESSION");

View File

@ -168,6 +168,8 @@ public:
std::vector<cmListFileBacktrace> SourceBacktraces;
std::vector<std::string> LinkOptionsEntries;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
std::vector<std::string> LinkDirectoriesEntries;
std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> LinkImplementationPropertyEntries;
std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
};
@ -391,6 +393,18 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->Internal->LinkOptionsBacktraces.insert(
this->Internal->LinkOptionsBacktraces.end(),
parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
const cmStringRange parentLinkDirectories =
this->Makefile->GetLinkDirectoriesEntries();
const cmBacktraceRange parentLinkDirectoriesBts =
this->Makefile->GetLinkDirectoriesBacktraces();
this->Internal->LinkDirectoriesEntries.insert(
this->Internal->LinkDirectoriesEntries.end(),
parentLinkDirectories.begin(), parentLinkDirectories.end());
this->Internal->LinkDirectoriesBacktraces.insert(
this->Internal->LinkDirectoriesBacktraces.end(),
parentLinkDirectoriesBts.begin(), parentLinkDirectoriesBts.end());
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@ -654,19 +668,6 @@ cmSourceFile* cmTarget::AddSource(const std::string& src)
cmSourceFileLocationKind::Known);
}
void cmTarget::AddLinkDirectory(const std::string& d)
{
// Make sure we don't add unnecessary search directories.
if (this->LinkDirectoriesEmmitted.insert(d).second) {
this->LinkDirectories.push_back(d);
}
}
const std::vector<std::string>& cmTarget::GetLinkDirectories() const
{
return this->LinkDirectories;
}
void cmTarget::ClearDependencyInformation(cmMakefile& mf)
{
std::string depname = this->GetName();
@ -874,6 +875,16 @@ cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
return cmMakeRange(this->Internal->LinkOptionsBacktraces);
}
cmStringRange cmTarget::GetLinkDirectoriesEntries() const
{
return cmMakeRange(this->Internal->LinkDirectoriesEntries);
}
cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
{
return cmMakeRange(this->Internal->LinkDirectoriesBacktraces);
}
cmStringRange cmTarget::GetLinkImplementationEntries() const
{
return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
@ -900,6 +911,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
MAKE_STATIC_PROP(LINK_OPTIONS);
MAKE_STATIC_PROP(LINK_DIRECTORIES);
MAKE_STATIC_PROP(LINK_LIBRARIES);
MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
MAKE_STATIC_PROP(NAME);
@ -986,6 +998,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_DIRECTORIES) {
this->Internal->LinkDirectoriesEntries.clear();
this->Internal->LinkDirectoriesBacktraces.clear();
if (value) {
this->Internal->LinkDirectoriesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == propLINK_LIBRARIES) {
this->Internal->LinkImplementationPropertyEntries.clear();
this->Internal->LinkImplementationPropertyBacktraces.clear();
@ -1097,6 +1117,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkOptionsBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_DIRECTORIES") {
if (value && *value) {
this->Internal->LinkDirectoriesEntries.push_back(value);
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
}
} else if (prop == "LINK_LIBRARIES") {
if (value && *value) {
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
@ -1194,6 +1220,21 @@ void cmTarget::InsertLinkOption(std::string const& entry,
this->Internal->LinkOptionsBacktraces.insert(btPosition, bt);
}
void cmTarget::InsertLinkDirectory(std::string const& entry,
cmListFileBacktrace const& bt, bool before)
{
std::vector<std::string>::iterator position = before
? this->Internal->LinkDirectoriesEntries.begin()
: this->Internal->LinkDirectoriesEntries.end();
std::vector<cmListFileBacktrace>::iterator btPosition = before
? this->Internal->LinkDirectoriesBacktraces.begin()
: this->Internal->LinkDirectoriesBacktraces.end();
this->Internal->LinkDirectoriesEntries.insert(position, entry);
this->Internal->LinkDirectoriesBacktraces.insert(btPosition, bt);
}
static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
const char* value,
cmMakefile* context,
@ -1314,6 +1355,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
MAKE_STATIC_PROP(COMPILE_OPTIONS);
MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
MAKE_STATIC_PROP(LINK_OPTIONS);
MAKE_STATIC_PROP(LINK_DIRECTORIES);
MAKE_STATIC_PROP(IMPORTED);
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
@ -1330,6 +1372,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
specialProps.insert(propCOMPILE_OPTIONS);
specialProps.insert(propCOMPILE_DEFINITIONS);
specialProps.insert(propLINK_OPTIONS);
specialProps.insert(propLINK_DIRECTORIES);
specialProps.insert(propIMPORTED);
specialProps.insert(propIMPORTED_GLOBAL);
specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
@ -1397,6 +1440,16 @@ const char* cmTarget::GetProperty(const std::string& prop) const
output = cmJoin(this->Internal->LinkOptionsEntries, ";");
return output.c_str();
}
if (prop == propLINK_DIRECTORIES) {
if (this->Internal->LinkDirectoriesEntries.empty()) {
return nullptr;
}
static std::string output;
output = cmJoin(this->Internal->LinkDirectoriesEntries, ";");
return output.c_str();
}
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
if (this->Utilities.empty()) {
return nullptr;

View File

@ -154,10 +154,6 @@ public:
cmListFileContext const& lfc);
void GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const;
const std::vector<std::string>& GetLinkDirectories() const;
void AddLinkDirectory(const std::string& d);
/**
* Set the path where this target should be installed. This is relative to
* INSTALL_PREFIX
@ -247,6 +243,8 @@ public:
cmListFileBacktrace const& bt);
void InsertLinkOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before = false);
void InsertLinkDirectory(std::string const& entry,
cmListFileBacktrace const& bt, bool before = false);
void AppendBuildInterfaceIncludes();
@ -277,6 +275,9 @@ public:
cmStringRange GetLinkOptionsEntries() const;
cmBacktraceRange GetLinkOptionsBacktraces() const;
cmStringRange GetLinkDirectoriesEntries() const;
cmBacktraceRange GetLinkDirectoriesBacktraces() const;
cmStringRange GetLinkImplementationEntries() const;
cmBacktraceRange GetLinkImplementationBacktraces() const;
@ -306,14 +307,12 @@ private:
bool IsGeneratorProvided;
cmPropertyMap Properties;
std::set<std::string> SystemIncludeDirectories;
std::set<std::string> LinkDirectoriesEmmitted;
std::set<std::string> Utilities;
std::map<std::string, cmListFileBacktrace> UtilityBacktraces;
cmPolicies::PolicyMap PolicyMap;
std::string Name;
std::string InstallPath;
std::string RuntimeInstallPath;
std::vector<std::string> LinkDirectories;
std::vector<cmCustomCommand> PreBuildCommands;
std::vector<cmCustomCommand> PreLinkCommands;
std::vector<cmCustomCommand> PostBuildCommands;

View File

@ -0,0 +1,61 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmTargetLinkDirectoriesCommand.h"
#include <sstream>
#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmake.h"
class cmExecutionStatus;
bool cmTargetLinkDirectoriesCommand::InitialPass(
std::vector<std::string> const& args, cmExecutionStatus&)
{
return this->HandleArguments(args, "LINK_DIRECTORIES", PROCESS_BEFORE);
}
void cmTargetLinkDirectoriesCommand::HandleMissingTarget(
const std::string& name)
{
std::ostringstream e;
e << "Cannot specify link directories for target \"" << name
<< "\" which is not built by this project.";
this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
}
std::string cmTargetLinkDirectoriesCommand::Join(
const std::vector<std::string>& content)
{
std::vector<std::string> directories;
for (const auto& dir : content) {
auto unixPath = dir;
cmSystemTools::ConvertToUnixSlashes(unixPath);
if (!cmSystemTools::FileIsFullPath(unixPath) &&
!cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
auto tmp = this->Makefile->GetCurrentSourceDirectory();
tmp += "/";
tmp += unixPath;
unixPath = tmp;
}
directories.push_back(unixPath);
}
return cmJoin(directories, ";");
}
bool cmTargetLinkDirectoriesCommand::HandleDirectContent(
cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool)
{
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
tgt->InsertLinkDirectory(this->Join(content), lfbt, prepend);
return true; // Successfully handled.
}

View File

@ -0,0 +1,41 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmTargetLinkDirectoriesCommand_h
#define cmTargetLinkDirectoriesCommand_h
#include "cmConfigure.h" // IWYU pragma: keep
#include <string>
#include <vector>
#include "cmTargetPropCommandBase.h"
class cmCommand;
class cmExecutionStatus;
class cmTarget;
class cmTargetLinkDirectoriesCommand : public cmTargetPropCommandBase
{
public:
/**
* This is a virtual constructor for the command.
*/
cmCommand* Clone() override { return new cmTargetLinkDirectoriesCommand; }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) override;
private:
void HandleMissingTarget(const std::string& name) override;
std::string Join(const std::vector<std::string>& content) override;
bool HandleDirectContent(cmTarget* tgt,
const std::vector<std::string>& content,
bool prepend, bool system) override;
};
#endif

View File

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.12)
project(target_link_directories LANGUAGES C)
add_library(target_link_directories SHARED LinkDirectoriesLib.c)
# Test no items
target_link_directories(target_link_directories PRIVATE)
add_library(target_link_directories_2 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
target_link_directories(target_link_directories_2 PRIVATE /private/dir INTERFACE /interface/dir)
get_target_property(result target_link_directories_2 LINK_DIRECTORIES)
if (NOT result MATCHES "/private/dir")
message(SEND_ERROR "${result} target_link_directories not populated the LINK_DIRECTORIES target property")
endif()
get_target_property(result target_link_directories_2 INTERFACE_LINK_DIRECTORIES)
if (NOT result MATCHES "/interface/dir")
message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of shared library")
endif()
add_library(target_link_directories_3 STATIC EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
target_link_directories(target_link_directories_3 INTERFACE /interface/dir)
get_target_property(result target_link_directories_3 INTERFACE_LINK_DIRECTORIES)
if (NOT result MATCHES "/interface/dir")
message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of static library")
endif()
add_library(target_link_directories_4 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
target_link_directories(target_link_directories_4 PRIVATE relative/dir)
get_target_property(result target_link_directories_4 LINK_DIRECTORIES)
if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
endif()
add_subdirectory(subdir)
target_link_directories(target_link_directories_5 PRIVATE relative/dir)
get_target_property(result target_link_directories_5 LINK_DIRECTORIES)
if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
endif()

View File

@ -0,0 +1,7 @@
#if defined(_WIN32)
__declspec(dllexport)
#endif
int flags_lib(void)
{
return 0;
}

View File

@ -0,0 +1,2 @@
add_library(target_link_directories_5 SHARED EXCLUDE_FROM_ALL ../LinkDirectoriesLib.c)

View File

@ -2823,6 +2823,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CMakeCommands.add_compile_definitions add_compile_definitions)
ADD_TEST_MACRO(CMakeCommands.add_compile_options add_compile_options)
ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries)
ADD_TEST_MACRO(CMakeCommands.target_link_directories)
ADD_TEST_MACRO(CMakeCommands.target_include_directories target_include_directories)
ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions)
ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options)

View File

@ -618,6 +618,18 @@ install(TARGETS testLinkOptions
export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
#------------------------------------------------------------------------------
# test export of INTERFACE_LINK_DIRECTORIES
add_library(testLinkDirectories INTERFACE)
target_link_directories(testLinkDirectories INTERFACE
$<BUILD_INTERFACE:/interface/build>
$<INSTALL_INTERFACE:interface/install>)
install(TARGETS testLinkDirectories
EXPORT RequiredExp DESTINATION lib)
export(TARGETS testLinkDirectories NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
#------------------------------------------------------------------------------
# test export of INTERFACE_LINK_DEPENDS
if(CMAKE_GENERATOR MATCHES "Make|Ninja")

View File

@ -489,6 +489,11 @@ endif()
checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
#---------------------------------------------------------------------------------
# check that imported libraries have the expected INTERFACE_LINK_DIRECTORIES property
checkForProperty(bld_testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "/interface/build")
checkForProperty(Req::testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "${CMAKE_INSTALL_PREFIX}/interface/install")
#---------------------------------------------------------------------------------
# check that imported libraries have the expected INTERFACE_LINK_DEPENDS property
if(CMAKE_GENERATOR MATCHES "Make|Ninja")

View File

@ -1,6 +1,20 @@
cmake_minimum_required(VERSION 2.8)
project(LinkDirectoryExternal C)
add_executable(myexe2 myexe.c)
set_property(TARGET myexe2 PROPERTY OUTPUT_NAME LinkDirectory2)
target_link_directories(myexe2 PRIVATE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
target_link_libraries(myexe2 PRIVATE mylibA mylibB)
add_library (mylibs INTERFACE)
target_link_directories(mylibs INTERFACE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
target_link_libraries(mylibs INTERFACE mylibA mylibB)
add_executable(myexe3 myexe.c)
set_property(TARGET myexe3 PROPERTY OUTPUT_NAME LinkDirectory3)
target_link_libraries(myexe3 PRIVATE mylibs)
# Test CMP0015 OLD behavior: -L../lib
cmake_policy(SET CMP0015 OLD)
link_directories(../lib)

View File

@ -0,0 +1,2 @@
-- Target LINK_DIRECTORIES is 'a;b;c;d;;e'
-- Directory LINK_DIRECTORIES is 'a;b;c;d;;e'

View File

@ -0,0 +1,3 @@
include(Common.cmake)
test_target_property(LINK_DIRECTORIES)
test_directory_property(LINK_DIRECTORIES)

View File

@ -6,6 +6,7 @@ run_cmake(COMPILE_OPTIONS)
run_cmake(IMPORTED_GLOBAL)
run_cmake(INCLUDE_DIRECTORIES)
run_cmake(LINK_OPTIONS)
run_cmake(LINK_DIRECTORIES)
run_cmake(LINK_LIBRARIES)
run_cmake(SOURCES)
run_cmake(TYPE)