From 551d3343cd16c566be4b33e96c892c3e769951af Mon Sep 17 00:00:00 2001 From: Pavel Shramov Date: Wed, 19 Jun 2013 16:35:23 +0400 Subject: [PATCH] cmDependsC: Collapse relative include paths While calculating dependencies collapse sequences such as ../../../a/b/c/../../d/e/../../e/f to avoid total path lengths over the Windows path length limit as much as possible. --- Source/cmDependsC.cxx | 18 ++++-------------- Source/cmSystemTools.cxx | 34 ++++++++++++++++++++++++++++++++++ Source/cmSystemTools.h | 6 ++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index 43b7b8a60..a252a1ab7 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -193,17 +193,8 @@ bool cmDependsC::WriteDependencies(const std::set& sources, // Construct the name of the file as if it were in the current // include directory. Avoid using a leading "./". - tempPathStr = ""; - if((*i) == ".") - { - tempPathStr += current.FileName; - } - else - { - tempPathStr += *i; - tempPathStr+="/"; - tempPathStr+=current.FileName; - } + tempPathStr = + cmSystemTools::CollapseCombinedPath(*i, current.FileName); // Look for the file in this location. if(cmSystemTools::FileExists(tempPathStr.c_str(), true)) @@ -458,9 +449,8 @@ void cmDependsC::Scan(std::istream& is, const char* directory, // This was a double-quoted include with a relative path. We // must check for the file in the directory containing the // file we are scanning. - entry.QuotedLocation = directory; - entry.QuotedLocation += "/"; - entry.QuotedLocation += entry.FileName; + entry.QuotedLocation = + cmSystemTools::CollapseCombinedPath(directory, entry.FileName); } // Queue the file if it has not yet been encountered and it diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 21c361d9f..f32f2dc0e 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1594,6 +1594,40 @@ std::string cmSystemTools::RelativePath(const char* local, const char* remote) return cmsys::SystemTools::RelativePath(local, remote); } +std::string cmSystemTools::CollapseCombinedPath(std::string const& dir, + std::string const& file) +{ + if(dir.empty() || dir == ".") + { + return file; + } + + std::vector dirComponents; + std::vector fileComponents; + cmSystemTools::SplitPath(dir.c_str(), dirComponents); + cmSystemTools::SplitPath(file.c_str(), fileComponents); + + if(fileComponents.empty()) + { + return dir; + } + if(fileComponents[0] != "") + { + // File is not a relative path. + return file; + } + + std::vector::iterator i = fileComponents.begin()+1; + while(i != fileComponents.end() && *i == ".." && dirComponents.size() > 1) + { + ++i; // Remove ".." file component. + dirComponents.pop_back(); // Remove last dir component. + } + + dirComponents.insert(dirComponents.end(), i, fileComponents.end()); + return cmSystemTools::JoinPath(dirComponents); +} + #ifdef CMAKE_BUILD_WITH_CMAKE //---------------------------------------------------------------------- bool cmSystemTools::UnsetEnv(const char* value) diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index ec539292a..9614449ad 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -365,6 +365,12 @@ public: */ static std::string RelativePath(const char* local, const char* remote); + /** Joins two paths while collapsing x/../ parts + * For example CollapseCombinedPath("a/b/c", "../../d") results in "a/d" + */ + static std::string CollapseCombinedPath(std::string const& dir, + std::string const& file); + #ifdef CMAKE_BUILD_WITH_CMAKE /** Remove an environment variable */ static bool UnsetEnv(const char* value);