ENH: Added SOURCE_GROUP command and corresponding support code. This command allows CMakeLists files to specify how sources are organized into groups in the generated DSP files and makefiles.

This commit is contained in:
Brad King 2001-03-20 13:20:59 -05:00
parent 51ef865ef8
commit 8c087d0e7a
17 changed files with 723 additions and 234 deletions

View File

@ -125,6 +125,10 @@ SOURCE=.\cmRegularExpression.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=.\cmSourceGroup.cxx
# End Source File
# Begin Source File
SOURCE=.\cmSystemTools.cxx SOURCE=.\cmSystemTools.cxx
# End Source File # End Source File
# Begin Source File # Begin Source File

View File

@ -22,7 +22,8 @@ cmSystemTools.o \
cmDirectory.o \ cmDirectory.o \
cmUnixMakefileGenerator.o \ cmUnixMakefileGenerator.o \
cmCommands.o \ cmCommands.o \
cmCacheManager.o cmCacheManager.o \
cmSourceGroup.o
DEPENDS = $(srcdir)/*.h ${CMAKE_CONFIG_DIR}/CMake/Source/cmConfigure.h DEPENDS = $(srcdir)/*.h ${CMAKE_CONFIG_DIR}/CMake/Source/cmConfigure.h
@ -38,6 +39,7 @@ cmDirectory.o : $(DEPENDS)
cmUnixMakefileGenerator.o : $(DEPENDS) cmUnixMakefileGenerator.o : $(DEPENDS)
cmCommands.o : $(DEPENDS) cmCommands.o : $(DEPENDS)
cmCacheManager.o : $(DEPENDS) cmCacheManager.o : $(DEPENDS)
cmSourceGroup.o : $(DEPENDS)

View File

@ -107,7 +107,7 @@ void cmCableCommand::SetupCableData()
std::vector<std::string> depends; std::vector<std::string> depends;
m_Makefile->AddCustomCommand(cMakeLists.c_str(), m_Makefile->AddCustomCommand(cMakeLists.c_str(),
"cable_config.xml",
command.c_str(), command.c_str(),
depends); depends,
"cable_config.xml");
} }

View File

@ -60,17 +60,19 @@ bool cmCablePackageCommand::Invoke(std::vector<std::string>& args)
// files. // files.
std::string command = "${CABLE}"; std::string command = "${CABLE}";
m_Makefile->ExpandVariablesInString(command); m_Makefile->ExpandVariablesInString(command);
std::vector<std::string> depends; std::vector<std::string> depends;
depends.push_back(command); depends.push_back(command);
command += " cable_config.xml"; command += " cable_config.xml";
std::string packageFile = "Cxx/"+m_PackageName+"_cxx.cxx"; std::vector<std::string> outputs;
outputs.push_back("Cxx/"+m_PackageName+"_cxx.cxx");
outputs.push_back("Cxx/"+m_PackageName+"_cxx.h");
// A rule for the package's source file. // A rule for the package's source files.
m_Makefile->AddCustomCommand("cable_config.xml", m_Makefile->AddCustomCommand("cable_config.xml",
packageFile.c_str(),
command.c_str(), command.c_str(),
depends); depends,
outputs);
return true; return true;
} }

View File

@ -42,6 +42,7 @@
#include "cmBuildSharedLibrariesCommand.cxx" #include "cmBuildSharedLibrariesCommand.cxx"
#include "cmUtilitySourceCommand.cxx" #include "cmUtilitySourceCommand.cxx"
#include "cmIncludeRegularExpressionCommand.cxx" #include "cmIncludeRegularExpressionCommand.cxx"
#include "cmSourceGroupCommand.cxx"
void GetPredefinedCommands(std::list<cmCommand*>& commands) void GetPredefinedCommands(std::list<cmCommand*>& commands)
{ {
@ -81,6 +82,7 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands)
commands.push_back(new cmBuildSharedLibrariesCommand); commands.push_back(new cmBuildSharedLibrariesCommand);
commands.push_back(new cmUtilitySourceCommand); commands.push_back(new cmUtilitySourceCommand);
commands.push_back(new cmIncludeRegularExpressionCommand); commands.push_back(new cmIncludeRegularExpressionCommand);
commands.push_back(new cmSourceGroupCommand);
} }

View File

@ -170,42 +170,127 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout)
dsprule += " -B"; dsprule += " -B";
dsprule += m_Makefile->GetHomeOutputDirectory(); dsprule += m_Makefile->GetHomeOutputDirectory();
std::vector<std::string> depends; std::set<std::string> depends;
this->WriteCustomRule(fout, makefileIn.c_str(), std::set<std::string> outputs;
dspname.c_str(), outputs.insert(outputs.begin(), dspname);
dsprule.c_str(), fout << "# Begin Source File\n\n";
depends); fout << "SOURCE=" << makefileIn.c_str() << "\n\n";
this->WriteCustomRule(fout, dsprule.c_str(), depends, outputs);
fout << "# End Source File\n";
} }
void cmDSPMakefile::AddDSPBuildRule(cmSourceGroup& sourceGroup)
{
std::string dspname = *(m_CreatedProjectNames.end()-1);
dspname += ".dsp";
std::string makefileIn = m_Makefile->GetStartDirectory();
makefileIn += "/";
makefileIn += "CMakeLists.txt";
std::string dsprule = m_Makefile->GetHomeDirectory();
dsprule += "/CMake/Source/CMakeSetupCMD ";
dsprule += makefileIn;
dsprule += " -DSP -H";
dsprule += m_Makefile->GetHomeDirectory();
dsprule += " -S";
dsprule += m_Makefile->GetStartDirectory();
dsprule += " -O";
dsprule += m_Makefile->GetStartOutputDirectory();
dsprule += " -B";
dsprule += m_Makefile->GetHomeOutputDirectory();
std::vector<std::string> depends;
std::vector<std::string> outputs;
outputs.push_back(dspname);
sourceGroup.AddCustomCommand(makefileIn.c_str(), dsprule.c_str(),
depends, outputs);
}
void cmDSPMakefile::WriteDSPFile(std::ostream& fout) void cmDSPMakefile::WriteDSPFile(std::ostream& fout)
{ {
// Write the DSP file's header.
this->WriteDSPHeader(fout); this->WriteDSPHeader(fout);
this->WriteDSPBeginGroup(fout, "Source Files", "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat");
this->WriteDSPBuildRules(fout,"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"); // We may be modifying the source groups temporarily, so make a copy.
this->WriteDSPEndGroup(fout); std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups();
this->WriteDSPBeginGroup(fout, "Header Files", "h;hpp;hxx;hm;inl");
this->WriteDSPBuildRules(fout,"h;hpp;hxx;hm;inl"); // Find the group in which the CMakeLists.txt source belongs, and add
this->WriteDSPEndGroup(fout); // the rule to generate this DSP file.
this->WriteDSPBeginGroup(fout, "XML Files", "xml"); for(std::vector<cmSourceGroup>::reverse_iterator sg = sourceGroups.rbegin();
this->WriteDSPBuildRules(fout,"xml"); sg != sourceGroups.rend(); ++sg)
this->WriteDSPEndGroup(fout); {
this->WriteDSPBeginGroup(fout, "Text Files", "txt"); if(sg->Matches("CMakeLists.txt"))
this->WriteDSPBuildRules(fout,"txt"); {
this->WriteDSPEndGroup(fout); this->AddDSPBuildRule(*sg);
this->WriteDSPBuildRule(fout); break;
}
}
// Loop through every source group.
for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin();
sg != sourceGroups.end(); ++sg)
{
const std::vector<std::string>& sources = sg->GetSources();
const cmSourceGroup::CustomCommands& customCommands = sg->GetCustomCommands();
// If the group is empty, don't write it at all.
if(sources.empty() && customCommands.empty())
{ continue; }
// If the group has a name, write the header.
std::string name = sg->GetName();
if(name != "")
{
this->WriteDSPBeginGroup(fout, name.c_str(), "");
}
// Loop through each source in the source group.
for(std::vector<std::string>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
this->WriteDSPBuildRule(fout, s->c_str());
}
// Loop through each custom command in the source group.
for(cmSourceGroup::CustomCommands::const_iterator cc =
customCommands.begin(); cc != customCommands.end(); ++ cc)
{
std::string source = cc->first;
const cmSourceGroup::Commands& commands = cc->second;
fout << "# Begin Source File\n\n";
fout << "SOURCE=" << source << "\n\n";
// Loop through every command generating code from the current source.
for(cmSourceGroup::Commands::const_iterator c = commands.begin();
c != commands.end(); ++c)
{
std::string command = c->first;
const cmSourceGroup::CommandFiles& commandFiles = c->second;
this->WriteCustomRule(fout, command.c_str(), commandFiles.m_Depends,
commandFiles.m_Outputs);
}
fout << "# End Source File\n";
}
// If the group has a name, write the footer.
if(name != "")
{
this->WriteDSPEndGroup(fout);
}
}
// Write the DSP file's footer.
this->WriteDSPFooter(fout); this->WriteDSPFooter(fout);
} }
void cmDSPMakefile::WriteCustomRule(std::ostream& fout, void cmDSPMakefile::WriteCustomRule(std::ostream& fout,
const char* source,
const char* result,
const char* command, const char* command,
std::vector<std::string>& depends) const std::set<std::string>& depends,
const std::set<std::string>& outputs)
{ {
fout << "# Begin Source File\n\n";
fout << "SOURCE=" << source << "\n\n";
std::vector<std::string>::iterator i; std::vector<std::string>::iterator i;
for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i) for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i)
{ {
@ -218,17 +303,27 @@ void cmDSPMakefile::WriteCustomRule(std::ostream& fout,
fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl; fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
} }
fout << "# Begin Custom Build\n\n"; fout << "# Begin Custom Build\n\n";
fout << '\"' << result << "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\" "; fout << "BuildCommand = " << command << "\n\n";
for (int i = 0; i < depends.size(); i++)
// Write a rule for every output generated by this command.
for(std::set<std::string>::const_iterator output = outputs.begin();
output != outputs.end(); ++output)
{ {
fout << "\"" << depends[i].c_str() << "\" "; fout << "\"" << output->c_str()
<< "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"";
// Write out all the dependencies for this rule.
for(std::set<std::string>::const_iterator d = depends.begin();
d != depends.end(); ++d)
{
fout << " \"" << d->c_str() << "\"";
}
fout << "\n $(BuildCommand)\n\n";
} }
fout << "\n " << command << "\n\n";
fout << "# End Custom Build\n\n"; fout << "# End Custom Build\n\n";
} }
fout << "!ENDIF\n\n"; fout << "!ENDIF\n\n";
fout << "# End Source File\n";
} }
@ -339,61 +434,6 @@ void cmDSPMakefile::WriteDSPFooter(std::ostream& fout)
} }
} }
void cmDSPMakefile::WriteDSPBuildRules(std::ostream& fout, const char *ext)
{
// make a list if matching extentions
std::vector<std::string> exts;
std::string inExts = ext;
std::string::size_type pos = inExts.find(';');
std::string::size_type lastPos = 0;
while (pos != std::string::npos)
{
std::string anExt = inExts.substr(lastPos, pos - lastPos);
exts.push_back(anExt);
lastPos = pos + 1;
pos = inExts.find(';',lastPos);
}
exts.push_back(inExts.substr(lastPos,inExts.size() - lastPos));
// loop over any classes
std::vector<cmClassFile>& Classes = m_Makefile->GetClasses();
for(int i = 0; i < Classes.size(); ++i)
{
if(!Classes[i].m_IsExecutable && !Classes[i].m_HeaderFileOnly)
{
// is this class of the appropriate type ?
if (std::find(exts.begin(),exts.end(),Classes[i].m_ClassExtension)
!= exts.end())
{
this->WriteDSPBuildRule(fout, Classes[i].m_FullPath.c_str());
}
}
}
// loop over any custom commands
std::vector<cmMakefile::customCommand>& ccoms =
this->GetMakefile()->GetCustomCommands();
int numCust = ccoms.size();
for (int j = 0; j < numCust; j++)
{
cmMakefile::customCommand &cc = ccoms[j];
// is the source of the command the correct type
pos = cc.m_Source.rfind('.');
if(pos != std::string::npos)
{
if (std::find(exts.begin(),exts.end(),
cc.m_Source.substr(pos+1,cc.m_Source.size() - pos - 1))
!= exts.end())
{
this->WriteCustomRule(fout, cc.m_Source.c_str(),
cc.m_Result.c_str(),
cc.m_Command.c_str(),
cc.m_Depends);
}
}
}
}
void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path) void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path)
{ {
@ -402,5 +442,3 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path)
<< path << "\n"; << path << "\n";
fout << "# End Source File\n"; fout << "# End Source File\n";
} }

View File

@ -75,15 +75,14 @@ private:
const char* filter); const char* filter);
void WriteDSPEndGroup(std::ostream& fout); void WriteDSPEndGroup(std::ostream& fout);
void WriteDSPHeader(std::ostream& fout); void WriteDSPHeader(std::ostream& fout);
void WriteDSPBuildRules(std::ostream& fout, const char *extensions);
void WriteDSPBuildRule(std::ostream& fout, const char*); void WriteDSPBuildRule(std::ostream& fout, const char*);
void WriteDSPFooter(std::ostream& fout);
void WriteDSPBuildRule(std::ostream& fout); void WriteDSPBuildRule(std::ostream& fout);
void WriteDSPFooter(std::ostream& fout);
void AddDSPBuildRule(cmSourceGroup&);
void WriteCustomRule(std::ostream& fout, void WriteCustomRule(std::ostream& fout,
const char* source, const char* command,
const char* result, const std::set<std::string>& depends,
const char* command, const std::set<std::string>& outputs);
std::vector<std::string>& depends);
std::string m_IncludeOptions; std::string m_IncludeOptions;
std::string m_LibraryOptions; std::string m_LibraryOptions;

View File

@ -170,42 +170,127 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout)
dsprule += " -B"; dsprule += " -B";
dsprule += m_Makefile->GetHomeOutputDirectory(); dsprule += m_Makefile->GetHomeOutputDirectory();
std::vector<std::string> depends; std::set<std::string> depends;
this->WriteCustomRule(fout, makefileIn.c_str(), std::set<std::string> outputs;
dspname.c_str(), outputs.insert(outputs.begin(), dspname);
dsprule.c_str(), fout << "# Begin Source File\n\n";
depends); fout << "SOURCE=" << makefileIn.c_str() << "\n\n";
this->WriteCustomRule(fout, dsprule.c_str(), depends, outputs);
fout << "# End Source File\n";
} }
void cmDSPMakefile::AddDSPBuildRule(cmSourceGroup& sourceGroup)
{
std::string dspname = *(m_CreatedProjectNames.end()-1);
dspname += ".dsp";
std::string makefileIn = m_Makefile->GetStartDirectory();
makefileIn += "/";
makefileIn += "CMakeLists.txt";
std::string dsprule = m_Makefile->GetHomeDirectory();
dsprule += "/CMake/Source/CMakeSetupCMD ";
dsprule += makefileIn;
dsprule += " -DSP -H";
dsprule += m_Makefile->GetHomeDirectory();
dsprule += " -S";
dsprule += m_Makefile->GetStartDirectory();
dsprule += " -O";
dsprule += m_Makefile->GetStartOutputDirectory();
dsprule += " -B";
dsprule += m_Makefile->GetHomeOutputDirectory();
std::vector<std::string> depends;
std::vector<std::string> outputs;
outputs.push_back(dspname);
sourceGroup.AddCustomCommand(makefileIn.c_str(), dsprule.c_str(),
depends, outputs);
}
void cmDSPMakefile::WriteDSPFile(std::ostream& fout) void cmDSPMakefile::WriteDSPFile(std::ostream& fout)
{ {
// Write the DSP file's header.
this->WriteDSPHeader(fout); this->WriteDSPHeader(fout);
this->WriteDSPBeginGroup(fout, "Source Files", "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat");
this->WriteDSPBuildRules(fout,"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"); // We may be modifying the source groups temporarily, so make a copy.
this->WriteDSPEndGroup(fout); std::vector<cmSourceGroup> sourceGroups = m_Makefile->GetSourceGroups();
this->WriteDSPBeginGroup(fout, "Header Files", "h;hpp;hxx;hm;inl");
this->WriteDSPBuildRules(fout,"h;hpp;hxx;hm;inl"); // Find the group in which the CMakeLists.txt source belongs, and add
this->WriteDSPEndGroup(fout); // the rule to generate this DSP file.
this->WriteDSPBeginGroup(fout, "XML Files", "xml"); for(std::vector<cmSourceGroup>::reverse_iterator sg = sourceGroups.rbegin();
this->WriteDSPBuildRules(fout,"xml"); sg != sourceGroups.rend(); ++sg)
this->WriteDSPEndGroup(fout); {
this->WriteDSPBeginGroup(fout, "Text Files", "txt"); if(sg->Matches("CMakeLists.txt"))
this->WriteDSPBuildRules(fout,"txt"); {
this->WriteDSPEndGroup(fout); this->AddDSPBuildRule(*sg);
this->WriteDSPBuildRule(fout); break;
}
}
// Loop through every source group.
for(std::vector<cmSourceGroup>::const_iterator sg = sourceGroups.begin();
sg != sourceGroups.end(); ++sg)
{
const std::vector<std::string>& sources = sg->GetSources();
const cmSourceGroup::CustomCommands& customCommands = sg->GetCustomCommands();
// If the group is empty, don't write it at all.
if(sources.empty() && customCommands.empty())
{ continue; }
// If the group has a name, write the header.
std::string name = sg->GetName();
if(name != "")
{
this->WriteDSPBeginGroup(fout, name.c_str(), "");
}
// Loop through each source in the source group.
for(std::vector<std::string>::const_iterator s = sources.begin();
s != sources.end(); ++s)
{
this->WriteDSPBuildRule(fout, s->c_str());
}
// Loop through each custom command in the source group.
for(cmSourceGroup::CustomCommands::const_iterator cc =
customCommands.begin(); cc != customCommands.end(); ++ cc)
{
std::string source = cc->first;
const cmSourceGroup::Commands& commands = cc->second;
fout << "# Begin Source File\n\n";
fout << "SOURCE=" << source << "\n\n";
// Loop through every command generating code from the current source.
for(cmSourceGroup::Commands::const_iterator c = commands.begin();
c != commands.end(); ++c)
{
std::string command = c->first;
const cmSourceGroup::CommandFiles& commandFiles = c->second;
this->WriteCustomRule(fout, command.c_str(), commandFiles.m_Depends,
commandFiles.m_Outputs);
}
fout << "# End Source File\n";
}
// If the group has a name, write the footer.
if(name != "")
{
this->WriteDSPEndGroup(fout);
}
}
// Write the DSP file's footer.
this->WriteDSPFooter(fout); this->WriteDSPFooter(fout);
} }
void cmDSPMakefile::WriteCustomRule(std::ostream& fout, void cmDSPMakefile::WriteCustomRule(std::ostream& fout,
const char* source,
const char* result,
const char* command, const char* command,
std::vector<std::string>& depends) const std::set<std::string>& depends,
const std::set<std::string>& outputs)
{ {
fout << "# Begin Source File\n\n";
fout << "SOURCE=" << source << "\n\n";
std::vector<std::string>::iterator i; std::vector<std::string>::iterator i;
for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i) for(i = m_Configurations.begin(); i != m_Configurations.end(); ++i)
{ {
@ -218,17 +303,27 @@ void cmDSPMakefile::WriteCustomRule(std::ostream& fout,
fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl; fout << "!ELSEIF \"$(CFG)\" == " << i->c_str() << std::endl;
} }
fout << "# Begin Custom Build\n\n"; fout << "# Begin Custom Build\n\n";
fout << '\"' << result << "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\" "; fout << "BuildCommand = " << command << "\n\n";
for (int i = 0; i < depends.size(); i++)
// Write a rule for every output generated by this command.
for(std::set<std::string>::const_iterator output = outputs.begin();
output != outputs.end(); ++output)
{ {
fout << "\"" << depends[i].c_str() << "\" "; fout << "\"" << output->c_str()
<< "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\"";
// Write out all the dependencies for this rule.
for(std::set<std::string>::const_iterator d = depends.begin();
d != depends.end(); ++d)
{
fout << " \"" << d->c_str() << "\"";
}
fout << "\n $(BuildCommand)\n\n";
} }
fout << "\n " << command << "\n\n";
fout << "# End Custom Build\n\n"; fout << "# End Custom Build\n\n";
} }
fout << "!ENDIF\n\n"; fout << "!ENDIF\n\n";
fout << "# End Source File\n";
} }
@ -339,61 +434,6 @@ void cmDSPMakefile::WriteDSPFooter(std::ostream& fout)
} }
} }
void cmDSPMakefile::WriteDSPBuildRules(std::ostream& fout, const char *ext)
{
// make a list if matching extentions
std::vector<std::string> exts;
std::string inExts = ext;
std::string::size_type pos = inExts.find(';');
std::string::size_type lastPos = 0;
while (pos != std::string::npos)
{
std::string anExt = inExts.substr(lastPos, pos - lastPos);
exts.push_back(anExt);
lastPos = pos + 1;
pos = inExts.find(';',lastPos);
}
exts.push_back(inExts.substr(lastPos,inExts.size() - lastPos));
// loop over any classes
std::vector<cmClassFile>& Classes = m_Makefile->GetClasses();
for(int i = 0; i < Classes.size(); ++i)
{
if(!Classes[i].m_IsExecutable && !Classes[i].m_HeaderFileOnly)
{
// is this class of the appropriate type ?
if (std::find(exts.begin(),exts.end(),Classes[i].m_ClassExtension)
!= exts.end())
{
this->WriteDSPBuildRule(fout, Classes[i].m_FullPath.c_str());
}
}
}
// loop over any custom commands
std::vector<cmMakefile::customCommand>& ccoms =
this->GetMakefile()->GetCustomCommands();
int numCust = ccoms.size();
for (int j = 0; j < numCust; j++)
{
cmMakefile::customCommand &cc = ccoms[j];
// is the source of the command the correct type
pos = cc.m_Source.rfind('.');
if(pos != std::string::npos)
{
if (std::find(exts.begin(),exts.end(),
cc.m_Source.substr(pos+1,cc.m_Source.size() - pos - 1))
!= exts.end())
{
this->WriteCustomRule(fout, cc.m_Source.c_str(),
cc.m_Result.c_str(),
cc.m_Command.c_str(),
cc.m_Depends);
}
}
}
}
void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path) void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path)
{ {
@ -402,5 +442,3 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path)
<< path << "\n"; << path << "\n";
fout << "# End Source File\n"; fout << "# End Source File\n";
} }

View File

@ -75,15 +75,14 @@ private:
const char* filter); const char* filter);
void WriteDSPEndGroup(std::ostream& fout); void WriteDSPEndGroup(std::ostream& fout);
void WriteDSPHeader(std::ostream& fout); void WriteDSPHeader(std::ostream& fout);
void WriteDSPBuildRules(std::ostream& fout, const char *extensions);
void WriteDSPBuildRule(std::ostream& fout, const char*); void WriteDSPBuildRule(std::ostream& fout, const char*);
void WriteDSPFooter(std::ostream& fout);
void WriteDSPBuildRule(std::ostream& fout); void WriteDSPBuildRule(std::ostream& fout);
void WriteDSPFooter(std::ostream& fout);
void AddDSPBuildRule(cmSourceGroup&);
void WriteCustomRule(std::ostream& fout, void WriteCustomRule(std::ostream& fout,
const char* source, const char* command,
const char* result, const std::set<std::string>& depends,
const char* command, const std::set<std::string>& outputs);
std::vector<std::string>& depends);
std::string m_IncludeOptions; std::string m_IncludeOptions;
std::string m_LibraryOptions; std::string m_LibraryOptions;

View File

@ -27,10 +27,14 @@
cmMakefile::cmMakefile() cmMakefile::cmMakefile()
{ {
// Setup the default include file regular expression. // Setup the default include file regular expression.
// Should be changed to something like "\\.(h|hh|hpp|hxx)$" or "^.*$"
m_IncludeFileRegularExpression = "^itk|^vtk|^vnl|^vcl|^f2c"; m_IncludeFileRegularExpression = "^itk|^vtk|^vnl|^vcl|^f2c";
m_DefineFlags = " "; m_DefineFlags = " ";
m_MakefileGenerator = 0; m_MakefileGenerator = 0;
this->AddSourceGroup("", "^.*$");
this->AddSourceGroup("Source Files", "\\.(cpp|C|c|cxx|rc|def|r|odl|idl|hpj|bat)$");
this->AddSourceGroup("Header Files", "\\.(h|hh|hpp|hxx|hm|inl)$");
this->AddDefaultCommands(); this->AddDefaultCommands();
this->AddDefaultDefinitions(); this->AddDefaultDefinitions();
} }
@ -249,21 +253,33 @@ void cmMakefile::GenerateMakefile()
void cmMakefile::AddClass(cmClassFile& cmfile) void cmMakefile::AddClass(cmClassFile& cmfile)
{ {
m_Classes.push_back(cmfile); m_Classes.push_back(cmfile);
if(!cmfile.m_IsExecutable && !cmfile.m_HeaderFileOnly)
{
// Add the file to the list of sources.
std::string source = cmfile.m_FullPath;
cmSourceGroup& sourceGroup = this->FindSourceGroup(source.c_str());
sourceGroup.AddSource(source.c_str());
}
} }
void cmMakefile::AddCustomCommand(const char* source,
const char* command,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs)
{
cmSourceGroup& sourceGroup = this->FindSourceGroup(source);
sourceGroup.AddCustomCommand(source, command, depends, outputs);
}
void cmMakefile::AddCustomCommand(const char* source, void cmMakefile::AddCustomCommand(const char* source,
const char* result, const char* command,
const char* command, const std::vector<std::string>& depends,
std::vector<std::string>& depends) const char* output)
{ {
cmMakefile::customCommand customCommand; std::vector<std::string> outputs;
customCommand.m_Source = source; outputs.push_back(output);
customCommand.m_Result = result; this->AddCustomCommand(source, command, depends, outputs);
customCommand.m_Command = command;
customCommand.m_Depends = depends;
m_CustomCommands.push_back(customCommand);
} }
void cmMakefile::AddDefineFlag(const char* flag) void cmMakefile::AddDefineFlag(const char* flag)
@ -335,6 +351,25 @@ void cmMakefile::SetLibraryName(const char* l)
m_LibraryName = l; m_LibraryName = l;
} }
void cmMakefile::AddSourceGroup(const char* name, const char* regex)
{
// First see if the group exists. If so, replace its regular expression.
for(std::vector<cmSourceGroup>::iterator sg = m_SourceGroups.begin();
sg != m_SourceGroups.end(); ++sg)
{
std::string sgName = sg->GetName();
if(sgName == name)
{
// We only want to set the regular expression. If there are already
// source files in the group, we don't want to remove them.
sg->SetGroupRegex(regex);
return;
}
}
// The group doesn't exist. Add it.
m_SourceGroups.push_back(cmSourceGroup(name, regex));
}
void cmMakefile::AddExtraDirectory(const char* dir) void cmMakefile::AddExtraDirectory(const char* dir)
{ {
@ -549,3 +584,32 @@ void cmMakefile::AddDefaultDefinitions()
this->AddDefinition("CMAKE_CFG_OUTDIR","."); this->AddDefinition("CMAKE_CFG_OUTDIR",".");
#endif #endif
} }
/**
* Find a source group whose regular expression matches the filename
* part of the given source name. Search backward through the list of
* source groups, and take the first matching group found. This way
* non-inherited SOURCE_GROUP commands will have precedence over
* inherited ones.
*/
cmSourceGroup& cmMakefile::FindSourceGroup(const char* source)
{
std::string file = source;
std::string::size_type pos = file.rfind('/');
if(pos != std::string::npos)
{
file = file.substr(pos, file.length()-pos);
}
for(std::vector<cmSourceGroup>::reverse_iterator sg = m_SourceGroups.rbegin();
sg != m_SourceGroups.rend(); ++sg)
{
if(sg->Matches(file.c_str()))
{
return *sg;
}
}
// Shouldn't get here, but just in case, return the default group.
return m_SourceGroups.front();
}

