diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index cb500519d..5fd5c5c05 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/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 diff --git a/Help/release/dev/cmake-depend-in-project-only.rst b/Help/release/dev/cmake-depend-in-project-only.rst new file mode 100644 index 000000000..8553e80e7 --- /dev/null +++ b/Help/release/dev/cmake-depend-in-project-only.rst @@ -0,0 +1,6 @@ +cmake-depend-in-project-only +---------------------------- + +* The :ref:`Makefile Generators` learned to optionally limit dependency + scanning only to files in the project source and build trees. + See the :variable:`CMAKE_DEPENDS_IN_PROJECT_ONLY` variable. diff --git a/Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst b/Help/variable/CMAKE_DEPENDS_IN_PROJECT_ONLY.rst new file mode 100644 index 000000000..717907145 --- /dev/null +++ b/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. diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 62fea3d84..afdff337e 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -34,6 +34,7 @@ #include #include +#include //---------------------------------------------------------------------------- // 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::iterator itr = + std::remove_if(includes.begin(), includes.end(), + ::NotInProjectDir(sourceDir, binaryDir)); + includes.erase(itr, includes.end()); + } for(std::vector::iterator i = includes.begin(); i != includes.end(); ++i) { diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c new file mode 100644 index 000000000..bcb8745bf --- /dev/null +++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.c @@ -0,0 +1,2 @@ +#include +int main() { return MakeInProjectOnly(); } diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake new file mode 100644 index 000000000..add9aeb69 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.cmake @@ -0,0 +1,16 @@ +enable_language(C) +get_filename_component(include_dir "${CMAKE_BINARY_DIR}" PATH) +include_directories("${include_dir}") +add_executable(MakeInProjectOnly MakeInProjectOnly.c) +set(CMAKE_DEPENDS_IN_PROJECT_ONLY 1) +file(GENERATE OUTPUT check-$>.cmake CONTENT " +if (check_step EQUAL 1) + set(check_pairs + \"$|${include_dir}/MakeInProjectOnly.h\" + ) +else() + set(check_pairs + \"${include_dir}/MakeInProjectOnly.h|\$\" + ) +endif() +") diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake new file mode 100644 index 000000000..d6551abe0 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step1.cmake @@ -0,0 +1,3 @@ +file(WRITE "${RunCMake_TEST_BINARY_DIR}/../MakeInProjectOnly.h" [[ +int MakeInProjectOnly(void) { return 0; } +]]) diff --git a/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake new file mode 100644 index 000000000..145605be7 --- /dev/null +++ b/Tests/RunCMake/BuildDepends/MakeInProjectOnly.step2.cmake @@ -0,0 +1,3 @@ +file(WRITE "${RunCMake_TEST_BINARY_DIR}/../MakeInProjectOnly.h" [[ +int MakeInProjectOnly(void) { return 1; } +]]) diff --git a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake index 26ffcc0e8..6b2b85a2b 100644 --- a/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake +++ b/Tests/RunCMake/BuildDepends/RunCMakeTest.cmake @@ -41,6 +41,11 @@ endif() run_BuildDepends(Custom-Always) +if(RunCMake_GENERATOR MATCHES "Make" AND + NOT "${RunCMake_BINARY_DIR}" STREQUAL "${RunCMake_SOURCE_DIR}") + run_BuildDepends(MakeInProjectOnly) +endif() + function(run_ReGeneration) # test re-generation of project even if CMakeLists.txt files disappeared