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.
This commit is contained in:
Charles Huet 2016-03-11 16:26:29 +01:00 committed by Brad King
parent 9cdb37e917
commit ca575fe935
3 changed files with 89 additions and 0 deletions

View File

@ -6,3 +6,7 @@ Generates build.ninja files.
A build.ninja file is generated into the build tree. Recent versions A build.ninja file is generated into the build tree. Recent versions
of the ninja program can build the project through the "all" target. of the ninja program can build the project through the "all" target.
An "install" target is also provided. 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.

View File

@ -577,6 +577,7 @@ void cmGlobalNinjaGenerator::Generate()
this->WriteAssumedSourceDependencies(); this->WriteAssumedSourceDependencies();
this->WriteTargetAliases(*this->BuildFileStream); this->WriteTargetAliases(*this->BuildFileStream);
this->WriteFolderTargets(*this->BuildFileStream);
this->WriteUnknownExplicitDependencies(*this->BuildFileStream); this->WriteUnknownExplicitDependencies(*this->BuildFileStream);
this->WriteBuiltinTargets(*this->BuildFileStream); this->WriteBuiltinTargets(*this->BuildFileStream);
@ -848,6 +849,18 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path)
return convPath; 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( void cmGlobalNinjaGenerator::AddCXXCompileCommand(
const std::string &commandLine, const std::string &commandLine,
const std::string &sourceFile) 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) void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os)
{ {
if (!this->ComputingUnknownDependencies) if (!this->ComputingUnknownDependencies)

View File

@ -228,6 +228,8 @@ public:
return this->RulesFileStream; } return this->RulesFileStream; }
std::string ConvertToNinjaPath(const std::string& path); std::string ConvertToNinjaPath(const std::string& path);
std::string ConvertToNinjaFolderRule(const std::string& path);
struct MapToNinjaPathImpl { struct MapToNinjaPathImpl {
cmGlobalNinjaGenerator* GG; cmGlobalNinjaGenerator* GG;
@ -342,6 +344,7 @@ private:
void WriteAssumedSourceDependencies(); void WriteAssumedSourceDependencies();
void WriteTargetAliases(std::ostream& os); void WriteTargetAliases(std::ostream& os);
void WriteFolderTargets(std::ostream& os);
void WriteUnknownExplicitDependencies(std::ostream& os); void WriteUnknownExplicitDependencies(std::ostream& os);
void WriteBuiltinTargets(std::ostream& os); void WriteBuiltinTargets(std::ostream& os);