View File

@ -19,6 +19,7 @@
#include "cmStandardIncludes.h" #include "cmStandardIncludes.h"
#include "cmClassFile.h" #include "cmClassFile.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmSourceGroup.h"
class cmCommand; class cmCommand;
class cmMakefileGenerator; class cmMakefileGenerator;
@ -74,9 +75,15 @@ public:
* Add a custom command to the build. * Add a custom command to the build.
*/ */
void AddCustomCommand(const char* source, void AddCustomCommand(const char* source,
const char* result, const char* command,
const char* command, const std::vector<std::string>& depends,
std::vector<std::string>& depends); const std::vector<std::string>& outputs);
void AddCustomCommand(const char* source,
const char* command,
const std::vector<std::string>& depends,
const char* output);
/** /**
* Add a define flag to the build. * Add a define flag to the build.
*/ */
@ -146,6 +153,11 @@ public:
*/ */
void AddClass(cmClassFile& ); void AddClass(cmClassFile& );
/**
* Add a source group for consideration when adding a new source.
*/
void AddSourceGroup(const char* name, const char* regex);
/** /**
* Add an auxiliary directory to the build. * Add an auxiliary directory to the build.
*/ */
@ -369,6 +381,12 @@ public:
const std::vector<cmCommand*>& GetUsedCommands() const const std::vector<cmCommand*>& GetUsedCommands() const
{return m_UsedCommands;} {return m_UsedCommands;}
/**
* Get the vector source groups.
*/
const std::vector<cmSourceGroup>& GetSourceGroups() const
{ return m_SourceGroups; }
/** /**
* Dump documentation to a file. If 0 is returned, the * Dump documentation to a file. If 0 is returned, the
* operation failed. * operation failed.
@ -387,19 +405,7 @@ public:
/** /**
* Expand variables in the makefiles ivars such as link directories etc * Expand variables in the makefiles ivars such as link directories etc
*/ */
void ExpandVariables(); void ExpandVariables();
struct customCommand
{
std::string m_Source;
std::string m_Result;
std::string m_Command;
std::vector<std::string> m_Depends;
};
std::vector<customCommand>& GetCustomCommands() {
return m_CustomCommands; };
/** Recursivly read and create a cmMakefile object for /** Recursivly read and create a cmMakefile object for
* all CMakeLists.txt files in the GetSubDirectories list. * all CMakeLists.txt files in the GetSubDirectories list.
@ -440,7 +446,7 @@ protected:
std::vector<std::string> m_LinkLibrariesUnix; std::vector<std::string> m_LinkLibrariesUnix;
std::string m_IncludeFileRegularExpression; std::string m_IncludeFileRegularExpression;
std::string m_DefineFlags; std::string m_DefineFlags;
std::vector<customCommand> m_CustomCommands; std::vector<cmSourceGroup> m_SourceGroups;
typedef std::map<std::string, cmCommand*> RegisteredCommandsMap; typedef std::map<std::string, cmCommand*> RegisteredCommandsMap;
typedef std::map<std::string, std::string> DefinitionMap; typedef std::map<std::string, std::string> DefinitionMap;
DefinitionMap m_Definitions; DefinitionMap m_Definitions;
@ -461,6 +467,8 @@ private:
void PrintStringVector(const char* s, std::vector<std::string>& v); void PrintStringVector(const char* s, std::vector<std::string>& v);
void AddDefaultCommands(); void AddDefaultCommands();
void AddDefaultDefinitions(); void AddDefaultDefinitions();
cmSourceGroup& FindSourceGroup(const char* source);
}; };

87
Source/cmSourceGroup.cxx Normal file
View File

@ -0,0 +1,87 @@
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2000 National Library of Medicine
All rights reserved.
See COPYRIGHT.txt for copyright details.
=========================================================================*/
#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)
{
}
/**
* Copy constructor.
*/
cmSourceGroup::cmSourceGroup(const cmSourceGroup& r):
m_Name(r.m_Name),
m_GroupRegex(r.m_GroupRegex),
m_Sources(r.m_Sources),
m_CustomCommands(r.m_CustomCommands)
{
}
/**
* Returns whether the given name matches the group's regular expression.
*/
bool cmSourceGroup::Matches(const char* name)
{
return m_GroupRegex.find(name);
}
/**
* Add a source and corresponding custom command to the group. If the
* source already exists, the command will be added to its set of commands.
* If the command also already exists, the given dependencies and outputs
* are added to it.
*/
void cmSourceGroup::AddCustomCommand(const char* source,
const char* command,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs)
{
CustomCommands::iterator s = m_CustomCommands.find(source);
if(s == m_CustomCommands.end())
{
// The source was not found. Add it with this command.
m_CustomCommands[source][command].m_Depends.insert(depends.begin(),
depends.end());
m_CustomCommands[source][command].m_Outputs.insert(outputs.begin(),
outputs.end());
return;
}
// The source already exists. See if the command exists.
Commands& commands = s->second;
Commands::iterator c = commands.find(command);
if(c == commands.end())
{
// The command did not exist. Add it.
commands[command].m_Depends.insert(depends.begin(), depends.end());
commands[command].m_Outputs.insert(outputs.begin(), outputs.end());
return;
}
// The command already exists for this source. Merge the sets.
CommandFiles& commandFiles = c->second;
commandFiles.m_Depends.insert(depends.begin(), depends.end());
commandFiles.m_Outputs.insert(outputs.begin(), outputs.end());
}

