Commit 48aedb2b authored by Brad King's avatar Brad King

ENH: Fully implemented SOURCE_GROUP command.

parent e093bdad
......@@ -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")
......
......@@ -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
......
......@@ -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
......
......@@ -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;
}
......@@ -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;
};
......
......@@ -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;
}
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment