Merge topic 'ninja-directory-targets'

9ead71df Help: Add notes for topic 'ninja-directory-targets'
e9bf8ec8 Ninja: Add test for `$subdir/all` targets
ca575fe9 Ninja: Add `$subdir/all` targets
This commit is contained in:
Brad King 2016-03-22 11:15:38 -04:00 committed by CMake Topic Stage
commit 2f9e6551c0
8 changed files with 117 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
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.

View File

@ -0,0 +1,7 @@
ninja-directory-targets
-----------------------
* The :generator:`Ninja` generator learned to produce phony targets
of the form ``sub/dir/all`` to drive the build of a subdirectory.
This is equivalent to ``cd sub/dir; make all`` with
:ref:`Makefile Generators`.

View File

@ -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)

View File

@ -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);

View File

@ -16,3 +16,19 @@ run_CMP0058(WARN-no)
run_CMP0058(WARN-by)
run_CMP0058(NEW-no)
run_CMP0058(NEW-by)
function(run_SubDir)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SubDir-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(SubDir)
if(WIN32)
set(SubDir_all [[SubDir\all]])
else()
set(SubDir_all [[SubDir/all]])
endif()
run_cmake_command(SubDir-build ${CMAKE_COMMAND} --build . --target ${SubDir_all})
endfunction()
run_SubDir()

View File

@ -0,0 +1 @@
Building InAll

View File

@ -0,0 +1,2 @@
add_subdirectory(SubDir)
add_custom_target(TopFail ALL COMMAND does_not_exist)

View File

@ -0,0 +1,2 @@
add_custom_target(SubFail COMMAND does_not_exist)
add_custom_target(InAll ALL COMMAND ${CMAKE_COMMAND} -E echo "Building InAll")