diff options
author | Brad King <brad.king@kitware.com> | 2013-07-01 13:15:09 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2013-07-01 13:15:09 (GMT) |
commit | 62428f5e72a9f3fbc0cb0d64b8215f8023386f65 (patch) | |
tree | 06ff7cbdb9a7809ef2cce1684adf418f0af95ec5 /Source | |
parent | 07095e1ea7a82d4d2c0b89931cc860539569c1e5 (diff) | |
parent | 539356f1281902f5494828eca963d95e2b726dda (diff) | |
download | CMake-62428f5e72a9f3fbc0cb0d64b8215f8023386f65.zip CMake-62428f5e72a9f3fbc0cb0d64b8215f8023386f65.tar.gz CMake-62428f5e72a9f3fbc0cb0d64b8215f8023386f65.tar.bz2 |
Merge topic 'ninja_phony_targets'
539356f Ninja: Custom Command file depends don't need to exist before building
874e171 Ninja: GlobalNinjaGenerator WriteBuild and WritePhonyBuild non static
88d27ad Add a test to expose a bug with add_custom_command and ninja.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 219 | ||||
-rw-r--r-- | Source/cmGlobalNinjaGenerator.h | 41 | ||||
-rw-r--r-- | Source/cmLocalNinjaGenerator.cxx | 17 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 77 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 24 | ||||
-rw-r--r-- | Source/cmNinjaUtilityTargetGenerator.cxx | 19 |
6 files changed, 267 insertions, 130 deletions
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index e2c0e18..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. @@ -208,14 +219,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 +262,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 +304,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, @@ -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) @@ -896,13 +908,124 @@ 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); } } +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. @@ -920,10 +1043,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 +1093,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..e046c7c 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, @@ -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<std::string> 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<std::string> CombinedBuildExplicitDependencies; + std::set<std::string> CombinedBuildOutputs; + /// The mapping from source file to assumed dependencies. std::map<std::string, std::set<std::string> > AssumedSourceDependencies; 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 3fce7cd..65173ca 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -612,24 +612,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<std::string> 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(), |