diff --git a/Source/cmLocalUnixMakefileGenerator2.cxx b/Source/cmLocalUnixMakefileGenerator2.cxx index 3c5b5d0bc..56b733c30 100644 --- a/Source/cmLocalUnixMakefileGenerator2.cxx +++ b/Source/cmLocalUnixMakefileGenerator2.cxx @@ -24,13 +24,16 @@ #include // Quick-switch for generating old makefiles. -#if 0 +#if 1 # define CMLUMG_MAKEFILE_NAME "Makefile" #else # define CMLUMG_WRITE_OLD_MAKEFILE # define CMLUMG_MAKEFILE_NAME "Makefile2" #endif +// TODO: Add "help" target. +// TODO: Add install targets to m_InstallTargets list. + //---------------------------------------------------------------------------- cmLocalUnixMakefileGenerator2::cmLocalUnixMakefileGenerator2() { @@ -130,16 +133,24 @@ void cmLocalUnixMakefileGenerator2::GenerateMakefile() this->WriteAllRules(makefileStream); // Write dependency generation rules. - this->WriteDependRules(makefileStream); + this->WritePassRules(makefileStream, "depend", + "Build dependencies for this directory.", + m_DependTargets); // Write main build rules. - this->WriteBuildRules(makefileStream); + this->WritePassRules(makefileStream, "build", + "Build targets in this directory.", + m_BuildTargets); + + // Write install rules. + this->WritePassRules(makefileStream, "install", + "Install files from this directory.", + m_InstallTargets); // Write clean rules. - this->WriteCleanRules(makefileStream); - - // TODO: Write install rules. - //this->WriteInstallRules(makefileStream); + this->WritePassRules(makefileStream, "clean", + "Clean targets in this directory.", + m_CleanTargets); // Write include statements to get rules for this directory. this->WriteRuleFileIncludes(makefileStream); @@ -299,28 +310,7 @@ cmLocalUnixMakefileGenerator2 << "\n"; } - // Write the dependency generation rule. - { - std::vector depends; - std::vector no_commands; - std::string depEcho = "Building dependencies for "; - depEcho += target.GetName(); - depEcho += "..."; - std::string depTarget = dir; - depTarget += "/"; - depTarget += target.GetName(); - depTarget += ".depends"; - for(std::vector::const_iterator obj = objects.begin(); - obj != objects.end(); ++obj) - { - depends.push_back((*obj)+".depends"); - } - depends.push_back(ruleFileName); - this->WriteMakeRule(ruleFileStream, 0, depEcho.c_str(), - depTarget.c_str(), depends, no_commands); - } - - // Write the build rule. + // Write the rule for this target type. switch(target.GetType()) { case cmTarget::STATIC_LIBRARY: @@ -1002,157 +992,33 @@ cmLocalUnixMakefileGenerator2 //---------------------------------------------------------------------------- void -cmLocalUnixMakefileGenerator2::WriteDependRules(std::ostream& makefileStream) +cmLocalUnixMakefileGenerator2 +::WritePassRules(std::ostream& makefileStream, + const char* pass, + const char* comment, + const std::vector& depends) { // Write section header. this->WriteDivider(makefileStream); makefileStream - << "# Rules for computing dependencies.\n" + << "# Rules for the " << pass << " pass.\n" << "\n"; - // TODO: Unify WriteDependRules, WriteBuildRules, WriteCleanRules, - // etc. They are mostly duplicate code. - - // TODO: Add registered files for cleaning. - - // Write rules to traverse the directory tree building dependencies. - this->WriteDriverRules(makefileStream, "depend", "depend.local"); - - // Write the rule to build dependencies in this directory. It just - // depends on all targets' dependencies. - const cmTargets& targets = m_Makefile->GetTargets(); - std::vector depends; - std::vector commands; - for(cmTargets::const_iterator t = targets.begin(); t != targets.end(); ++t) - { - // TODO: Dispatch generation of each target type. - if((t->second.GetType() == cmTarget::EXECUTABLE) || - (t->second.GetType() == cmTarget::STATIC_LIBRARY) || - (t->second.GetType() == cmTarget::SHARED_LIBRARY) || - (t->second.GetType() == cmTarget::MODULE_LIBRARY)) - { - if(t->second.IsInAll()) - { - std::string dep = this->GetTargetDirectory(t->second); - dep += "/"; - dep += t->first; - dep += ".depends"; - depends.push_back(dep); - } - } - } + // Write rules to traverse the directory tree for this pass. + std::string passLocal = pass; + passLocal += ".local"; + this->WriteDriverRules(makefileStream, pass, passLocal.c_str()); // If there are no dependencies, use empty commands. + std::vector commands; if(depends.empty()) { commands = m_EmptyCommands; } // Write the rule. - this->WriteMakeRule(makefileStream, - "Build dependencies for this directory.", - 0, - "depend.local", - depends, - commands); -} - -//---------------------------------------------------------------------------- -void -cmLocalUnixMakefileGenerator2::WriteBuildRules(std::ostream& makefileStream) -{ - // Write section header. - this->WriteDivider(makefileStream); - makefileStream - << "# Rules for building targets.\n" - << "\n"; - - // Write rules to traverse the directory tree building targets. - this->WriteDriverRules(makefileStream, "build", "build.local"); - - // Write the rule to build targets in this directory. It just - // depends on all targets. - const cmTargets& targets = m_Makefile->GetTargets(); - std::vector depends; - std::vector commands; - for(cmTargets::const_iterator t = targets.begin(); t != targets.end(); ++t) - { - // TODO: Dispatch generation of each target type. - if((t->second.GetType() == cmTarget::EXECUTABLE) || - (t->second.GetType() == cmTarget::STATIC_LIBRARY) || - (t->second.GetType() == cmTarget::SHARED_LIBRARY) || - (t->second.GetType() == cmTarget::MODULE_LIBRARY)) - { - if(t->second.IsInAll()) - { - depends.push_back(t->first); - } - } - } - - // If there are no dependencies, use empty commands. - if(depends.empty()) - { - commands = m_EmptyCommands; - } - - // Write the rule. - this->WriteMakeRule(makefileStream, - "Build targets in this directory.", - 0, - "build.local", - depends, - commands); -} - -//---------------------------------------------------------------------------- -void -cmLocalUnixMakefileGenerator2::WriteCleanRules(std::ostream& makefileStream) -{ - // Write section header. - this->WriteDivider(makefileStream); - makefileStream - << "# Rules for cleaning targets.\n" - << "\n"; - - // Write rules to traverse the directory tree cleaning targets. - this->WriteDriverRules(makefileStream, "clean", "clean.local"); - - // Write the rule to clean targets in this directory. It just - // depends on all targets' clean rules. - const cmTargets& targets = m_Makefile->GetTargets(); - std::vector depends; - std::vector commands; - for(cmTargets::const_iterator t = targets.begin(); t != targets.end(); ++t) - { - // TODO: Dispatch generation of each target type. - if((t->second.GetType() == cmTarget::EXECUTABLE) || - (t->second.GetType() == cmTarget::STATIC_LIBRARY) || - (t->second.GetType() == cmTarget::SHARED_LIBRARY) || - (t->second.GetType() == cmTarget::MODULE_LIBRARY)) - { - if(t->second.IsInAll()) - { - std::string clean = t->first; - clean += ".clean"; - depends.push_back(clean); - } - } - } - - // If there are no dependencies, use empty commands. - if(depends.empty()) - { - commands = m_EmptyCommands; - } - - // Write the rule. - this->WriteMakeRule(makefileStream, - "Clean targets in this directory.", - 0, - "clean.local", - depends, - commands); + this->WriteMakeRule(makefileStream, comment, 0, passLocal.c_str(), + depends, commands); } //---------------------------------------------------------------------------- @@ -1336,9 +1202,9 @@ cmLocalUnixMakefileGenerator2 // Build comment to describe purpose. std::string comment = "Driver target for "; comment += order; - comment += "-order subdirectories during "; + comment += "-order subdirectories during the "; comment += pass; - comment += "."; + comment += " pass."; // Build the make target name. std::string tgt = pass; @@ -1431,6 +1297,9 @@ cmLocalUnixMakefileGenerator2 const cmTarget& target, std::vector& objects) { + // Write the dependency generation rule. + this->WriteTargetDependsRule(ruleFileStream, ruleFileName, target, objects); + std::vector commands; // Build list of dependencies. @@ -1554,19 +1423,17 @@ cmLocalUnixMakefileGenerator2 // Write convenience targets. this->WriteConvenienceRules(ruleFileStream, target, targetFullPath.c_str()); - // Write clean target. TODO: Unify with all target and object file - // cleaning rules. - std::string remove = "$(CMAKE_COMMAND) -E remove -f "; - remove += this->ConvertToRelativeOutputPath(targetFullPath.c_str()); - remove += " "; - remove += objs; - std::string cleanTarget = target.GetName(); - cleanTarget += ".clean"; - commands.clear(); - depends.clear(); - commands.push_back(remove); - this->WriteMakeRule(ruleFileStream, 0, 0, cleanTarget.c_str(), - depends, commands); + // Write clean target. + std::vector cleanFiles; + cleanFiles.push_back(this->ConvertToRelativeOutputPath(targetFullPath.c_str())); + cleanFiles.push_back(objs); + this->WriteTargetCleanRule(ruleFileStream, target, cleanFiles); + + // Add this to the list of build rules in this directory. + if(target.IsInAll()) + { + m_BuildTargets.push_back(target.GetName()); + } } //---------------------------------------------------------------------------- @@ -1656,6 +1523,9 @@ cmLocalUnixMakefileGenerator2 const char* linkRuleVar, const char* extraFlags) { + // Write the dependency generation rule. + this->WriteTargetDependsRule(ruleFileStream, ruleFileName, target, objects); + // TODO: Merge the methods that call this method to avoid // code duplication. std::vector commands; @@ -1725,18 +1595,22 @@ cmLocalUnixMakefileGenerator2 } // Add a command to remove any existing files for this library. + std::vector cleanFiles; std::string remove = "$(CMAKE_COMMAND) -E remove -f "; remove += targetFullPathReal; + cleanFiles.push_back(targetFullPathReal); if(targetFullPathSO != targetFullPathReal) { remove += " "; remove += targetFullPathSO; + cleanFiles.push_back(targetFullPathSO); } if(targetFullPath != targetFullPathSO && targetFullPath != targetFullPathReal) { remove += " "; remove += targetFullPath; + cleanFiles.push_back(targetFullPath); } commands.push_back(remove); @@ -1811,17 +1685,15 @@ cmLocalUnixMakefileGenerator2 // Write convenience targets. this->WriteConvenienceRules(ruleFileStream, target, targetFullPath.c_str()); - // Write clean target. TODO: Unify with all target and object file - // cleaning rules. - std::string cleanTarget = target.GetName(); - cleanTarget += ".clean"; - commands.clear(); - depends.clear(); - remove += " "; - remove += objs; - commands.push_back(remove); - this->WriteMakeRule(ruleFileStream, 0, 0, cleanTarget.c_str(), - depends, commands); + // Write clean target. + cleanFiles.push_back(objs); + this->WriteTargetCleanRule(ruleFileStream, target, cleanFiles); + + // Add this to the list of build rules in this directory. + if(target.IsInAll()) + { + m_BuildTargets.push_back(target.GetName()); + } } //---------------------------------------------------------------------------- @@ -1862,6 +1734,86 @@ cmLocalUnixMakefileGenerator2 << "\n"; } +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteTargetDependsRule(std::ostream& ruleFileStream, + const char* ruleFileName, + const cmTarget& target, + const std::vector& objects) +{ + std::vector depends; + std::vector no_commands; + + // Construct the output message for the rule. + std::string depEcho = "Building dependencies for "; + depEcho += target.GetName(); + depEcho += "..."; + + // Construct the name of the dependency generation target. + std::string depTarget = this->GetTargetDirectory(target); + depTarget += "/"; + depTarget += target.GetName(); + depTarget += ".depends"; + + // This target drives dependency generation for all object files. + for(std::vector::const_iterator obj = objects.begin(); + obj != objects.end(); ++obj) + { + depends.push_back((*obj)+".depends"); + } + + // Depend on the rule file itself. + depends.push_back(ruleFileName); + + // Write the rule. + this->WriteMakeRule(ruleFileStream, 0, depEcho.c_str(), + depTarget.c_str(), depends, no_commands); + + // Add this to the list of depend rules in this directory. + if(target.IsInAll()) + { + m_DependTargets.push_back(depTarget); + } +} + +//---------------------------------------------------------------------------- +void +cmLocalUnixMakefileGenerator2 +::WriteTargetCleanRule(std::ostream& ruleFileStream, + const cmTarget& target, + const std::vector& files) +{ + std::vector no_depends; + std::vector commands; + + // TODO: Add registered files for cleaning. + + // Construct the clean target name. + std::string cleanTarget = target.GetName(); + cleanTarget += ".clean"; + + // Construct the clean command. + std::string remove = "$(CMAKE_COMMAND) -E remove -f"; + for(std::vector::const_iterator f = files.begin(); + f != files.end(); ++f) + { + remove += " "; + remove += *f; + } + commands.push_back(remove); + + // Write the rule. + this->WriteMakeRule(ruleFileStream, 0, 0, cleanTarget.c_str(), + no_depends, commands); + + // Add this to the list of clean rules in this directory. + if(target.IsInAll()) + { + m_CleanTargets.push_back(cleanTarget); + } +} + //---------------------------------------------------------------------------- std::string cmLocalUnixMakefileGenerator2 diff --git a/Source/cmLocalUnixMakefileGenerator2.h b/Source/cmLocalUnixMakefileGenerator2.h index 29682a300..075a89829 100644 --- a/Source/cmLocalUnixMakefileGenerator2.h +++ b/Source/cmLocalUnixMakefileGenerator2.h @@ -82,9 +82,9 @@ protected: void WriteSpecialTargetsBottom(std::ostream& makefileStream); void WriteRuleFileIncludes(std::ostream& makefileStream); void WriteAllRules(std::ostream& makefileStream); - void WriteDependRules(std::ostream& makefileStream); - void WriteBuildRules(std::ostream& makefileStream); - void WriteCleanRules(std::ostream& makefileStream); + void WritePassRules(std::ostream& makefileStream, + const char* pass, const char* comment, + const std::vector& depends); void WriteDriverRules(std::ostream& makefileStream, const char* pass, const char* local1, const char* local2=0); void WriteSubdirRules(std::ostream& makefileStream, const char* pass); @@ -123,6 +123,13 @@ protected: void WriteObjectsVariable(std::ostream& ruleFileStream, const cmTarget& target, std::vector& objects); + void WriteTargetDependsRule(std::ostream& ruleFileStream, + const char* ruleFileName, + const cmTarget& target, + const std::vector& objects); + void WriteTargetCleanRule(std::ostream& ruleFileStream, + const cmTarget& target, + const std::vector& files); std::string GetTargetDirectory(const cmTarget& target); std::string GetSubdirTargetName(const char* pass, const char* subdir); std::string GetObjectFileName(const cmTarget& target, @@ -168,6 +175,13 @@ private: // Set of custom rule files that have been generated. std::set m_CustomRuleFiles; + + // List of target-level rules for each pass. These are populated by + // target rule file writing methods. + std::vector m_DependTargets; + std::vector m_BuildTargets; + std::vector m_InstallTargets; + std::vector m_CleanTargets; }; #endif