From 8c087d0e7a2045fead07d3069eefddfa4c515179 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 20 Mar 2001 13:20:59 -0500 Subject: 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. --- Source/CMakeLib.dsp | 4 + Source/Makefile.in | 4 +- Source/cmCableCommand.cxx | 4 +- Source/cmCablePackageCommand.cxx | 12 ++- Source/cmCommands.cxx | 2 + Source/cmDSPMakefile.cxx | 208 ++++++++++++++++++++++--------------- Source/cmDSPMakefile.h | 11 +- Source/cmDSPWriter.cxx | 208 ++++++++++++++++++++++--------------- Source/cmDSPWriter.h | 11 +- Source/cmMakefile.cxx | 84 +++++++++++++-- Source/cmMakefile.h | 42 +++++--- Source/cmSourceGroup.cxx | 87 ++++++++++++++++ Source/cmSourceGroup.h | 94 +++++++++++++++++ Source/cmSourceGroupCommand.cxx | 31 ++++++ Source/cmSourceGroupCommand.h | 84 +++++++++++++++ Source/cmUnixMakefileGenerator.cxx | 60 ++++++++--- Source/cmWrapTclCommand.cxx | 7 +- 17 files changed, 721 insertions(+), 232 deletions(-) create mode 100644 Source/cmSourceGroup.cxx create mode 100644 Source/cmSourceGroup.h create mode 100644 Source/cmSourceGroupCommand.cxx create mode 100644 Source/cmSourceGroupCommand.h diff --git a/Source/CMakeLib.dsp b/Source/CMakeLib.dsp index 9da72ea..2af4746 100644 --- a/Source/CMakeLib.dsp +++ b/Source/CMakeLib.dsp @@ -125,6 +125,10 @@ SOURCE=.\cmRegularExpression.cxx # End Source File # Begin Source File +SOURCE=.\cmSourceGroup.cxx +# End Source File +# Begin Source File + SOURCE=.\cmSystemTools.cxx # End Source File # Begin Source File diff --git a/Source/Makefile.in b/Source/Makefile.in index fcaeb9a..352944e 100644 --- a/Source/Makefile.in +++ b/Source/Makefile.in @@ -22,7 +22,8 @@ cmSystemTools.o \ cmDirectory.o \ cmUnixMakefileGenerator.o \ cmCommands.o \ -cmCacheManager.o +cmCacheManager.o \ +cmSourceGroup.o DEPENDS = $(srcdir)/*.h ${CMAKE_CONFIG_DIR}/CMake/Source/cmConfigure.h @@ -38,6 +39,7 @@ cmDirectory.o : $(DEPENDS) cmUnixMakefileGenerator.o : $(DEPENDS) cmCommands.o : $(DEPENDS) cmCacheManager.o : $(DEPENDS) +cmSourceGroup.o : $(DEPENDS) diff --git a/Source/cmCableCommand.cxx b/Source/cmCableCommand.cxx index f200037..8e23945 100644 --- a/Source/cmCableCommand.cxx +++ b/Source/cmCableCommand.cxx @@ -107,7 +107,7 @@ void cmCableCommand::SetupCableData() std::vector depends; m_Makefile->AddCustomCommand(cMakeLists.c_str(), - "cable_config.xml", command.c_str(), - depends); + depends, + "cable_config.xml"); } diff --git a/Source/cmCablePackageCommand.cxx b/Source/cmCablePackageCommand.cxx index 4c334a7..aca0612 100644 --- a/Source/cmCablePackageCommand.cxx +++ b/Source/cmCablePackageCommand.cxx @@ -60,17 +60,19 @@ bool cmCablePackageCommand::Invoke(std::vector& args) // files. std::string command = "${CABLE}"; m_Makefile->ExpandVariablesInString(command); - std::vector depends; + std::vector depends; depends.push_back(command); command += " cable_config.xml"; - std::string packageFile = "Cxx/"+m_PackageName+"_cxx.cxx"; + std::vector 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", - packageFile.c_str(), command.c_str(), - depends); + depends, + outputs); return true; } diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 7bdcaac..1debaa0 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -42,6 +42,7 @@ #include "cmBuildSharedLibrariesCommand.cxx" #include "cmUtilitySourceCommand.cxx" #include "cmIncludeRegularExpressionCommand.cxx" +#include "cmSourceGroupCommand.cxx" void GetPredefinedCommands(std::list& commands) { @@ -81,6 +82,7 @@ void GetPredefinedCommands(std::list& commands) commands.push_back(new cmBuildSharedLibrariesCommand); commands.push_back(new cmUtilitySourceCommand); commands.push_back(new cmIncludeRegularExpressionCommand); + commands.push_back(new cmSourceGroupCommand); } diff --git a/Source/cmDSPMakefile.cxx b/Source/cmDSPMakefile.cxx index 10c9da8..31efded 100644 --- a/Source/cmDSPMakefile.cxx +++ b/Source/cmDSPMakefile.cxx @@ -170,42 +170,127 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout) dsprule += " -B"; dsprule += m_Makefile->GetHomeOutputDirectory(); + std::set depends; + std::set outputs; + outputs.insert(outputs.begin(), dspname); + fout << "# Begin Source File\n\n"; + 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 depends; - this->WriteCustomRule(fout, makefileIn.c_str(), - dspname.c_str(), - dsprule.c_str(), - depends); + std::vector outputs; + outputs.push_back(dspname); + sourceGroup.AddCustomCommand(makefileIn.c_str(), dsprule.c_str(), + depends, outputs); } + void cmDSPMakefile::WriteDSPFile(std::ostream& fout) { + // Write the DSP file's header. 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"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "Header Files", "h;hpp;hxx;hm;inl"); - this->WriteDSPBuildRules(fout,"h;hpp;hxx;hm;inl"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "XML Files", "xml"); - this->WriteDSPBuildRules(fout,"xml"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "Text Files", "txt"); - this->WriteDSPBuildRules(fout,"txt"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBuildRule(fout); + + // We may be modifying the source groups temporarily, so make a copy. + std::vector sourceGroups = m_Makefile->GetSourceGroups(); + + // Find the group in which the CMakeLists.txt source belongs, and add + // the rule to generate this DSP file. + for(std::vector::reverse_iterator sg = sourceGroups.rbegin(); + sg != sourceGroups.rend(); ++sg) + { + if(sg->Matches("CMakeLists.txt")) + { + this->AddDSPBuildRule(*sg); + break; + } + } + + // Loop through every source group. + for(std::vector::const_iterator sg = sourceGroups.begin(); + sg != sourceGroups.end(); ++sg) + { + const std::vector& 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::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); } void cmDSPMakefile::WriteCustomRule(std::ostream& fout, - const char* source, - const char* result, const char* command, - std::vector& depends) + const std::set& depends, + const std::set& outputs) { - fout << "# Begin Source File\n\n"; - fout << "SOURCE=" << source << "\n\n"; - std::vector::iterator 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 << "# Begin Custom Build\n\n"; - fout << '\"' << result << "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\" "; - for (int i = 0; i < depends.size(); i++) + fout << "BuildCommand = " << command << "\n\n"; + + // Write a rule for every output generated by this command. + for(std::set::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::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 << "!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 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& 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& 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) { @@ -402,5 +442,3 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path) << path << "\n"; fout << "# End Source File\n"; } - - diff --git a/Source/cmDSPMakefile.h b/Source/cmDSPMakefile.h index 0c4906b..f1a2003 100644 --- a/Source/cmDSPMakefile.h +++ b/Source/cmDSPMakefile.h @@ -75,15 +75,14 @@ private: const char* filter); void WriteDSPEndGroup(std::ostream& fout); void WriteDSPHeader(std::ostream& fout); - void WriteDSPBuildRules(std::ostream& fout, const char *extensions); void WriteDSPBuildRule(std::ostream& fout, const char*); - void WriteDSPFooter(std::ostream& fout); void WriteDSPBuildRule(std::ostream& fout); + void WriteDSPFooter(std::ostream& fout); + void AddDSPBuildRule(cmSourceGroup&); void WriteCustomRule(std::ostream& fout, - const char* source, - const char* result, - const char* command, - std::vector& depends); + const char* command, + const std::set& depends, + const std::set& outputs); std::string m_IncludeOptions; std::string m_LibraryOptions; diff --git a/Source/cmDSPWriter.cxx b/Source/cmDSPWriter.cxx index 10c9da8..31efded 100644 --- a/Source/cmDSPWriter.cxx +++ b/Source/cmDSPWriter.cxx @@ -170,42 +170,127 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout) dsprule += " -B"; dsprule += m_Makefile->GetHomeOutputDirectory(); + std::set depends; + std::set outputs; + outputs.insert(outputs.begin(), dspname); + fout << "# Begin Source File\n\n"; + 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 depends; - this->WriteCustomRule(fout, makefileIn.c_str(), - dspname.c_str(), - dsprule.c_str(), - depends); + std::vector outputs; + outputs.push_back(dspname); + sourceGroup.AddCustomCommand(makefileIn.c_str(), dsprule.c_str(), + depends, outputs); } + void cmDSPMakefile::WriteDSPFile(std::ostream& fout) { + // Write the DSP file's header. 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"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "Header Files", "h;hpp;hxx;hm;inl"); - this->WriteDSPBuildRules(fout,"h;hpp;hxx;hm;inl"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "XML Files", "xml"); - this->WriteDSPBuildRules(fout,"xml"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBeginGroup(fout, "Text Files", "txt"); - this->WriteDSPBuildRules(fout,"txt"); - this->WriteDSPEndGroup(fout); - this->WriteDSPBuildRule(fout); + + // We may be modifying the source groups temporarily, so make a copy. + std::vector sourceGroups = m_Makefile->GetSourceGroups(); + + // Find the group in which the CMakeLists.txt source belongs, and add + // the rule to generate this DSP file. + for(std::vector::reverse_iterator sg = sourceGroups.rbegin(); + sg != sourceGroups.rend(); ++sg) + { + if(sg->Matches("CMakeLists.txt")) + { + this->AddDSPBuildRule(*sg); + break; + } + } + + // Loop through every source group. + for(std::vector::const_iterator sg = sourceGroups.begin(); + sg != sourceGroups.end(); ++sg) + { + const std::vector& 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::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); } void cmDSPMakefile::WriteCustomRule(std::ostream& fout, - const char* source, - const char* result, const char* command, - std::vector& depends) + const std::set& depends, + const std::set& outputs) { - fout << "# Begin Source File\n\n"; - fout << "SOURCE=" << source << "\n\n"; - std::vector::iterator 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 << "# Begin Custom Build\n\n"; - fout << '\"' << result << "\" : \"$(SOURCE)\" \"$(INTDIR)\" \"$(OUTDIR)\" "; - for (int i = 0; i < depends.size(); i++) + fout << "BuildCommand = " << command << "\n\n"; + + // Write a rule for every output generated by this command. + for(std::set::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::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 << "!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 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& 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& 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) { @@ -402,5 +442,3 @@ void cmDSPMakefile::WriteDSPBuildRule(std::ostream& fout, const char* path) << path << "\n"; fout << "# End Source File\n"; } - - diff --git a/Source/cmDSPWriter.h b/Source/cmDSPWriter.h index 0c4906b..f1a2003 100644 --- a/Source/cmDSPWriter.h +++ b/Source/cmDSPWriter.h @@ -75,15 +75,14 @@ private: const char* filter); void WriteDSPEndGroup(std::ostream& fout); void WriteDSPHeader(std::ostream& fout); - void WriteDSPBuildRules(std::ostream& fout, const char *extensions); void WriteDSPBuildRule(std::ostream& fout, const char*); - void WriteDSPFooter(std::ostream& fout); void WriteDSPBuildRule(std::ostream& fout); + void WriteDSPFooter(std::ostream& fout); + void AddDSPBuildRule(cmSourceGroup&); void WriteCustomRule(std::ostream& fout, - const char* source, - const char* result, - const char* command, - std::vector& depends); + const char* command, + const std::set& depends, + const std::set& outputs); std::string m_IncludeOptions; std::string m_LibraryOptions; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8248f5e..87cc709 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -27,10 +27,14 @@ cmMakefile::cmMakefile() { // 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_DefineFlags = " "; 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->AddDefaultDefinitions(); } @@ -249,21 +253,33 @@ void cmMakefile::GenerateMakefile() void cmMakefile::AddClass(cmClassFile& 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& depends, + const std::vector& outputs) +{ + cmSourceGroup& sourceGroup = this->FindSourceGroup(source); + sourceGroup.AddCustomCommand(source, command, depends, outputs); +} void cmMakefile::AddCustomCommand(const char* source, - const char* result, - const char* command, - std::vector& depends) + const char* command, + const std::vector& depends, + const char* output) { - cmMakefile::customCommand customCommand; - customCommand.m_Source = source; - customCommand.m_Result = result; - customCommand.m_Command = command; - customCommand.m_Depends = depends; - m_CustomCommands.push_back(customCommand); + std::vector outputs; + outputs.push_back(output); + this->AddCustomCommand(source, command, depends, outputs); } void cmMakefile::AddDefineFlag(const char* flag) @@ -335,6 +351,25 @@ void cmMakefile::SetLibraryName(const char* 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::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) { @@ -549,3 +584,32 @@ void cmMakefile::AddDefaultDefinitions() this->AddDefinition("CMAKE_CFG_OUTDIR","."); #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::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(); +} diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 21ce96f..83e4fe6 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -19,6 +19,7 @@ #include "cmStandardIncludes.h" #include "cmClassFile.h" #include "cmSystemTools.h" +#include "cmSourceGroup.h" class cmCommand; class cmMakefileGenerator; @@ -74,9 +75,15 @@ public: * Add a custom command to the build. */ void AddCustomCommand(const char* source, - const char* result, - const char* command, - std::vector& depends); + const char* command, + const std::vector& depends, + const std::vector& outputs); + + void AddCustomCommand(const char* source, + const char* command, + const std::vector& depends, + const char* output); + /** * Add a define flag to the build. */ @@ -147,6 +154,11 @@ public: 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. */ void AddExtraDirectory(const char* dir); @@ -370,6 +382,12 @@ public: {return m_UsedCommands;} /** + * Get the vector source groups. + */ + const std::vector& GetSourceGroups() const + { return m_SourceGroups; } + + /** * Dump documentation to a file. If 0 is returned, the * operation failed. */ @@ -387,19 +405,7 @@ public: /** * Expand variables in the makefiles ivars such as link directories etc */ - void ExpandVariables(); - - struct customCommand - { - std::string m_Source; - std::string m_Result; - std::string m_Command; - std::vector m_Depends; - }; - - std::vector& GetCustomCommands() { - return m_CustomCommands; }; - + void ExpandVariables(); /** Recursivly read and create a cmMakefile object for * all CMakeLists.txt files in the GetSubDirectories list. @@ -440,7 +446,7 @@ protected: std::vector m_LinkLibrariesUnix; std::string m_IncludeFileRegularExpression; std::string m_DefineFlags; - std::vector m_CustomCommands; + std::vector m_SourceGroups; typedef std::map RegisteredCommandsMap; typedef std::map DefinitionMap; DefinitionMap m_Definitions; @@ -461,6 +467,8 @@ private: void PrintStringVector(const char* s, std::vector& v); void AddDefaultCommands(); void AddDefaultDefinitions(); + + cmSourceGroup& FindSourceGroup(const char* source); }; diff --git a/Source/cmSourceGroup.cxx b/Source/cmSourceGroup.cxx new file mode 100644 index 0000000..fc09631 --- /dev/null +++ b/Source/cmSourceGroup.cxx @@ -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& depends, + const std::vector& 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()); +} diff --git a/Source/cmSourceGroup.h b/Source/cmSourceGroup.h new file mode 100644 index 0000000..bc8ec1c --- /dev/null +++ b/Source/cmSourceGroup.h @@ -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 + +/** \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 m_Outputs; + std::set m_Depends; + }; + + /** + * Map from command to its output/depends sets. + */ + typedef std::map Commands; + + /** + * Map from source to command map. + */ + typedef std::map 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& depends, + const std::vector& outputs); + const char* GetName() const + { return m_Name.c_str(); } + const std::vector& 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 m_Sources; + + /** + * The custom commands in this group and their corresponding sources. + */ + CustomCommands m_CustomCommands; +}; + +#endif diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx new file mode 100644 index 0000000..4559e70 --- /dev/null +++ b/Source/cmSourceGroupCommand.cxx @@ -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& 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; +} + diff --git a/Source/cmSourceGroupCommand.h b/Source/cmSourceGroupCommand.h new file mode 100644 index 0000000..7a48a64 --- /dev/null +++ b/Source/cmSourceGroupCommand.h @@ -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& 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 diff --git a/Source/cmUnixMakefileGenerator.cxx b/Source/cmUnixMakefileGenerator.cxx index 955b108..0128848 100644 --- a/Source/cmUnixMakefileGenerator.cxx +++ b/Source/cmUnixMakefileGenerator.cxx @@ -394,21 +394,57 @@ void cmUnixMakefileGenerator::OutputObjectDepends(std::ostream& fout) // Output each custom rule in the following format: -// m_Result: m_Source m_Depends[0] m_Depends[1] ... -// (tab) m_Command +// output: source depends... +// (tab) command... void cmUnixMakefileGenerator::OutputCustomRules(std::ostream& fout) { - for(std::vector::const_iterator c = - m_Makefile->GetCustomCommands().begin(); - c != m_Makefile->GetCustomCommands().end(); ++c) + // Loop through every source group. + for(std::vector::const_iterator sg = + m_Makefile->GetSourceGroups().begin(); + sg != m_Makefile->GetSourceGroups().end(); ++sg) { - fout << c->m_Result.c_str() << ": " << c->m_Source.c_str(); - for(std::vector::const_iterator d = c->m_Depends.begin(); - d != c->m_Depends.end(); ++ d) + const cmSourceGroup::CustomCommands& customCommands = sg->GetCustomCommands(); + if(customCommands.empty()) + { 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::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::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"; + } + } } diff --git a/Source/cmWrapTclCommand.cxx b/Source/cmWrapTclCommand.cxx index b6e3d40..522fe46 100644 --- a/Source/cmWrapTclCommand.cxx +++ b/Source/cmWrapTclCommand.cxx @@ -104,9 +104,10 @@ void cmWrapTclCommand::FinalPass() std::string res = m_WrapClasses[classNum].m_ClassName + ".cxx"; std::string cmd = wtcl + " " + m_WrapHeaders[classNum] + " " + hints + (m_WrapClasses[classNum].m_AbstractClass ? " 0 " : " 1 ") + " > " + m_WrapClasses[classNum].m_ClassName + ".cxx"; - m_Makefile->AddCustomCommand(m_WrapHeaders[classNum].c_str(), - res.c_str(), - cmd.c_str(), depends); + m_Makefile->AddCustomCommand(m_WrapHeaders[classNum].c_str(), + cmd.c_str(), + depends, + res.c_str()); } } -- cgit v0.12