Browse Source

link_directories(): enhance capabilities

Marc Chevrier 7 years ago
parent
commit
f9717725f9

+ 7 - 1
Help/command/link_directories.rst

@@ -5,7 +5,7 @@ Add directories in which the linker will look for libraries.
 
 ::
 
-  link_directories(directory1 [directory2 ...])
+  link_directories([AFTER|BEFORE] directory1 [directory2 ...])
 
 Add the paths in which the linker should search for libraries.
 Relative paths given to this command are interpreted as relative to
@@ -16,6 +16,12 @@ 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)`

+ 1 - 0
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

+ 5 - 0
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.

+ 9 - 0
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.

+ 21 - 4
Source/cmLinkDirectoriesCommand.cxx

@@ -4,6 +4,7 @@
 
 #include <sstream>
 
+#include "cmAlgorithms.h"
 #include "cmGeneratorExpression.h"
 #include "cmMakefile.h"
 #include "cmPolicies.h"
@@ -20,13 +21,29 @@ 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);
@@ -64,5 +81,5 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
       unixPath = tmp;
     }
   }
-  this->Makefile->AddLinkDirectory(unixPath);
+  directories.push_back(unixPath);
 }

+ 2 - 1
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

+ 9 - 2
Source/cmMakefile.cxx

@@ -1248,9 +1248,16 @@ void cmMakefile::AddLinkOption(std::string const& option)
   this->AppendProperty("LINK_OPTIONS", option.c_str());
 }
 
-void cmMakefile::AddLinkDirectory(std::string const& directory)
+void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
 {
-  this->AppendProperty("LINK_DIRECTORIES", directory.c_str());
+  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)

+ 1 - 1
Source/cmMakefile.h

@@ -182,7 +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);
+  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,

+ 27 - 0
Source/cmStateDirectory.cxx

@@ -417,6 +417,33 @@ void cmStateDirectory::AppendLinkDirectoriesEntry(
               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)

+ 2 - 0
Source/cmStateDirectory.h

@@ -62,6 +62,8 @@ 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();
 

+ 30 - 0
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()

+ 4 - 0
Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c

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

+ 2 - 1
Tests/CMakeLists.txt

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