94
Source/cmSourceGroup.h Normal file
View File

@ -0,0 +1,94 @@
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2000 National Library of Medicine
All rights reserved.
See COPYRIGHT.txt for copyright details.
=========================================================================*/
#ifndef cmSourceGroup_h
#define cmSourceGroup_h
#include "cmStandardIncludes.h"
#include "cmRegularExpression.h"
#include <set>
/** \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.
*/
class cmSourceGroup
{
public:
cmSourceGroup(const char* name, const char* regex);
cmSourceGroup(const cmSourceGroup&);
~cmSourceGroup() {}
struct CommandFiles
{
CommandFiles() {}
CommandFiles(const CommandFiles& r):
m_Outputs(r.m_Outputs), m_Depends(r.m_Depends) {}
std::set<std::string> m_Outputs;
std::set<std::string> m_Depends;
};
/**
* Map from command to its output/depends sets.
*/
typedef std::map<std::string, CommandFiles> Commands;
/**
* Map from source to command map.
*/
typedef std::map<std::string, Commands> CustomCommands;
bool Matches(const char* name);
void SetGroupRegex(const char* regex)
{ m_GroupRegex.compile(regex); }
void AddSource(const char* name)
{ m_Sources.push_back(name); }
void AddCustomCommand(const char* source,
const char* command,
const std::vector<std::string>& depends,
const std::vector<std::string>& outputs);
const char* GetName() const
{ return m_Name.c_str(); }
const std::vector<std::string>& GetSources() const
{ return m_Sources; }
const CustomCommands& GetCustomCommands() const
{ return m_CustomCommands; }
private:
/**
* The name of the source group.
*/
std::string m_Name;
/**
* The regular expression matching the files in the group.
*/
cmRegularExpression m_GroupRegex;
/**
* The sources in this group that the compiler will know how to build.
*/
std::vector<std::string> m_Sources;
/**
* The custom commands in this group and their corresponding sources.
*/
CustomCommands m_CustomCommands;
};
#endif

