summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmGlobalBorlandMakefileGenerator.cxx1
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx56
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.h11
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx5
-rw-r--r--Source/cmMakefileTargetGenerator.cxx79
-rw-r--r--Source/cmMakefileTargetGenerator.h10
-rw-r--r--Source/kwsys/Glob.cxx93
-rw-r--r--Source/kwsys/Glob.hxx.in47
9 files changed, 213 insertions, 91 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 3ca0984..038a09f 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 2)
-set(CMake_VERSION_PATCH 20150306)
+set(CMake_VERSION_PATCH 20150309)
#set(CMake_VERSION_RC 1)
diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx
index 950d440..6c20952 100644
--- a/Source/cmGlobalBorlandMakefileGenerator.cxx
+++ b/Source/cmGlobalBorlandMakefileGenerator.cxx
@@ -49,7 +49,6 @@ cmLocalGenerator *cmGlobalBorlandMakefileGenerator::CreateLocalGenerator()
lg->SetUnixCD(false);
lg->SetMakeCommandEscapeTargetTwice(true);
lg->SetBorlandMakeCurlyHack(true);
- lg->SetNoMultiOutputMultiDepRules(true);
return lg;
}
diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx
index 432cb3a..723e39b 100644
--- a/Source/cmLocalUnixMakefileGenerator3.cxx
+++ b/Source/cmLocalUnixMakefileGenerator3.cxx
@@ -92,7 +92,6 @@ cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3()
this->SkipAssemblySourceRules = false;
this->MakeCommandEscapeTargetTwice = false;
this->BorlandMakeCurlyHack = false;
- this->NoMultiOutputMultiDepRules = false;
}
//----------------------------------------------------------------------------
@@ -600,7 +599,6 @@ const std::string &cmLocalUnixMakefileGenerator3::GetHomeRelativeOutputPath()
return this->HomeRelativeOutputPath;
}
-
//----------------------------------------------------------------------------
void
cmLocalUnixMakefileGenerator3
@@ -619,30 +617,6 @@ cmLocalUnixMakefileGenerator3
comment);
return;
}
- std::vector<std::string> outputs(1, target);
- this->WriteMakeRule(os, comment,
- outputs, depends, commands,
- symbolic, in_help);
-}
-
-//----------------------------------------------------------------------------
-void
-cmLocalUnixMakefileGenerator3
-::WriteMakeRule(std::ostream& os,
- const char* comment,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& depends,
- const std::vector<std::string>& commands,
- bool symbolic,
- bool in_help)
-{
- // Make sure there is an output.
- if(outputs.empty())
- {
- cmSystemTools::Error("No outputs for WriteMakeRule! called with comment: ",
- comment);
- return;
- }
std::string replace;
@@ -661,17 +635,7 @@ cmLocalUnixMakefileGenerator3
}
// Construct the left hand side of the rule.
- std::string tgt;
- {
- const char* sep = "";
- for (std::vector<std::string>::const_iterator i = outputs.begin();
- i != outputs.end(); ++i)
- {
- tgt += sep;
- tgt += this->Convert(*i,HOME_OUTPUT,MAKERULE);
- sep = " ";
- }
- }
+ std::string tgt = this->Convert(target, HOME_OUTPUT, MAKERULE);
const char* space = "";
if(tgt.size() == 1)
@@ -697,19 +661,6 @@ cmLocalUnixMakefileGenerator3
// No dependencies. The commands will always run.
os << cmMakeSafe(tgt) << space << ":\n";
}
- else if(this->NoMultiOutputMultiDepRules && outputs.size() >= 2)
- {
- // Borland make does not understand multiple dependency rules when
- // there are multiple outputs, so write them all on one line.
- os << cmMakeSafe(tgt) << space << ":";
- for(std::vector<std::string>::const_iterator dep = depends.begin();
- dep != depends.end(); ++dep)
- {
- replace = this->Convert(*dep, HOME_OUTPUT, MAKERULE);
- os << " " << cmMakeSafe(replace);
- }
- os << "\n";
- }
else
{
// Split dependencies into multiple rule lines. This allows for
@@ -733,8 +684,7 @@ cmLocalUnixMakefileGenerator3
// Add the output to the local help if requested.
if(in_help)
{
- this->LocalHelp.insert(this->LocalHelp.end(),
- outputs.begin(), outputs.end());
+ this->LocalHelp.push_back(target);
}
}
@@ -1754,8 +1704,6 @@ cmLocalUnixMakefileGenerator3
//----------------------------------------------------------------------------
void cmLocalUnixMakefileGenerator3::CheckMultipleOutputs(bool verbose)
{
- // Nothing populates multiple output pairs anymore, but we need to
- // honor it when working in a build tree generated by an older CMake.
cmMakefile* mf = this->Makefile;
// Get the string listing the multiple output pairs.
diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h
index 1ff5e7f..a2f4245 100644
--- a/Source/cmLocalUnixMakefileGenerator3.h
+++ b/Source/cmLocalUnixMakefileGenerator3.h
@@ -61,13 +61,6 @@ public:
const std::vector<std::string>& commands,
bool symbolic,
bool in_help = false);
- void WriteMakeRule(std::ostream& os,
- const char* comment,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& depends,
- const std::vector<std::string>& commands,
- bool symbolic,
- bool in_help = false);
// write the main variables used by the makefiles
void WriteMakeVariables(std::ostream& makefileStream);
@@ -161,9 +154,6 @@ public:
void SetBorlandMakeCurlyHack(bool b)
{ this->BorlandMakeCurlyHack = b; }
- void SetNoMultiOutputMultiDepRules(bool b)
- { this->NoMultiOutputMultiDepRules = b; }
-
// used in writing out Cmake files such as WriteDirectoryInformation
static void WriteCMakeArgument(std::ostream& os, const char* s);
@@ -349,7 +339,6 @@ private:
bool PassMakeflags;
bool MakeCommandEscapeTargetTwice;
bool BorlandMakeCurlyHack;
- bool NoMultiOutputMultiDepRules;
//==========================================================================
std::string HomeRelativeOutputPath;
diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx
index 84761cc..fcb76c3 100644
--- a/Source/cmMakefileLibraryTargetGenerator.cxx
+++ b/Source/cmMakefileLibraryTargetGenerator.cxx
@@ -769,9 +769,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
}
// Write the build rule.
- this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
- outputs, depends, commands, false);
-
+ this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+ depends, commands, false);
// Write the main driver rule to build everything in this target.
this->WriteTargetDriverRule(targetFullPath, relink);
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 20207f5..e751bc1 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -769,8 +769,8 @@ cmMakefileTargetGenerator
}
// Write the rule.
- this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
- outputs, depends, commands, false);
+ this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+ depends, commands, false);
bool do_preprocess_rules = lang_has_preprocessor &&
this->LocalGenerator->GetCreatePreprocessedSourceRules();
@@ -991,6 +991,57 @@ void cmMakefileTargetGenerator::WriteTargetCleanRules()
depends, commands, true);
}
+//----------------------------------------------------------------------------
+void cmMakefileTargetGenerator::WriteMakeRule(
+ std::ostream& os,
+ const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands,
+ bool symbolic,
+ bool in_help)
+{
+ if (outputs.size() == 0)
+ {
+ return;
+ }
+
+ // We always attach the actual commands to the first output.
+ this->LocalGenerator->WriteMakeRule(os, comment, outputs[0], depends,
+ commands, symbolic, in_help);
+
+ // For single outputs, we are done.
+ if (outputs.size() == 1)
+ {
+ return;
+ }
+
+ // For multiple outputs, make the extra ones depend on the first one.
+ std::vector<std::string> const output_depends(1, outputs[0]);
+ for (std::vector<std::string>::const_iterator o = outputs.begin()+1;
+ o != outputs.end(); ++o)
+ {
+ // Touch the extra output so "make" knows that it was updated,
+ // but only if the output was acually created.
+ std::string const out = this->Convert(*o, cmLocalGenerator::HOME_OUTPUT,
+ cmLocalGenerator::SHELL);
+ std::vector<std::string> output_commands;
+ if (!symbolic)
+ {
+ output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
+ }
+ this->LocalGenerator->WriteMakeRule(os, 0, *o, output_depends,
+ output_commands, symbolic, in_help);
+
+ if (!symbolic)
+ {
+ // At build time, remove the first output if this one does not exist
+ // so that "make" will rerun the real commands that create this one.
+ MultipleOutputPairsType::value_type p(*o, outputs[0]);
+ this->MultipleOutputPairs.insert(p);
+ }
+ }
+}
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator::WriteTargetDependRules()
@@ -1011,6 +1062,25 @@ void cmMakefileTargetGenerator::WriteTargetDependRules()
this->LocalGenerator->
WriteDependLanguageInfo(*this->InfoFileStream,*this->Target);
+ // Store multiple output pairs in the depend info file.
+ if(!this->MultipleOutputPairs.empty())
+ {
+ *this->InfoFileStream
+ << "\n"
+ << "# Pairs of files generated by the same build rule.\n"
+ << "set(CMAKE_MULTIPLE_OUTPUT_PAIRS\n";
+ for(MultipleOutputPairsType::const_iterator pi =
+ this->MultipleOutputPairs.begin();
+ pi != this->MultipleOutputPairs.end(); ++pi)
+ {
+ *this->InfoFileStream
+ << " " << this->LocalGenerator->EscapeForCMake(pi->first)
+ << " " << this->LocalGenerator->EscapeForCMake(pi->second)
+ << "\n";
+ }
+ *this->InfoFileStream << " )\n\n";
+ }
+
// Store list of targets linked directly or transitively.
{
*this->InfoFileStream
@@ -1240,9 +1310,8 @@ void cmMakefileTargetGenerator
symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
- this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
- outputs, depends, commands,
- symbolic);
+ this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
+ depends, commands, symbolic);
// If the rule has changed make sure the output is rebuilt.
if(!symbolic)
diff --git a/Source/cmMakefileTargetGenerator.h b/Source/cmMakefileTargetGenerator.h
index b072cfa..98017be 100644
--- a/Source/cmMakefileTargetGenerator.h
+++ b/Source/cmMakefileTargetGenerator.h
@@ -222,6 +222,16 @@ protected:
// Set of extra output files to be driven by the build.
std::set<std::string> ExtraFiles;
+ typedef std::map<std::string, std::string> MultipleOutputPairsType;
+ MultipleOutputPairsType MultipleOutputPairs;
+ void WriteMakeRule(std::ostream& os,
+ const char* comment,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& depends,
+ const std::vector<std::string>& commands,
+ bool symbolic,
+ bool in_help = false);
+
// Target name info.
std::string TargetNameOut;
std::string TargetNameSO;
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index 1476c25..11bfd16 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -19,6 +19,7 @@
#include KWSYS_HEADER(Directory.hxx)
#include KWSYS_HEADER(stl/string)
#include KWSYS_HEADER(stl/vector)
+#include KWSYS_HEADER(stl/algorithm)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
@@ -30,6 +31,8 @@
# include "SystemTools.hxx.in"
# include "kwsys_stl.hxx.in"
# include "kwsys_stl_string.hxx.in"
+# include "kwsys_stl_vector.hxx.in"
+# include "kwsys_stl_algorithm.hxx.in"
#endif
#include <ctype.h>
@@ -66,6 +69,10 @@ Glob::Glob()
// RecurseThroughSymlinks is true by default for backwards compatibility,
// not because it's a good idea...
this->FollowedSymlinkCount = 0;
+
+ // Keep separate variables for directory listing for back compatibility
+ this->ListDirs = true;
+ this->RecurseListDirs = false;
}
//----------------------------------------------------------------------------
@@ -214,13 +221,13 @@ kwsys_stl::string Glob::PatternToRegex(const kwsys_stl::string& pattern,
}
//----------------------------------------------------------------------------
-void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
- const kwsys_stl::string& dir)
+bool Glob::RecurseDirectory(kwsys_stl::string::size_type start,
+ const kwsys_stl::string& dir, GlobMessages* messages)
{
kwsys::Directory d;
if ( !d.Load(dir) )
{
- return;
+ return true;
}
unsigned long cc;
kwsys_stl::string realname;
@@ -255,8 +262,67 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
if (isSymLink)
{
++this->FollowedSymlinkCount;
+ kwsys_stl::string realPathErrorMessage;
+ kwsys_stl::string canonicalPath(SystemTools::GetRealPath(dir,
+ &realPathErrorMessage));
+
+ if(!realPathErrorMessage.empty())
+ {
+ if(messages)
+ {
+ messages->push_back(Message(
+ Glob::error, "Canonical path generation from path '"
+ + dir + "' failed! Reason: '" + realPathErrorMessage + "'"));
+ }
+ return false;
+ }
+
+ if(kwsys_stl::find(this->VisitedSymlinks.begin(),
+ this->VisitedSymlinks.end(),
+ canonicalPath) == this->VisitedSymlinks.end())
+ {
+ if(this->RecurseListDirs)
+ {
+ // symlinks are treated as directories
+ this->AddFile(this->Internals->Files, realname);
+ }
+
+ this->VisitedSymlinks.push_back(canonicalPath);
+ if(!this->RecurseDirectory(start+1, realname, messages))
+ {
+ this->VisitedSymlinks.pop_back();
+
+ return false;
+ }
+ this->VisitedSymlinks.pop_back();
+ }
+ // else we have already visited this symlink - prevent cyclic recursion
+ else if(messages)
+ {
+ kwsys_stl::string message;
+ for(kwsys_stl::vector<kwsys_stl::string>::const_iterator
+ pathIt = kwsys_stl::find(this->VisitedSymlinks.begin(),
+ this->VisitedSymlinks.end(),
+ canonicalPath);
+ pathIt != this->VisitedSymlinks.end(); ++pathIt)
+ {
+ message += *pathIt + "\n";
+ }
+ message += canonicalPath + "/" + fname;
+ messages->push_back(Message(Glob::cyclicRecursion, message));
+ }
+ }
+ else
+ {
+ if(this->RecurseListDirs)
+ {
+ this->AddFile(this->Internals->Files, realname);
+ }
+ if(!this->RecurseDirectory(start+1, realname, messages))
+ {
+ return false;
+ }
}
- this->RecurseDirectory(start+1, realname);
}
else
{
@@ -267,17 +333,19 @@ void Glob::RecurseDirectory(kwsys_stl::string::size_type start,
}
}
}
+
+ return true;
}
//----------------------------------------------------------------------------
void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
- const kwsys_stl::string& dir)
+ const kwsys_stl::string& dir, GlobMessages* messages)
{
//kwsys_ios::cout << "ProcessDirectory: " << dir << kwsys_ios::endl;
bool last = ( start == this->Internals->Expressions.size()-1 );
if ( last && this->Recurse )
{
- this->RecurseDirectory(start, dir);
+ this->RecurseDirectory(start, dir, messages);
return;
}
@@ -321,8 +389,9 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
// << this->Internals->TextExpressions[start].c_str() << kwsys_ios::endl;
//kwsys_ios::cout << "Real name: " << realname << kwsys_ios::endl;
- if ( !last &&
- !kwsys::SystemTools::FileIsDirectory(realname) )
+ if( (!last && !kwsys::SystemTools::FileIsDirectory(realname))
+ || (!this->ListDirs && last &&
+ kwsys::SystemTools::FileIsDirectory(realname)) )
{
continue;
}
@@ -335,14 +404,14 @@ void Glob::ProcessDirectory(kwsys_stl::string::size_type start,
}
else
{
- this->ProcessDirectory(start+1, realname);
+ this->ProcessDirectory(start+1, realname, messages);
}
}
}
}
//----------------------------------------------------------------------------
-bool Glob::FindFiles(const kwsys_stl::string& inexpr)
+bool Glob::FindFiles(const kwsys_stl::string& inexpr, GlobMessages* messages)
{
kwsys_stl::string cexpr;
kwsys_stl::string::size_type cc;
@@ -438,11 +507,11 @@ bool Glob::FindFiles(const kwsys_stl::string& inexpr)
// Handle network paths
if ( skip > 0 )
{
- this->ProcessDirectory(0, fexpr.substr(0, skip) + "/");
+ this->ProcessDirectory(0, fexpr.substr(0, skip) + "/", messages);
}
else
{
- this->ProcessDirectory(0, "/");
+ this->ProcessDirectory(0, "/", messages);
}
return true;
}
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index d8b8491..39b7ce7 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -40,11 +40,36 @@ class GlobInternals;
class @KWSYS_NAMESPACE@_EXPORT Glob
{
public:
+ enum MessageType
+ {
+ error,
+ cyclicRecursion
+ };
+
+ struct Message
+ {
+ MessageType type;
+ kwsys_stl::string content;
+
+ Message(MessageType t, const kwsys_stl::string& c) :
+ type(t),
+ content(c)
+ {}
+ Message(const Message& msg) :
+ type(msg.type),
+ content(msg.content)
+ {}
+ };
+
+ typedef kwsys_stl::vector<Message> GlobMessages;
+ typedef kwsys_stl::vector<Message>::iterator GlobMessagesIterator;
+public:
Glob();
~Glob();
//! Find all files that match the pattern.
- bool FindFiles(const kwsys_stl::string& inexpr);
+ bool FindFiles(const kwsys_stl::string& inexpr,
+ GlobMessages* messages = 0);
//! Return the list of files that matched.
kwsys_stl::vector<kwsys_stl::string>& GetFiles();
@@ -80,15 +105,26 @@ public:
bool require_whole_string = true,
bool preserve_case = false);
+ /** Getters and setters for enabling and disabling directory
+ listing in recursive and non recursive globbing mode.
+ If listing is enabled in recursive mode it also lists
+ directory symbolic links even if follow symlinks is enabled. */
+ void SetListDirs(bool list) { this->ListDirs=list; }
+ bool GetListDirs() const { return this->ListDirs; }
+ void SetRecurseListDirs(bool list) { this->RecurseListDirs=list; }
+ bool GetRecurseListDirs() const { return this->RecurseListDirs; }
+
protected:
//! Process directory
void ProcessDirectory(kwsys_stl::string::size_type start,
- const kwsys_stl::string& dir);
+ const kwsys_stl::string& dir,
+ GlobMessages* messages);
//! Process last directory, but only when recurse flags is on. That is
// effectively like saying: /path/to/file/**/file
- void RecurseDirectory(kwsys_stl::string::size_type start,
- const kwsys_stl::string& dir);
+ bool RecurseDirectory(kwsys_stl::string::size_type start,
+ const kwsys_stl::string& dir,
+ GlobMessages* messages);
//! Add regular expression
void AddExpression(const kwsys_stl::string& expr);
@@ -101,6 +137,9 @@ protected:
kwsys_stl::string Relative;
bool RecurseThroughSymlinks;
unsigned int FollowedSymlinkCount;
+ kwsys_stl::vector<kwsys_stl::string> VisitedSymlinks;
+ bool ListDirs;
+ bool RecurseListDirs;
private:
Glob(const Glob&); // Not implemented.