Merge topic 'link-directories'

f9717725f9 link_directories(): enhance capabilities
b5915744eb LINK_DIRECTORIES target property: add policy for absolute paths check.
a71caab46b LINK_DIRECTORIES: Add new properties and commands
5ca130e223 Refactoring: introduce function to check if a string is a generator expression

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2403
This commit is contained in:
Craig Scott
2018-09-26 12:11:28 +00:00
committed by Kitware Robot
68 changed files with 898 additions and 80 deletions

View File

@@ -1,19 +1,51 @@
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([AFTER|BEFORE] 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.
By default the directories specified are appended onto the current list of
directories. This default behavior can be changed by setting
:variable:`CMAKE_LINK_DIRECTORIES_BEFORE` to ``ON``. By using
``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
prepending, independent of the default.
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

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.13
.. toctree::
:maxdepth: 1
CMP0081: Relative paths not allowed in LINK_DIRECTORIES target property. </policy/CMP0081>
CMP0080: BundleUtilities cannot be included at configure time. </policy/CMP0080>
CMP0079: target_link_libraries allows use with targets in other directories. </policy/CMP0079>
CMP0078: UseSWIG generates standard target names. </policy/CMP0078>

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

@@ -179,6 +179,7 @@ Variables that Change Behavior
/variable/CMAKE_INSTALL_PREFIX
/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
/variable/CMAKE_LIBRARY_PATH
/variable/CMAKE_LINK_DIRECTORIES_BEFORE
/variable/CMAKE_MFC_FLAG
/variable/CMAKE_MODULE_PATH
/variable/CMAKE_NOT_USING_CONFIG_FLAGS

22
Help/policy/CMP0081.rst Normal file
View File

@@ -0,0 +1,22 @@
CMP0081
-------
Relative paths not allowed in :prop_tgt:`LINK_DIRECTORIES` target property.
CMake 3.12 and lower allowed the :prop_dir:`LINK_DIRECTORIES` directory
property to contain relative paths. The base path for such relative
entries is not well defined. CMake 3.13 and later will issue a
``FATAL_ERROR`` if the :prop_tgt:`LINK_DIRECTORIES` target property
(which is initialized by the :prop_dir:`LINK_DIRECTORIES` directory property)
contains a relative path.
The ``OLD`` behavior for this policy is not to warn about relative paths
in the :prop_tgt:`LINK_DIRECTORIES` target property. The ``NEW`` behavior for
this policy is to issue a ``FATAL_ERROR`` if :prop_tgt:`LINK_DIRECTORIES`
contains a relative path.
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

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,5 @@
LINK_DIRECTORIES-policy
-----------------------
* The :prop_tgt:`LINK_DIRECTORIES` target property expects absolute paths.
See policy :policy:`CMP0081`.

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

@@ -0,0 +1,5 @@
link_directories-enhancements
-----------------------------
* :command:`link_directories` command gains capability to control directories
insertion position.

View File

@@ -0,0 +1,9 @@
CMAKE_LINK_DIRECTORIES_BEFORE
-----------------------------
Whether to append or prepend directories by default in
:command:`link_directories`.
This variable affects the default behavior of the :command:`link_directories`
command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
option in all uses of that command.

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

@@ -168,7 +168,7 @@ static std::string stripAllGeneratorExpressions(const std::string& input)
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
if (c[0] == '$' && c[1] == '<') {
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -243,7 +243,7 @@ static std::string stripExportInterface(
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
if (c[0] == '$' && c[1] == '<') {
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -310,7 +310,7 @@ void cmGeneratorExpression::Split(const std::string& input,
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
if (c[0] == '$' && c[1] == '<') {
if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;

View File

@@ -63,6 +63,15 @@ public:
static std::string StripEmptyListElements(const std::string& input);
static inline bool StartsWithGeneratorExpression(const std::string& input)
{
return input.length() >= 2 && input[0] == '$' && input[1] == '<';
}
static inline bool StartsWithGeneratorExpression(const char* input)
{
return input != nullptr && input[0] == '$' && input[1] == '<';
}
private:
cmListFileBacktrace Backtrace;
};

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,126 @@ 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;
bool noMessage = false;
cmake::MessageType messageType = cmake::FATAL_ERROR;
if (!targetName.empty()) {
/* clang-format off */
e << "Target \"" << targetName << "\" contains relative "
"path in its INTERFACE_LINK_DIRECTORIES:\n"
" \"" << entryDirectory << "\"";
/* clang-format on */
} else {
switch (tgt->GetPolicyStatusCMP0081()) {
case cmPolicies::WARN: {
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
messageType = cmake::AUTHOR_WARNING;
} break;
case cmPolicies::OLD:
noMessage = true;
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::NEW:
// Issue the fatal message.
break;
}
e << "Found relative path while evaluating link directories of "
"\""
<< tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
}
if (!noMessage) {
tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
if (messageType == cmake::FATAL_ERROR) {
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

@@ -5,6 +5,7 @@
#include <algorithm>
#include <set>
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -69,11 +70,6 @@ bool cmIncludeDirectoryCommand::InitialPass(
return true;
}
static bool StartsWithGeneratorExpression(const std::string& input)
{
return input[0] == '$' && input[1] == '<';
}
// do a lot of cleanup on the arguments because this is one place where folks
// sometimes take the output of a program and pass it directly into this
// command not thinking that a single argument could be filled with spaces
@@ -124,7 +120,7 @@ void cmIncludeDirectoryCommand::NormalizeInclude(std::string& inc)
cmSystemTools::ConvertToUnixSlashes(inc);
if (!cmSystemTools::FileIsFullPath(inc)) {
if (!StartsWithGeneratorExpression(inc)) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(inc)) {
std::string tmp = this->Makefile->GetCurrentSourceDirectory();
tmp += "/";
tmp += inc;

View File

@@ -4,6 +4,8 @@
#include <sstream>
#include "cmAlgorithms.h"
#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmSystemTools.h"
@@ -19,17 +21,34 @@ bool cmLinkDirectoriesCommand::InitialPass(
return true;
}
for (std::string const& i : args) {
this->AddLinkDir(i);
bool before = this->Makefile->IsOn("CMAKE_LINK_DIRECTORIES_BEFORE");
auto i = args.cbegin();
if ((*i) == "BEFORE") {
before = true;
++i;
} else if ((*i) == "AFTER") {
before = false;
++i;
}
std::vector<std::string> directories;
for (; i != args.cend(); ++i) {
this->AddLinkDir(*i, directories);
}
this->Makefile->AddLinkDirectory(cmJoin(directories, ";"), before);
return true;
}
void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
void cmLinkDirectoriesCommand::AddLinkDir(
std::string const& dir, std::vector<std::string>& directories)
{
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 +60,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 +81,5 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
unixPath = tmp;
}
}
this->Makefile->AppendProperty("LINK_DIRECTORIES", unixPath.c_str());
directories.push_back(unixPath);
}

View File

@@ -36,7 +36,8 @@ public:
cmExecutionStatus& status) override;
private:
void AddLinkDir(std::string const& dir);
void AddLinkDir(std::string const& dir,
std::vector<std::string>& directories);
};
#endif

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,18 @@ void cmMakefile::AddLinkOption(std::string const& option)
this->AppendProperty("LINK_OPTIONS", option.c_str());
}
void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
{
cmListFileBacktrace lfbt = this->GetBacktrace();
if (before) {
this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory,
lfbt);
} else {
this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory,
lfbt);
}
}
bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
{
// Create a regular expression to match valid definitions.
@@ -1335,10 +1358,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 +1891,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, bool before = false);
/** 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

@@ -237,7 +237,10 @@ class cmMakefile;
13, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0080, \
"BundleUtilities cannot be included at configure time", 3, 13, 0, \
cmPolicies::WARN)
cmPolicies::WARN) \
SELECT(POLICY, CMP0081, \
"Relative paths not allowed in LINK_DIRECTORIES target property.", \
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) \
@@ -263,7 +266,8 @@ class cmMakefile;
F(CMP0068) \
F(CMP0069) \
F(CMP0073) \
F(CMP0076)
F(CMP0076) \
F(CMP0081)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies

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,70 @@ 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::PrependLinkDirectoriesEntry(
const std::string& vec, const cmListFileBacktrace& lfbt)
{
std::vector<std::string>::iterator entryEnd =
this->DirectoryState->LinkDirectories.begin() +
this->Snapshot_.Position->LinkDirectoriesPosition;
std::vector<std::string>::reverse_iterator rend =
this->DirectoryState->LinkDirectories.rend();
std::vector<std::string>::reverse_iterator rbegin =
cmMakeReverseIterator(entryEnd);
rbegin = std::find(rbegin, rend, cmPropertySentinal);
std::vector<std::string>::iterator entryIt = rbegin.base();
std::vector<std::string>::iterator entryBegin =
this->DirectoryState->LinkDirectories.begin();
std::vector<cmListFileBacktrace>::iterator btIt =
this->DirectoryState->LinkDirectoriesBacktraces.begin() +
std::distance(entryBegin, entryIt);
this->DirectoryState->LinkDirectories.insert(entryIt, vec);
this->DirectoryState->LinkDirectoriesBacktraces.insert(btIt, lfbt);
this->Snapshot_.Position->LinkDirectoriesPosition =
this->DirectoryState->LinkDirectories.size();
}
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 +495,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 +527,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 +618,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

@@ -62,9 +62,19 @@ public:
cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
void AppendLinkOptionsEntry(std::string const& vec,
cmListFileBacktrace const& lfbt);
void PrependLinkDirectoriesEntry(std::string const& vec,
cmListFileBacktrace const& lfbt);
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 &&
@@ -514,9 +528,7 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
std::string srcFiles;
const char* sep = "";
for (auto filename : srcs) {
const char* src = filename.c_str();
if (!(src[0] == '$' && src[1] == '<')) {
if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
filename = this->ProcessSourceItemCMP0049(filename);
if (filename.empty()) {
@@ -656,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();
@@ -876,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);
@@ -902,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);
@@ -988,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();
@@ -1099,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();
@@ -1196,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,
@@ -1316,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);
@@ -1332,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);
@@ -1399,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,30 @@
cmake_minimum_required(VERSION 3.12)
project(link_directories LANGUAGES C)
link_directories(/A)
link_directories(BEFORE /B)
set(CMAKE_LINK_DIRECTORIES_BEFORE ON)
link_directories(/C)
get_directory_property(result LINK_DIRECTORIES)
if (NOT result MATCHES "/C;/B;/A")
message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES directory property")
endif()
add_executable(link_directories EXCLUDE_FROM_ALL LinkDirectoriesExe.c)
get_target_property(result link_directories LINK_DIRECTORIES)
if (NOT result MATCHES "/C;/B;/A")
message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES target property")
endif()
add_library(imp UNKNOWN IMPORTED)
get_target_property(result imp LINK_DIRECTORIES)
if (result)
message(FATAL_ERROR "link_directories populated the LINK_DIRECTORIES target property")
endif()

View File

@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}

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

@@ -2830,6 +2830,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CMakeCommands.add_link_options)
ADD_TEST_MACRO(CMakeCommands.target_link_options)
ADD_TEST_MACRO(CMakeCommands.link_directories)
ADD_TEST_MACRO(CMakeCommands.target_link_directories)
# The cmake server-mode test requires python for a simple client.
find_package(PythonInterp QUIET)

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,5 @@
enable_language(CXX)
add_library(foo SHARED empty.cpp)
set_target_properties(foo PROPERTIES LINK_DIRECTORIES "../lib")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,4 @@
CMake Error in CMakeLists.txt:
Found relative path while evaluating link directories of "foo":
"../lib"

View File

@@ -0,0 +1,4 @@
cmake_policy(SET CMP0081 NEW)
include (CMP0081-Common.cmake)

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,4 @@
cmake_policy(SET CMP0081 OLD)
include (CMP0081-Common.cmake)

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,10 @@
CMake Warning \(dev\) in CMakeLists.txt:
Policy CMP0081 is not set: Relative paths not allowed in LINK_DIRECTORIES
target property. Run "cmake --help-policy CMP0081" for policy details.
Use the cmake_policy command to set the policy and suppress this warning.
Found relative path while evaluating link directories of "foo":
"../lib"
This warning is for project developers. Use -Wno-dev to suppress it.

View File

@@ -0,0 +1,2 @@
include (CMP0081-Common.cmake)

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.1)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,5 @@
include(RunCMake)
run_cmake(CMP0081-OLD)
run_cmake(CMP0081-NEW)
run_cmake(CMP0081-WARN)

View File

@@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}

View File

@@ -106,6 +106,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Darwin AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
add_RunCMake_test(CMP0068)
endif()
add_RunCMake_test(CMP0069)
add_RunCMake_test(CMP0081)
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode

View File

@@ -25,6 +25,7 @@
\* CMP0069
\* CMP0073
\* CMP0076
\* CMP0081
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

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)