View File

@ -0,0 +1,31 @@
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2000 National Library of Medicine
All rights reserved.
See COPYRIGHT.txt for copyright details.
=========================================================================*/
#include "cmSourceGroupCommand.h"
// cmSourceGroupCommand
bool cmSourceGroupCommand::Invoke(std::vector<std::string>& args)
{
if(args.size() != 2)
{
this->SetError("called with incorrect number of arguments");
return false;
}
m_Makefile->AddSourceGroup(args[0].c_str(), args[1].c_str());
return true;
}

View File

@ -0,0 +1,84 @@
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile$
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) 2000 National Library of Medicine
All rights reserved.
See COPYRIGHT.txt for copyright details.
=========================================================================*/
#ifndef cmSourceGroupCommand_h
#define cmSourceGroupCommand_h
#include "cmStandardIncludes.h"
#include "cmCommand.h"
/** \class cmSourceGroupCommand
* \brief Adds a cmSourceGroup to the cmMakefile.
*
* cmSourceGroupCommand is used to define cmSourceGroups which split up
* source files in to named, organized groups in the generated makefiles.
*/
class cmSourceGroupCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
virtual cmCommand* Clone()
{
return new cmSourceGroupCommand;
}
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
virtual bool Invoke(std::vector<std::string>& args);
/**
* The name of the command as specified in CMakeList.txt.
*/
virtual const char* GetName() {return "SOURCE_GROUP";}
/**
* This determines if the command gets propagated down
* to makefiles located in subdirectories.
*/
virtual bool IsInherited()
{
return true;
}
/**
* Succinct documentation.
*/
virtual const char* GetTerseDocumentation()
{
return "Define a grouping for sources in the makefile.";
}
/**
* More documentation.
*/
virtual const char* GetFullDocumentation()
{
return
"SOURCE_GROUP(name regex)\n"
"Defines a new source group. Any file whose name matches the regular\n"
"expression will be placed in this group. The LAST regular expression\n"
"of all defined SOURCE_GROUPs that matches the file will be selected.";
}
cmTypeMacro(cmSourceGroupCommand, cmCommand);
};
#endif

