diff options
author | Robert Maynard <robert.maynard@kitware.com> | 2013-06-07 18:26:03 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2013-07-01 13:01:01 (GMT) |
commit | 539356f1281902f5494828eca963d95e2b726dda (patch) | |
tree | f7271145dacaf817b96f518998c49bd8671da535 /Source/cmGlobalNinjaGenerator.cxx | |
parent | 874e17120db832656a77665e2ac13168aaf1e207 (diff) | |
download | CMake-539356f1281902f5494828eca963d95e2b726dda.zip CMake-539356f1281902f5494828eca963d95e2b726dda.tar.gz CMake-539356f1281902f5494828eca963d95e2b726dda.tar.bz2 |
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.
Diffstat (limited to 'Source/cmGlobalNinjaGenerator.cxx')
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 129 |
1 files changed, 126 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 <algorithm> @@ -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<cmLocalNinjaGenerator *>(this->LocalGenerators[0]); + + std::set<std::string> knownDependencies; + for (std::vector<cmLocalGenerator *>::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<std::string>& files = + (*i)->GetMakefile()->GetOutputFiles(); + typedef std::vector<std::string>::const_iterator vect_it; + for(vect_it j = files.begin(); j != files.end(); ++j) + { + knownDependencies.insert(ng->ConvertToNinjaPath( j->c_str() )); + } + } + + for(std::vector<cmGeneratorExpressionEvaluationFile*>::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<std::string> files = (*li)->GetFiles(); + typedef std::vector<std::string>::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<std::string>::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<std::string, std::set<std::string> >::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<std::string> 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<std::string>::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. |