From 88d27ad0140ac2274e886c10ac2bf9f8eede54c7 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Wed, 3 Apr 2013 17:03:43 -0400 Subject: Add a test to expose a bug with add_custom_command and ninja. Ninja Generator is unable to handle an add_custom_command having a dependency that is generated at build time by a previous target. --- Tests/CustomCommand/CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt index d3ced3f..30daa7d 100644 --- a/Tests/CustomCommand/CMakeLists.txt +++ b/Tests/CustomCommand/CMakeLists.txt @@ -123,6 +123,19 @@ add_custom_command( COMMENT "Running TDocument post-build commands" ) +# Setup a custom target that will fail if the POST_BUILD custom command +# isn't run before it. +add_custom_command( + OUTPUT doc3post.txt + DEPENDS ${PROJECT_BINARY_DIR}/doc2post.txt + COMMAND ${CMAKE_COMMAND} -E echo " Copying doc2pre.txt to doc3post.txt." + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/doc2post.txt + ${PROJECT_BINARY_DIR}/doc3post.txt + COMMENT "Running TDocument post-build dependent custom command" + ) +add_custom_target(doc3Post ALL DEPENDS doc3post.txt) +add_dependencies(doc3Post TDocument) + ################################################################ # # Test using a multistep generated file -- cgit v0.12 From 874e17120db832656a77665e2ac13168aaf1e207 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Fri, 7 Jun 2013 14:25:33 -0400 Subject: Ninja: GlobalNinjaGenerator WriteBuild and WritePhonyBuild non static To properly track the usage of dependencies that are generated at compile time as the side effect of other build steps we need to make the WriteBuild and WritePhonyBuild commands non static --- Source/cmGlobalNinjaGenerator.cxx | 90 ++++++++++++++++---------------- Source/cmGlobalNinjaGenerator.h | 34 ++++++------ Source/cmLocalNinjaGenerator.cxx | 17 +++--- Source/cmNinjaNormalTargetGenerator.cxx | 77 ++++++++++++++------------- Source/cmNinjaTargetGenerator.cxx | 24 ++++----- Source/cmNinjaUtilityTargetGenerator.cxx | 19 +++---- 6 files changed, 134 insertions(+), 127 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index e2c0e18..8587e0d 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -208,14 +208,14 @@ void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os, const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables) { - cmGlobalNinjaGenerator::WriteBuild(os, - comment, - "phony", - outputs, - explicitDeps, - implicitDeps, - orderOnlyDeps, - variables); + this->WriteBuild(os, + comment, + "phony", + outputs, + explicitDeps, + implicitDeps, + orderOnlyDeps, + variables); } void cmGlobalNinjaGenerator::AddCustomCommandRule() @@ -251,14 +251,14 @@ cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command, vars["COMMAND"] = cmd; vars["DESC"] = EncodeLiteral(description); - cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, - comment, - "CUSTOM_COMMAND", - outputs, - deps, - cmNinjaDeps(), - orderOnlyDeps, - vars); + this->WriteBuild(*this->BuildFileStream, + comment, + "CUSTOM_COMMAND", + outputs, + deps, + cmNinjaDeps(), + orderOnlyDeps, + vars); } void @@ -293,14 +293,14 @@ cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input, deps.push_back(input); cmNinjaVars vars; - cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, - "", - "COPY_OSX_CONTENT", - outputs, - deps, - cmNinjaDeps(), - cmNinjaDeps(), - cmNinjaVars()); + this->WriteBuild(*this->BuildFileStream, + "", + "COPY_OSX_CONTENT", + outputs, + deps, + cmNinjaDeps(), + cmNinjaDeps(), + cmNinjaVars()); } void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, @@ -896,10 +896,10 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) cmNinjaDeps deps; this->AppendTargetOutputs(i->second, deps); - cmGlobalNinjaGenerator::WritePhonyBuild(os, - "", - cmNinjaDeps(1, i->first), - deps); + this->WritePhonyBuild(os, + "", + cmNinjaDeps(1, i->first), + deps); } } @@ -920,10 +920,10 @@ void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) cmNinjaDeps outputs; outputs.push_back("all"); - cmGlobalNinjaGenerator::WritePhonyBuild(os, - "The main all target.", - outputs, - this->AllDependencies); + this->WritePhonyBuild(os, + "The main all target.", + outputs, + this->AllDependencies); cmGlobalNinjaGenerator::WriteDefault(os, outputs, @@ -970,19 +970,19 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) implicitDeps.end()); implicitDeps.push_back("CMakeCache.txt"); - WriteBuild(os, - "Re-run CMake if any of its inputs changed.", - "RERUN_CMAKE", - /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE), - /*explicitDeps=*/ cmNinjaDeps(), - implicitDeps, - /*orderOnlyDeps=*/ cmNinjaDeps(), - /*variables=*/ cmNinjaVars()); - - WritePhonyBuild(os, - "A missing CMake input file is not an error.", - implicitDeps, - cmNinjaDeps()); + this->WriteBuild(os, + "Re-run CMake if any of its inputs changed.", + "RERUN_CMAKE", + /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE), + /*explicitDeps=*/ cmNinjaDeps(), + implicitDeps, + /*orderOnlyDeps=*/ cmNinjaDeps(), + /*variables=*/ cmNinjaVars()); + + this->WritePhonyBuild(os, + "A missing CMake input file is not an error.", + implicitDeps, + cmNinjaDeps()); } std::string cmGlobalNinjaGenerator::ninjaCmd() const diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 6e93788..a7c8100 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -77,27 +77,27 @@ public: * It also writes the variables bound to this build statement. * @warning no escaping of any kind is done here. */ - static void WriteBuild(std::ostream& os, - const std::string& comment, - const std::string& rule, - const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps, - const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables, - const std::string& rspfile = std::string(), - int cmdLineLimit = -1); + void WriteBuild(std::ostream& os, + const std::string& comment, + const std::string& rule, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables, + const std::string& rspfile = std::string(), + int cmdLineLimit = -1); /** * Helper to write a build statement with the special 'phony' rule. */ - static void WritePhonyBuild(std::ostream& os, - const std::string& comment, - const cmNinjaDeps& outputs, - const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps = cmNinjaDeps(), - const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), - const cmNinjaVars& variables = cmNinjaVars()); + void WritePhonyBuild(std::ostream& os, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), + const cmNinjaVars& variables = cmNinjaVars()); void WriteCustomCommandBuild(const std::string& command, const std::string& description, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 294a539..bdc3d80 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -340,14 +340,15 @@ cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( this->AppendCustomCommandLines(cc, cmdLines); if (cmdLines.empty()) { - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Phony custom command for " + - ninjaOutputs[0], - ninjaOutputs, - ninjaDeps, - cmNinjaDeps(), - orderOnlyDeps, - cmNinjaVars()); + this->GetGlobalNinjaGenerator()->WritePhonyBuild( + this->GetBuildFileStream(), + "Phony custom command for " + + ninjaOutputs[0], + ninjaOutputs, + ninjaDeps, + cmNinjaDeps(), + orderOnlyDeps, + cmNinjaVars()); } else { this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines), diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 6d352ed..921ca92 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -598,32 +598,37 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() #endif } + //Get the global generator as we are going to be call WriteBuild numerous + //times in the following section + cmGlobalNinjaGenerator* globalGenerator = this->GetGlobalGenerator(); + + const std::string rspfile = std::string (cmake::GetCMakeFilesDirectoryPostSlash()) + this->GetTarget()->GetName() + ".rsp"; // Write the build statement for this target. - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - comment.str(), - this->LanguageLinkerRule(), - outputs, - explicitDeps, - implicitDeps, - emptyDeps, - vars, - rspfile, - commandLineLengthLimit); + globalGenerator->WriteBuild(this->GetBuildFileStream(), + comment.str(), + this->LanguageLinkerRule(), + outputs, + explicitDeps, + implicitDeps, + emptyDeps, + vars, + rspfile, + commandLineLengthLimit); if (targetOutput != targetOutputReal) { if (targetType == cmTarget::EXECUTABLE) { - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + globalGenerator->WriteBuild(this->GetBuildFileStream(), "Create executable symlink " + targetOutput, - "CMAKE_SYMLINK_EXECUTABLE", - cmNinjaDeps(1, targetOutput), - cmNinjaDeps(1, targetOutputReal), - emptyDeps, - emptyDeps, - symlinkVars); + "CMAKE_SYMLINK_EXECUTABLE", + cmNinjaDeps(1, targetOutput), + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); } else { cmNinjaDeps symlinks; const std::string soName = this->GetTargetFilePath(this->TargetNameSO); @@ -635,30 +640,30 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinks.push_back(soName); } symlinks.push_back(targetOutput); - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - "Create library symlink " + targetOutput, - "CMAKE_SYMLINK_LIBRARY", - symlinks, - cmNinjaDeps(1, targetOutputReal), - emptyDeps, - emptyDeps, - symlinkVars); + globalGenerator->WriteBuild(this->GetBuildFileStream(), + "Create library symlink " + targetOutput, + "CMAKE_SYMLINK_LIBRARY", + symlinks, + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); } } if (!this->TargetNameImport.empty()) { // Since using multiple outputs would mess up the $out variable, use an // alias for the import library. - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Alias for import library.", - cmNinjaDeps(1, targetOutputImplib), - cmNinjaDeps(1, targetOutputReal)); + globalGenerator->WritePhonyBuild(this->GetBuildFileStream(), + "Alias for import library.", + cmNinjaDeps(1, targetOutputImplib), + cmNinjaDeps(1, targetOutputReal)); } // Add aliases for the file name and the target name. - this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut, + globalGenerator->AddTargetAlias(this->TargetNameOut, this->GetTarget()); - this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), + globalGenerator->AddTargetAlias(this->GetTargetName(), this->GetTarget()); } @@ -669,11 +674,11 @@ void cmNinjaNormalTargetGenerator::WriteObjectLibStatement() cmNinjaDeps outputs; this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs); cmNinjaDeps depends = this->GetObjects(); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Object library " - + this->GetTargetName(), - outputs, - depends); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Object library " + + this->GetTargetName(), + outputs, + depends); // Add aliases for the target name. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 43b7baa..56c1de8 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -642,24 +642,24 @@ cmNinjaTargetGenerator sourceFileName); } - cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), - comment, - rule, - outputs, - explicitDeps, - implicitDeps, - orderOnlyDeps, - vars); + this->GetGlobalGenerator()->WriteBuild(this->GetBuildFileStream(), + comment, + rule, + outputs, + explicitDeps, + implicitDeps, + orderOnlyDeps, + vars); if(const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { std::vector outputList; cmSystemTools::ExpandListArgument(objectOutputs, outputList); std::transform(outputList.begin(), outputList.end(), outputList.begin(), MapToNinjaPath()); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Additional output files.", - outputList, - outputs); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Additional output files.", + outputList, + outputs); } } diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx index 9c2fd13..755ce6e 100644 --- a/Source/cmNinjaUtilityTargetGenerator.cxx +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -61,11 +61,11 @@ void cmNinjaUtilityTargetGenerator::Generate() this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(), deps); if (commands.empty()) { - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "Utility command for " - + this->GetTargetName(), - outputs, - deps); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "Utility command for " + + this->GetTargetName(), + outputs, + deps); } else { std::string command = this->GetLocalGenerator()->BuildCommandLine(commands); @@ -105,10 +105,11 @@ void cmNinjaUtilityTargetGenerator::Generate() cmNinjaDeps(1, utilCommandName), deps); - cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), - "", - outputs, - cmNinjaDeps(1, utilCommandName)); + this->GetGlobalGenerator()->WritePhonyBuild(this->GetBuildFileStream(), + "", + outputs, + cmNinjaDeps(1, utilCommandName) + ); } this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), -- cgit v0.12 From 539356f1281902f5494828eca963d95e2b726dda Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Fri, 7 Jun 2013 14:26:03 -0400 Subject: Ninja: Custom Command file depends don't need to exist before building When converting custom commands for the ninja build system we need to make sure that any file dependencies that exist in the build tree are converted to phony targets. This tells ninja that these files might not exist when starting the build, but could be generated during the build. This is done by tracking all dependencies for custom command targets. After all have been written out we remove all items from the set that have been seen as a target, custom command output, an alias, or a file in the source directory. Anything that is left is considered to be a file that will be generated as a side effect of another custom command. --- Source/cmGlobalNinjaGenerator.cxx | 129 +++++++++++++++++++++++++++++++++++++- Source/cmGlobalNinjaGenerator.h | 7 +++ 2 files changed, 133 insertions(+), 3 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 8587e0d..9596ebc 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -10,11 +10,12 @@ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more information. ============================================================================*/ +#include "cmGeneratedFileStream.h" +#include "cmGeneratorExpressionEvaluationFile.h" +#include "cmGeneratorTarget.h" #include "cmGlobalNinjaGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" -#include "cmGeneratedFileStream.h" -#include "cmGeneratorTarget.h" #include "cmVersion.h" #include @@ -140,8 +141,15 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, for(cmNinjaDeps::const_iterator i = explicitDeps.begin(); i != explicitDeps.end(); ++i) + { arguments << " " << EncodeIdent(EncodePath(*i), os); + //we need to track every dependency that comes in, since we are trying + //to find dependencies that are side effects of build commands + // + this->CombinedBuildExplicitDependencies.insert(*i); + } + // Write implicit dependencies. if(!implicitDeps.empty()) { @@ -170,7 +178,10 @@ void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, build << "build"; for(cmNinjaDeps::const_iterator i = outputs.begin(); i != outputs.end(); ++i) + { build << " " << EncodeIdent(EncodePath(*i), os); + this->CombinedBuildOutputs.insert(*i); + } build << ":"; // Write the rule. @@ -478,6 +489,7 @@ void cmGlobalNinjaGenerator::Generate() this->WriteAssumedSourceDependencies(); this->WriteTargetAliases(*this->BuildFileStream); + this->WriteUnknownExplicitDependencies(*this->BuildFileStream); this->WriteBuiltinTargets(*this->BuildFileStream); if (cmSystemTools::GetErrorOccuredFlag()) { @@ -887,7 +899,7 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) cmGlobalNinjaGenerator::WriteDivider(os); os << "# Target aliases.\n\n"; - for (TargetAliasMap::iterator i = TargetAliases.begin(); + for (TargetAliasMap::const_iterator i = TargetAliases.begin(); i != TargetAliases.end(); ++i) { // Don't write ambiguous aliases. if (!i->second) @@ -903,6 +915,117 @@ void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) } } +void cmGlobalNinjaGenerator::WriteUnknownExplicitDependencies(std::ostream& os) +{ + //now write out the unknown explicit dependencies. + + //union the configured files, evaluations files and the CombinedBuildOutputs, + //and then difference with CombinedExplicitDependencies to find the explicit + //dependencies that we have no rule for + + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Unknown Build Time Dependencies.\n" + << "# Tell Ninja that they may appear as side effects of build rules\n" + << "# otherwise ordered by order-only dependencies.\n\n"; + + //get the list of files that cmake itself has generated as a + //product of configuration. + cmLocalNinjaGenerator *ng = + static_cast(this->LocalGenerators[0]); + + std::set knownDependencies; + for (std::vector::const_iterator i = + this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) + { + //get the vector of files created by this makefile and convert them + //to ninja paths, which are all relative in respect to the build directory + const std::vector& files = + (*i)->GetMakefile()->GetOutputFiles(); + typedef std::vector::const_iterator vect_it; + for(vect_it j = files.begin(); j != files.end(); ++j) + { + knownDependencies.insert(ng->ConvertToNinjaPath( j->c_str() )); + } + } + + for(std::vector::const_iterator + li = this->EvaluationFiles.begin(); + li != this->EvaluationFiles.end(); + ++li) + { + //get all the files created by generator expressions and convert them + //to ninja paths + std::vector files = (*li)->GetFiles(); + typedef std::vector::const_iterator vect_it; + for(vect_it j = files.begin(); j != files.end(); ++j) + { + knownDependencies.insert(ng->ConvertToNinjaPath( j->c_str() )); + } + } + + //insert outputs from all WirteBuild commands + for(std::set::iterator i = this->CombinedBuildOutputs.begin(); + i != this->CombinedBuildOutputs.end(); ++i) + { + knownDependencies.insert(*i); + } + + //after we have combined the data into knownDependencies we have no need + //to keep this data around + this->CombinedBuildOutputs.clear(); + + for(TargetAliasMap::const_iterator i= this->TargetAliases.begin(); + i != this->TargetAliases.end(); + ++i) + { + knownDependencies.insert(i->first); + } + + //remove all source files we know will exist. + typedef std::map >::const_iterator map_it; + for(map_it i = this->AssumedSourceDependencies.begin(); + i != this->AssumedSourceDependencies.end(); + ++i) + { + knownDependencies.insert(i->first); + } + + //now we difference with CombinedBuildExplicitDependencies to find + //the list of items we know nothing about + + std::vector unkownExplicitDepends; + this->CombinedBuildExplicitDependencies.erase("all"); + + std::set_difference(this->CombinedBuildExplicitDependencies.begin(), + this->CombinedBuildExplicitDependencies.end(), + knownDependencies.begin(), + knownDependencies.end(), + std::back_inserter(unkownExplicitDepends)); + + + std::string const rootBuildDirectory = + this->GetCMakeInstance()->GetHomeOutputDirectory(); + for (std::vector::const_iterator + i = unkownExplicitDepends.begin(); + i != unkownExplicitDepends.end(); + ++i) + { + //verify the file is in the build directory + std::string const absDepPath = cmSystemTools::CollapseFullPath( + i->c_str(), rootBuildDirectory.c_str()); + bool const inBuildDir = cmSystemTools::IsSubDirectory(absDepPath.c_str(), + rootBuildDirectory.c_str()); + if(inBuildDir) + { + cmNinjaDeps deps(1,*i); + this->WritePhonyBuild(os, + "", + deps, + deps); + } + } +} + void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) { // Write headers. diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index a7c8100..e046c7c 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -321,6 +321,7 @@ private: void WriteAssumedSourceDependencies(); void WriteTargetAliases(std::ostream& os); + void WriteUnknownExplicitDependencies(std::ostream& os); void WriteBuiltinTargets(std::ostream& os); void WriteTargetAll(std::ostream& os); @@ -358,6 +359,12 @@ private: /// The set of custom command outputs we have seen. std::set CustomCommandOutputs; + //The combined explicit dependencies of all build commands that the global + //generator has issued. When combined with CombinedBuildOutputs it allows + //us to detect the set of explicit dependencies that have + std::set CombinedBuildExplicitDependencies; + std::set CombinedBuildOutputs; + /// The mapping from source file to assumed dependencies. std::map > AssumedSourceDependencies; -- cgit v0.12