View File

@ -394,21 +394,57 @@ void cmUnixMakefileGenerator::OutputObjectDepends(std::ostream& fout)
// Output each custom rule in the following format: // Output each custom rule in the following format:
// m_Result: m_Source m_Depends[0] m_Depends[1] ... // output: source depends...
// (tab) m_Command // (tab) command...
void cmUnixMakefileGenerator::OutputCustomRules(std::ostream& fout) void cmUnixMakefileGenerator::OutputCustomRules(std::ostream& fout)
{ {
for(std::vector<cmMakefile::customCommand>::const_iterator c = // Loop through every source group.
m_Makefile->GetCustomCommands().begin(); for(std::vector<cmSourceGroup>::const_iterator sg =
c != m_Makefile->GetCustomCommands().end(); ++c) m_Makefile->GetSourceGroups().begin();
sg != m_Makefile->GetSourceGroups().end(); ++sg)
{ {
fout << c->m_Result.c_str() << ": " << c->m_Source.c_str(); const cmSourceGroup::CustomCommands& customCommands = sg->GetCustomCommands();
for(std::vector<std::string>::const_iterator d = c->m_Depends.begin(); if(customCommands.empty())
d != c->m_Depends.end(); ++ d) { continue; }
std::string name = sg->GetName();
if(name != "")
{ {
fout << " " << d->c_str(); fout << "# Start of source group \"" << name.c_str() << "\"\n";
} }
fout << "\n\t" << c->m_Command.c_str() << "\n\n";
} // Loop through each source in the source group.
for(cmSourceGroup::CustomCommands::const_iterator cc =
customCommands.begin(); cc != customCommands.end(); ++ cc)
{
std::string source = cc->first;
const cmSourceGroup::Commands& commands = cc->second;
// Loop through every command generating code from the current source.
for(cmSourceGroup::Commands::const_iterator c = commands.begin();
c != commands.end(); ++c)
{
std::string command = c->first;
const cmSourceGroup::CommandFiles& commandFiles = c->second;
// Write a rule for every output generated by this command.
for(std::set<std::string>::const_iterator output =
commandFiles.m_Outputs.begin();
output != commandFiles.m_Outputs.end(); ++output)
{
fout << output->c_str() << ": " << source.c_str();
// Write out all the dependencies for this rule.
for(std::set<std::string>::const_iterator d =
commandFiles.m_Depends.begin();
d != commandFiles.m_Depends.end(); ++d)
{
fout << " " << d->c_str();
}
fout << "\n\t" << command.c_str() << "\n\n";
}
}
}
if(name != "")
{
fout << "# End of source group \"" << name.c_str() << "\"\n\n";
}
}
} }

View File

@ -104,9 +104,10 @@ void cmWrapTclCommand::FinalPass()
std::string res = m_WrapClasses[classNum].m_ClassName + ".cxx"; std::string res = m_WrapClasses[classNum].m_ClassName + ".cxx";
std::string cmd = wtcl + " " + m_WrapHeaders[classNum] + " " std::string cmd = wtcl + " " + m_WrapHeaders[classNum] + " "
+ hints + (m_WrapClasses[classNum].m_AbstractClass ? " 0 " : " 1 ") + " > " + m_WrapClasses[classNum].m_ClassName + ".cxx"; + hints + (m_WrapClasses[classNum].m_AbstractClass ? " 0 " : " 1 ") + " > " + m_WrapClasses[classNum].m_ClassName + ".cxx";
m_Makefile->AddCustomCommand(m_WrapHeaders[classNum].c_str(), m_Makefile->AddCustomCommand(m_WrapHeaders[classNum].c_str(),
res.c_str(), cmd.c_str(),
cmd.c_str(), depends); depends,
res.c_str());
} }
} }