Browse Source

ENH: Fully implemented SOURCE_GROUP command.

Brad King 22 years ago
parent
commit
48aedb2ba3

+ 1 - 1
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")

+ 1 - 1
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

+ 10 - 7
Source/cmMakefile.cxx

@@ -1535,17 +1535,21 @@ cmSourceGroup&
 cmMakefile::FindSourceGroup(const char* source,
                             std::vector<cmSourceGroup> &groups)
 {
-  std::string file = source;
-  std::string::size_type pos = file.rfind('/');
-  if(pos != std::string::npos)
+  // First search for a group that lists the file explicitly.
+  for(std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin();
+      sg != groups.rend(); ++sg)
     {
-    file = file.substr(pos+1);
+    if(sg->MatchesFiles(source))
+      {
+      return *sg;
+      }
     }
-
+  
+  // Now search for a group whose regex matches the file.
   for(std::vector<cmSourceGroup>::reverse_iterator sg = groups.rbegin();
       sg != groups.rend(); ++sg)
     {
-    if(sg->Matches(file.c_str()))
+    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

+ 51 - 25
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<cmStdString>::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<const cmSourceFile*>& cmSourceGroup::GetSourceFiles() const
+{
+  return m_SourceFiles;
+}
+
+//----------------------------------------------------------------------------
+std::vector<const cmSourceFile*>& cmSourceGroup::GetSourceFiles()
+{
+  return m_SourceFiles;
+}

+ 47 - 14
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<const cmSourceFile*> &GetSourceFiles() const 
-    {return m_SourceFiles;}
-  std::vector<const cmSourceFile*> &GetSourceFiles() {return m_SourceFiles;}
+  const std::vector<const cmSourceFile*>& GetSourceFiles() const;
+  std::vector<const cmSourceFile*>& 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<cmStdString> m_GroupFiles;
+  
+  /**
+   * Vector of all source files that have been assigned to
+   * this group.
    */
   std::vector<const cmSourceFile*> m_SourceFiles;
 };

+ 47 - 24
Source/cmSourceGroupCommand.cxx

@@ -24,37 +24,60 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args)
     this->SetError("called with incorrect number of arguments");
     return false;
     }  
-  
-  if ( args[1] == "REGULAR_EXPRESSION" && args.size() == 3 )
+
+  // Get the source group with the given name.
+  cmSourceGroup* sg = m_Makefile->GetSourceGroup(args[0].c_str());
+  if(!sg)
     {
-    m_Makefile->AddSourceGroup(args[0].c_str(), args[2].c_str());
-    return true;
+    m_Makefile->AddSourceGroup(args[0].c_str(), 0);
+    sg = m_Makefile->GetSourceGroup(args[0].c_str());
     }
-
-  if ( args[1] == "FILES"  )
+  
+  // Process arguments.
+  bool doingFiles = false;
+  for(unsigned int i=1; i < args.size(); ++i)
     {
-    cmSourceGroup* sg =  m_Makefile->GetSourceGroup(args[0].c_str());
-    if ( !sg )
+    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")
       {
-      m_Makefile->AddSourceGroup(args[0].c_str(), 0);
-      sg =  m_Makefile->GetSourceGroup(args[0].c_str());
+      // Next arguments will specify files.
+      doingFiles = true;
       }
-    unsigned int cc;
-    for ( cc = 2; cc < args.size(); cc ++ )
+    else if(doingFiles)
       {
-      sg->AddSource(args[cc].c_str(), 0);
+      // 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;
       }
-    
-    return true;
     }
   
-  if ( args.size() == 2 )
-    {
-    m_Makefile->AddSourceGroup(args[0].c_str(), args[1].c_str());
-    return true;
-    }
-
-  this->SetError("called with incorrect number of arguments");
-  return false;
+  return true;
 }
-

+ 8 - 4
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);