Ver código fonte

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.
Charles Huet 9 anos atrás
pai
commit
ca575fe935

+ 4 - 0
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.

+ 82 - 0
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<cmLocalNinjaGenerator *>(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<std::string, cmNinjaDeps> targetsPerFolder;
+  for (std::vector<cmLocalGenerator *>::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<cmGeneratorTarget*>::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<cmState::Snapshot> const& children =
+      lg->GetStateSnapshot().GetChildren();
+    for(std::vector<cmState::Snapshot>::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<std::string, cmNinjaDeps >::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)

+ 3 - 0
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);