diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 0d6a830af..4e7df945a 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -252,7 +252,7 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, std::string source = (*i)->GetFullPath(); cmSourceGroup& sourceGroup = m_Makefile->FindSourceGroup(source.c_str(), sourceGroups); - sourceGroup.AddSource(source.c_str(), *i); + sourceGroup.AssignSource(*i); // while we are at it, if it is a .rule file then for visual studio 6 we // must generate it if ((*i)->GetSourceExtension() == "rule") diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index dbde4a717..95f0977ea 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -695,7 +695,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, } cmSourceGroup& sourceGroup = m_Makefile->FindSourceGroup(source.c_str(), sourceGroups); - sourceGroup.AddSource(source.c_str(), *i); + sourceGroup.AssignSource(*i); } // open the project diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6d196f8b2..8d4bb1eb2 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1535,17 +1535,21 @@ cmSourceGroup& cmMakefile::FindSourceGroup(const char* source, std::vector &groups) { - std::string file = source; - std::string::size_type pos = file.rfind('/'); - if(pos != std::string::npos) - { - file = file.substr(pos+1); - } - + // First search for a group that lists the file explicitly. for(std::vector::reverse_iterator sg = groups.rbegin(); sg != groups.rend(); ++sg) { - if(sg->Matches(file.c_str())) + if(sg->MatchesFiles(source)) + { + return *sg; + } + } + + // Now search for a group whose regex matches the file. + for(std::vector::reverse_iterator sg = groups.rbegin(); + sg != groups.rend(); ++sg) + { + if(sg->MatchesRegex(source)) { return *sg; } @@ -1840,7 +1844,6 @@ cmSourceFile* cmMakefile::GetOrCreateSource(const char* sourceName, return ret; } - cmSourceFile* cmMakefile::AddSource(cmSourceFile const&sf) { // check to see if it exists diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx index 706547d0a..035b643c2 100644 --- a/Source/cmSourceGroup.cxx +++ b/Source/cmSourceGroup.cxx @@ -16,42 +16,68 @@ =========================================================================*/ #include "cmSourceGroup.h" - -/** - * The constructor initializes the group's regular expression. - */ -cmSourceGroup::cmSourceGroup(const char* name, const char* regex): - m_Name(name), - m_GroupRegex(regex) +//---------------------------------------------------------------------------- +cmSourceGroup::cmSourceGroup(const char* name, const char* regex): m_Name(name) { + this->SetGroupRegex(regex); } - -/** - * Copy constructor. - */ -cmSourceGroup::cmSourceGroup(const cmSourceGroup& r): - m_Name(r.m_Name), - m_GroupRegex(r.m_GroupRegex), - m_SourceFiles(r.m_SourceFiles) +//---------------------------------------------------------------------------- +void cmSourceGroup::SetGroupRegex(const char* regex) { + if(regex) + { + m_GroupRegex.compile(regex); + } + else + { + m_GroupRegex.compile("^$"); + } } - - -/** - * Returns whether the given name matches the group's regular expression. - */ -bool cmSourceGroup::Matches(const char* name) + +//---------------------------------------------------------------------------- +void cmSourceGroup::AddGroupFile(const char* name) +{ + m_GroupFiles.insert(name); +} + +//---------------------------------------------------------------------------- +const char* cmSourceGroup::GetName() const +{ + return m_Name.c_str(); +} + +//---------------------------------------------------------------------------- +bool cmSourceGroup::MatchesRegex(const char* name) { return m_GroupRegex.find(name); } +//---------------------------------------------------------------------------- +bool cmSourceGroup::MatchesFiles(const char* name) +{ + std::set::const_iterator i = m_GroupFiles.find(name); + if(i != m_GroupFiles.end()) + { + return true; + } + return false; +} -/** - * Add a source to the group that the compiler will know how to build. - */ -void cmSourceGroup::AddSource(const char* /* name */, const cmSourceFile* sf) +//---------------------------------------------------------------------------- +void cmSourceGroup::AssignSource(const cmSourceFile* sf) { m_SourceFiles.push_back(sf); } +//---------------------------------------------------------------------------- +const std::vector& cmSourceGroup::GetSourceFiles() const +{ + return m_SourceFiles; +} + +//---------------------------------------------------------------------------- +std::vector& cmSourceGroup::GetSourceFiles() +{ + return m_SourceFiles; +} diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h index 3158041fa..430802864 100644 --- a/Source/cmSourceGroup.h +++ b/Source/cmSourceGroup.h @@ -25,29 +25,56 @@ class cmSourceFile; /** \class cmSourceGroup * \brief Hold a group of sources as specified by a SOURCE_GROUP command. * - * cmSourceGroup holds all the source files and corresponding commands - * for files matching the regular expression specified for the group. + * cmSourceGroup holds a regular expression and a list of files. When + * local generators are about to generate the rules for a target's + * files, the set of source groups is consulted to group files + * together. A file is placed into the last source group that lists + * the file by name. If no group lists the file, it is placed into + * the last group whose regex matches it. */ class cmSourceGroup { public: cmSourceGroup(const char* name, const char* regex); - cmSourceGroup(const cmSourceGroup&); ~cmSourceGroup() {} - void SetGroupRegex(const char* regex) - { m_GroupRegex.compile(regex); } - void AddSource(const char* name, const cmSourceFile*); - const char* GetName() const - { return m_Name.c_str(); } - bool Matches(const char *); + /** + * Set the regular expression for this group. + */ + void SetGroupRegex(const char* regex); + + /** + * Add a file name to the explicit list of files for this group. + */ + void AddGroupFile(const char* name); + + /** + * Get the name of this group. + */ + const char* GetName() const; + + /** + * Check if the given name matches this group's regex. + */ + bool MatchesRegex(const char* name); + + /** + * Check if the given name matches this group's explicit file list. + */ + bool MatchesFiles(const char* name); + + /** + * Assign the given source file to this group. Used only by + * generators. + */ + void AssignSource(const cmSourceFile* sf); /** - * Get the list of the source files used by this target + * Get the list of the source files that have been assigned to this + * source group. */ - const std::vector &GetSourceFiles() const - {return m_SourceFiles;} - std::vector &GetSourceFiles() {return m_SourceFiles;} + const std::vector& GetSourceFiles() const; + std::vector& GetSourceFiles(); private: /** @@ -61,7 +88,13 @@ private: cmsys::RegularExpression m_GroupRegex; /** - * vector of all source files in this source group + * Set of file names explicitly added to this group. + */ + std::set m_GroupFiles; + + /** + * Vector of all source files that have been assigned to + * this group. */ std::vector m_SourceFiles; }; diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 2978aed69..621b56455 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -24,37 +24,60 @@ bool cmSourceGroupCommand::InitialPass(std::vector const& args) this->SetError("called with incorrect number of arguments"); return false; } - - if ( args[1] == "REGULAR_EXPRESSION" && args.size() == 3 ) - { - m_Makefile->AddSourceGroup(args[0].c_str(), args[2].c_str()); - return true; - } - if ( args[1] == "FILES" ) + // Get the source group with the given name. + cmSourceGroup* sg = m_Makefile->GetSourceGroup(args[0].c_str()); + if(!sg) { - cmSourceGroup* sg = m_Makefile->GetSourceGroup(args[0].c_str()); - if ( !sg ) - { - m_Makefile->AddSourceGroup(args[0].c_str(), 0); - sg = m_Makefile->GetSourceGroup(args[0].c_str()); - } - unsigned int cc; - for ( cc = 2; cc < args.size(); cc ++ ) - { - sg->AddSource(args[cc].c_str(), 0); - } - - return true; + m_Makefile->AddSourceGroup(args[0].c_str(), 0); + sg = m_Makefile->GetSourceGroup(args[0].c_str()); } - if ( args.size() == 2 ) + // Process arguments. + bool doingFiles = false; + for(unsigned int i=1; i < args.size(); ++i) { - m_Makefile->AddSourceGroup(args[0].c_str(), args[1].c_str()); - return true; + if(args[i] == "REGULAR_EXPRESSION") + { + // Next argument must specify the regex. + if(i+1 < args.size()) + { + ++i; + sg->SetGroupRegex(args[i].c_str()); + } + else + { + this->SetError("REGULAR_EXPRESSION argument given without a regex."); + return false; + } + doingFiles = false; + } + else if(args[i] == "FILES") + { + // Next arguments will specify files. + doingFiles = true; + } + else if(doingFiles) + { + // Convert name to full path and add to the group's list. + std::string src = args[i].c_str(); + if(!cmSystemTools::FileIsFullPath(src.c_str())) + { + src = m_Makefile->GetCurrentDirectory(); + src += "/"; + src += args[i]; + } + sg->AddGroupFile(src.c_str()); + } + else + { + cmOStringStream err; + err << "Unknown argument \"" << args[i].c_str() << "\". " + << "Perhaps the FILES keyword is missing.\n"; + this->SetError(err.str().c_str()); + return false; + } } - - this->SetError("called with incorrect number of arguments"); - return false; + + return true; } - diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h index dea98508c..1dc1ba384 100644 --- a/Source/cmSourceGroupCommand.h +++ b/Source/cmSourceGroupCommand.h @@ -71,10 +71,14 @@ public: virtual const char* GetFullDocumentation() { return - " SOURCE_GROUP(name regex)\n" - "Defines a new source group. Any file whose name matches the regular " - "expression will be placed in this group. The LAST regular expression " - "of all defined SOURCE_GROUPs that matches the file will be selected."; + " SOURCE_GROUP(name [REGULAR_EXPRESSION regex] [FILES src1 src2 ...])\n" + "Defines a group into which sources will be placed in project files. " + "This is mainly used to setup file tabs in Visual Studio. " + "Any file whose name is listed or matches the regular expression will " + "be placed in this group. If a file matches multiple groups, the LAST " + "group that explicitly lists the file will be favored, if any. If no " + "group explicitly lists the file, the LAST group whose regular " + "expression matches the file will be favored."; } cmTypeMacro(cmSourceGroupCommand, cmCommand);