From ca575fe9355a2be2b9fadcc84b05bcfa095c5e64 Mon Sep 17 00:00:00 2001 From: Charles Huet Date: Fri, 11 Mar 2016 16:26:29 +0100 Subject: [PATCH] Ninja: Add `$subdir/all` targets With the Makefile generator one can use `cd $subdir; make all` to build all targets associated with a given subdirectory. This is not possible to do with the Ninja generator since there is only one `build.ninja` file at the top of the build tree. However, we can approximate it by allowing one to run `ninja $subdir/all` at the top of the tree to build the targets in the corresponding subdirectory. Port logic from cmGlobalUnixMakefileGenerator3::WriteDirectoryRule2 to cmGlobalNinjaGenerator in order to produce equivalent directory-level targets. --- Help/generator/Ninja.rst | 4 ++ Source/cmGlobalNinjaGenerator.cxx | 82 +++++++++++++++++++++++++++++++ Source/cmGlobalNinjaGenerator.h | 3 ++ 3 files changed, 89 insertions(+) diff --git a/Help/generator/Ninja.rst b/Help/generator/Ninja.rst index 920abcbfa..d94e5f600 100644 --- a/Help/generator/Ninja.rst +++ b/Help/generator/Ninja.rst @@ -6,3 +6,7 @@ Generates build.ninja files. A build.ninja file is generated into the build tree. Recent versions of the ninja program can build the project through the "all" target. An "install" target is also provided. + +For each subdirectory ``sub/dir`` of the project an additional target +named ``sub/dir/all`` is generated that depends on all targets required +by that subdirectory. diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 83422b70f..f12396f50 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -577,6 +577,7 @@ void cmGlobalNinjaGenerator::Generate() this->WriteAssumedSourceDependencies(); this->WriteTargetAliases(*this->BuildFileStream); + this->WriteFolderTargets(*this->BuildFileStream); this->WriteUnknownExplicitDependencies(*this->BuildFileStream); this->WriteBuiltinTargets(*this->BuildFileStream); @@ -848,6 +849,18 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) return convPath; } +std::string +cmGlobalNinjaGenerator::ConvertToNinjaFolderRule(const std::string& path) +{ + cmLocalNinjaGenerator *ng = + static_cast(this->LocalGenerators[0]); + std::string convPath = ng->Convert(path+"/all", cmOutputConverter::HOME); +#ifdef _WIN32 + cmSystemTools::ReplaceString(convPath, "/", "\\"); +#endif + return convPath; +} + void cmGlobalNinjaGenerator::AddCXXCompileCommand( const std::string &commandLine, const std::string &sourceFile) @@ -1044,6 +1057,75 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) } } +void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Folder targets.\n\n"; + + std::map targetsPerFolder; + for (std::vector::const_iterator + lgi = this->LocalGenerators.begin(); + lgi != this->LocalGenerators.end(); ++lgi) + { + cmLocalGenerator const* lg = *lgi; + const std::string currentSourceFolder( + lg->GetStateSnapshot().GetDirectory().GetCurrentSource()); + // The directory-level rule should depend on the target-level rules + // for all targets in the directory. + targetsPerFolder[currentSourceFolder] = cmNinjaDeps(); + for (std::vector::const_iterator + ti = lg->GetGeneratorTargets().begin(); + ti != lg->GetGeneratorTargets().end(); ++ti) + { + cmGeneratorTarget const* gt = *ti; + cmState::TargetType const type = gt->GetType(); + if((type == cmState::EXECUTABLE || + type == cmState::STATIC_LIBRARY || + type == cmState::SHARED_LIBRARY || + type == cmState::MODULE_LIBRARY || + type == cmState::OBJECT_LIBRARY || + type == cmState::UTILITY) && + !gt->GetPropertyAsBool("EXCLUDE_FROM_ALL")) + { + targetsPerFolder[currentSourceFolder].push_back(gt->GetName()); + } + } + + // The directory-level rule should depend on the directory-level + // rules of the subdirectories. + std::vector const& children = + lg->GetStateSnapshot().GetChildren(); + for(std::vector::const_iterator + stateIt = children.begin(); stateIt != children.end(); ++stateIt) + { + targetsPerFolder[currentSourceFolder].push_back( + this->ConvertToNinjaFolderRule( + stateIt->GetDirectory().GetCurrentSource())); + } + } + + std::string const rootSourceDir = + this->LocalGenerators[0]->GetSourceDirectory(); + for (std::map::const_iterator it = + targetsPerFolder.begin(); it != targetsPerFolder.end(); ++it) + { + cmGlobalNinjaGenerator::WriteDivider( os ); + std::string const& currentSourceDir = it->first; + + // Do not generate a rule for the root source dir. + if (rootSourceDir.length() >= currentSourceDir.length()) + { + continue; + } + + std::string const comment = "Folder: " + currentSourceDir; + cmNinjaDeps output(1); + output.push_back(this->ConvertToNinjaFolderRule(currentSourceDir)); + + this->WritePhonyBuild(os, comment, output, it->second); + } +} + void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) { if (!this->ComputingUnknownDependencies) diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 86565902c..3023a95c6 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -228,6 +228,8 @@ public: return this->RulesFileStream; } std::string ConvertToNinjaPath(const std::string& path); + std::string ConvertToNinjaFolderRule(const std::string& path); + struct MapToNinjaPathImpl { cmGlobalNinjaGenerator* GG; @@ -342,6 +344,7 @@ private: void WriteAssumedSourceDependencies(); void WriteTargetAliases(std::ostream& os); + void WriteFolderTargets(std::ostream& os); void WriteUnknownExplicitDependencies(std::ostream& os); void WriteBuiltinTargets(std::ostream& os);