浏览代码

Makefile: Optionally scan only source and build trees for dependencies

Add a `CMAKE_DEPENDS_IN_PROJECT_ONLY` variable to activate the behavior.
Attila Krasznahorkay 9 年之前
父节点
当前提交
b1e1aa1e6a

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -114,6 +114,7 @@ Variables that Change Behavior
    /variable/CMAKE_COLOR_MAKEFILE
    /variable/CMAKE_CONFIGURATION_TYPES
    /variable/CMAKE_DEBUG_TARGET_PROPERTIES
+   /variable/CMAKE_DEPENDS_IN_PROJECT_ONLY
    /variable/CMAKE_DISABLE_FIND_PACKAGE_PackageName
    /variable/CMAKE_ERROR_DEPRECATED
    /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION

+ 10 - 0
Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst

@@ -0,0 +1,10 @@
+CMAKE_DEPENDS_IN_PROJECT_ONLY
+-----------------------------
+
+When set to ``TRUE`` in a directory, the build system produced by the
+:ref:`Makefile Generators` is set up to only consider dependencies on source
+files that appear either in the source or in the binary directories.  Changes
+to source files outside of these directories will not cause rebuilds.
+
+This should be used carefully in cases where some source files are picked up
+through external headers during the build.

+ 61 - 0
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -34,6 +34,7 @@
 #include <cmsys/Terminal.h>
 
 #include <queue>
+#include <algorithm>
 
 //----------------------------------------------------------------------------
 // Escape special characters in Makefile dependency lines
@@ -1971,6 +1972,57 @@ void cmLocalUnixMakefileGenerator3::ClearDependencies(cmMakefile* mf,
 }
 
 
+namespace
+{
+  // Helper predicate for removing absolute paths that don't point to the
+  // source or binary directory. It is used when CMAKE_DEPENDS_IN_PROJECT_ONLY
+  // is set ON, to only consider in-project dependencies during the build.
+  class NotInProjectDir
+  {
+  public:
+    // Constructor with the source and binary directory's path
+    NotInProjectDir(const std::string& sourceDir,
+                    const std::string& binaryDir)
+      : SourceDir(sourceDir), BinaryDir(binaryDir) {}
+
+    // Operator evaluating the predicate
+    bool operator()(const std::string& path) const
+      {
+      // Keep all relative paths:
+      if(!cmSystemTools::FileIsFullPath(path))
+        {
+        return false;
+        }
+      // If it's an absolute path, check if it starts with the source
+      // direcotory:
+      return (!(IsInDirectory(SourceDir, path)||
+                IsInDirectory(BinaryDir, path)));
+      }
+
+  private:
+    // Helper function used by the predicate
+    static bool IsInDirectory(const std::string& baseDir,
+                              const std::string& testDir)
+      {
+      // First check if the test directory "starts with" the base directory:
+      if (testDir.find(baseDir) != 0)
+        {
+        return false;
+        }
+      // If it does, then check that it's either the same string, or that the
+      // next character is a slash:
+      return ((testDir.size() == baseDir.size())||
+              (testDir[baseDir.size()] == '/'));
+      }
+
+    // The path to the source directory
+    std::string SourceDir;
+    // The path to the binary directory
+    std::string BinaryDir;
+  };
+}
+
+
 void cmLocalUnixMakefileGenerator3
 ::WriteDependLanguageInfo(std::ostream& cmakefileStream,
                           cmGeneratorTarget* target)
@@ -2058,6 +2110,15 @@ void cmLocalUnixMakefileGenerator3
       this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
     this->GetIncludeDirectories(includes, target,
                                 l->first, config);
+    if(this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY"))
+      {
+      const char* sourceDir = this->GetState()->GetSourceDirectory();
+      const char* binaryDir = this->GetState()->GetBinaryDirectory();
+      std::vector<std::string>::iterator itr =
+        std::remove_if(includes.begin(), includes.end(),
+                       ::NotInProjectDir(sourceDir, binaryDir));
+      includes.erase(itr, includes.end());
+      }
     for(std::vector<std::string>::iterator i = includes.begin();
         i != includes.end(); ++i)
       {