diff options
68 files changed, 898 insertions, 80 deletions
diff --git a/Help/command/link_directories.rst b/Help/command/link_directories.rst index 5c64bc6..1dce9a0 100644 --- a/Help/command/link_directories.rst +++ b/Help/command/link_directories.rst @@ -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. diff --git a/Help/command/target_link_directories.rst b/Help/command/target_link_directories.rst new file mode 100644 index 0000000..b46aac0 --- /dev/null +++ b/Help/command/target_link_directories.rst @@ -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``). diff --git a/Help/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst index 753647d..0cc5fca 100644 --- a/Help/manual/cmake-commands.7.rst +++ b/Help/manual/cmake-commands.7.rst @@ -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 diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 904ebee..2cc52fe 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.13 .. toctree:: :maxdepth: 1 + 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> diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 8ccd7f6..5c3eb81 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -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 diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 6071999..78353fb 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -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 diff --git a/Help/policy/CMP0081.rst b/Help/policy/CMP0081.rst new file mode 100644 index 0000000..d3b2872 --- /dev/null +++ b/Help/policy/CMP0081.rst @@ -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 diff --git a/Help/prop_dir/LINK_DIRECTORIES.rst b/Help/prop_dir/LINK_DIRECTORIES.rst index fa37576..f9fb815 100644 --- a/Help/prop_dir/LINK_DIRECTORIES.rst +++ b/Help/prop_dir/LINK_DIRECTORIES.rst @@ -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. diff --git a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst new file mode 100644 index 0000000..56a4ec0 --- /dev/null +++ b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst @@ -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 diff --git a/Help/prop_tgt/LINK_DIRECTORIES.rst b/Help/prop_tgt/LINK_DIRECTORIES.rst new file mode 100644 index 0000000..085a701 --- /dev/null +++ b/Help/prop_tgt/LINK_DIRECTORIES.rst @@ -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. diff --git a/Help/release/dev/LINK_DIRECTORIES-policy.rst b/Help/release/dev/LINK_DIRECTORIES-policy.rst new file mode 100644 index 0000000..5bbfa51 --- /dev/null +++ b/Help/release/dev/LINK_DIRECTORIES-policy.rst @@ -0,0 +1,5 @@ +LINK_DIRECTORIES-policy +----------------------- + +* The :prop_tgt:`LINK_DIRECTORIES` target property expects absolute paths. + See policy :policy:`CMP0081`. diff --git a/Help/release/dev/LINK_DIRECTORIES.rst b/Help/release/dev/LINK_DIRECTORIES.rst new file mode 100644 index 0000000..dc7d609 --- /dev/null +++ b/Help/release/dev/LINK_DIRECTORIES.rst @@ -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. diff --git a/Help/release/dev/link_directories-enhancements.rst b/Help/release/dev/link_directories-enhancements.rst new file mode 100644 index 0000000..2521fa1 --- /dev/null +++ b/Help/release/dev/link_directories-enhancements.rst @@ -0,0 +1,5 @@ +link_directories-enhancements +----------------------------- + +* :command:`link_directories` command gains capability to control directories + insertion position. diff --git a/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst new file mode 100644 index 0000000..026ca35 --- /dev/null +++ b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst @@ -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. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index bfddbc6..3cf6c8f 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -579,6 +579,8 @@ set(SRCS cmTargetIncludeDirectoriesCommand.h cmTargetLinkOptionsCommand.cxx cmTargetLinkOptionsCommand.h + cmTargetLinkDirectoriesCommand.cxx + cmTargetLinkDirectoriesCommand.h cmTargetLinkLibrariesCommand.cxx cmTargetLinkLibrariesCommand.h cmTargetPropCommandBase.cxx diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index 3aa59d6..22ae340 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -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, diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 15fbd40..873372f 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -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); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index a3e135f..0e48ca8 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -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( diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 7f42035..024e641 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -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); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index d6573b8..4cf9dd7 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -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, diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 6ca2e07..41c6538 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -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, diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index bfb7a05..e444087 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -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); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index 658e9a7..2727d9a 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -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; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 8176d5c..9c05f60 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -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; }; diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h index 8b1697b..a5134c3 100644 --- a/Source/cmGeneratorExpressionDAGChecker.h +++ b/Source/cmGeneratorExpressionDAGChecker.h @@ -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) \ diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index a58d3cb..29c6058 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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(); @@ -3068,6 +3069,126 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions( } 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, const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries, diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 9d8c9f5..bfd95ac 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -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; diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index eaaf64d..caec67d 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -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; diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx index 1371c53..10425fd 100644 --- a/Source/cmLinkDirectoriesCommand.cxx +++ b/Source/cmLinkDirectoriesCommand.cxx @@ -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); } diff --git a/Source/cmLinkDirectoriesCommand.h b/Source/cmLinkDirectoriesCommand.h index 3fd4e50..ae4fb7f 100644 --- a/Source/cmLinkDirectoriesCommand.h +++ b/Source/cmLinkDirectoriesCommand.h @@ -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 diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 354da4e..8d163b7 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -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; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index bb01c0b..b30f281 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -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 { diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index f99cc0f..a367e47 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -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 diff --git a/Source/cmState.cxx b/Source/cmState.cxx index c6667f6..4b65cf1 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -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)) { diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx index 925b161..f94e714 100644 --- a/Source/cmStateDirectory.cxx +++ b/Source/cmStateDirectory.cxx @@ -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) { diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h index 412664f..e5f4d05 100644 --- a/Source/cmStateDirectory.h +++ b/Source/cmStateDirectory.h @@ -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, diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h index 7177221..e76f2af 100644 --- a/Source/cmStatePrivate.h +++ b/Source/cmStatePrivate.h @@ -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; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 0379e7e..c2510f3 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -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"); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 4e353c7..c5295f2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -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; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 1f380df..694de1c 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -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; diff --git a/Source/cmTargetLinkDirectoriesCommand.cxx b/Source/cmTargetLinkDirectoriesCommand.cxx new file mode 100644 index 0000000..bca3e45 --- /dev/null +++ b/Source/cmTargetLinkDirectoriesCommand.cxx @@ -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. +} diff --git a/Source/cmTargetLinkDirectoriesCommand.h b/Source/cmTargetLinkDirectoriesCommand.h new file mode 100644 index 0000000..52c75a0 --- /dev/null +++ b/Source/cmTargetLinkDirectoriesCommand.h @@ -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 diff --git a/Tests/CMakeCommands/link_directories/CMakeLists.txt b/Tests/CMakeCommands/link_directories/CMakeLists.txt new file mode 100644 index 0000000..60c07b6 --- /dev/null +++ b/Tests/CMakeCommands/link_directories/CMakeLists.txt @@ -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() diff --git a/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_directories/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt new file mode 100644 index 0000000..bc7b9b2 --- /dev/null +++ b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt @@ -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() diff --git a/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c new file mode 100644 index 0000000..9bbd24c --- /dev/null +++ b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c @@ -0,0 +1,7 @@ +#if defined(_WIN32) +__declspec(dllexport) +#endif + int flags_lib(void) +{ + return 0; +} diff --git a/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt new file mode 100644 index 0000000..7e7ad2a --- /dev/null +++ b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_library(target_link_directories_5 SHARED EXCLUDE_FROM_ALL ../LinkDirectoriesLib.c) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index fb44077..83349e3 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -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) diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index cb048be..c6b7dbc 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -619,6 +619,18 @@ 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") add_library(testLinkDepends INTERFACE) diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index 8791a19..67fcc02 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -490,6 +490,11 @@ 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") checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS") diff --git a/Tests/LinkDirectory/External/CMakeLists.txt b/Tests/LinkDirectory/External/CMakeLists.txt index f7c840f..d2a1f9f 100644 --- a/Tests/LinkDirectory/External/CMakeLists.txt +++ b/Tests/LinkDirectory/External/CMakeLists.txt @@ -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) diff --git a/Tests/RunCMake/CMP0081/CMP0081-Common.cmake b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake new file mode 100644 index 0000000..3ea5277 --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake @@ -0,0 +1,5 @@ + +enable_language(CXX) + +add_library(foo SHARED empty.cpp) +set_target_properties(foo PROPERTIES LINK_DIRECTORIES "../lib") diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt new file mode 100644 index 0000000..d31c149 --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt @@ -0,0 +1,4 @@ +CMake Error in CMakeLists.txt: + Found relative path while evaluating link directories of "foo": + + "../lib" diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake new file mode 100644 index 0000000..9b927a2 --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0081 NEW) + +include (CMP0081-Common.cmake) diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake new file mode 100644 index 0000000..2e91bf6 --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake @@ -0,0 +1,4 @@ + +cmake_policy(SET CMP0081 OLD) + +include (CMP0081-Common.cmake) diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt new file mode 100644 index 0000000..573541a --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt @@ -0,0 +1 @@ +0 diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt new file mode 100644 index 0000000..eac0648 --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt @@ -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. diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake new file mode 100644 index 0000000..33bb21d --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake @@ -0,0 +1,2 @@ + +include (CMP0081-Common.cmake) diff --git a/Tests/RunCMake/CMP0081/CMakeLists.txt b/Tests/RunCMake/CMP0081/CMakeLists.txt new file mode 100644 index 0000000..ef2163c --- /dev/null +++ b/Tests/RunCMake/CMP0081/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.1) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CMP0081/RunCMakeTest.cmake b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake new file mode 100644 index 0000000..335d8c5 --- /dev/null +++ b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake @@ -0,0 +1,5 @@ +include(RunCMake) + +run_cmake(CMP0081-OLD) +run_cmake(CMP0081-NEW) +run_cmake(CMP0081-WARN) diff --git a/Tests/RunCMake/CMP0081/empty.cpp b/Tests/RunCMake/CMP0081/empty.cpp new file mode 100644 index 0000000..11ec041 --- /dev/null +++ b/Tests/RunCMake/CMP0081/empty.cpp @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif + int empty() +{ + return 0; +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 69cb5b7..080d0d0 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -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 diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt index 6c861fa..2441a9c 100644 --- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt +++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt @@ -25,6 +25,7 @@ \* CMP0069 \* CMP0073 \* CMP0076 + \* CMP0081 Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt new file mode 100644 index 0000000..580c373 --- /dev/null +++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt @@ -0,0 +1,2 @@ +-- Target LINK_DIRECTORIES is 'a;b;c;d;;e' +-- Directory LINK_DIRECTORIES is 'a;b;c;d;;e' diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake new file mode 100644 index 0000000..8529ef5 --- /dev/null +++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake @@ -0,0 +1,3 @@ +include(Common.cmake) +test_target_property(LINK_DIRECTORIES) +test_directory_property(LINK_DIRECTORIES) diff --git a/Tests/RunCMake/set_property/RunCMakeTest.cmake b/Tests/RunCMake/set_property/RunCMakeTest.cmake index 77da703..8d4614c 100644 --- a/Tests/RunCMake/set_property/RunCMakeTest.cmake +++ b/Tests/RunCMake/set_property/RunCMakeTest.cmake @@ -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) |