summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2016-09-22 14:34:45 (GMT)
committerBrad King <brad.king@kitware.com>2016-09-22 17:53:10 (GMT)
commit59aae29214b727944978b8e545a552f96c88b883 (patch)
treeebfe620e3030e712a4839e4653516b3a74dee156
parent39ebfc79e614dc395d5ace2ad5818b3ba75ca478 (diff)
downloadCMake-59aae29214b727944978b8e545a552f96c88b883.zip
CMake-59aae29214b727944978b8e545a552f96c88b883.tar.gz
CMake-59aae29214b727944978b8e545a552f96c88b883.tar.bz2
Ninja: Add dyndep rules for Fortran module dependencies
Teach the Ninja generator to add dyndep rules and bindings as described in the design comment in `Source/cmGlobalNinjaGenerator.cxx`.
-rw-r--r--Source/cmNinjaTargetGenerator.cxx165
-rw-r--r--Source/cmNinjaTargetGenerator.h10
2 files changed, 174 insertions, 1 deletions
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index 76bae6b..b418ce3 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -29,6 +29,8 @@
#include "cmSystemTools.h"
#include "cmake.h"
+#include "cm_jsoncpp_writer.h"
+
#include <algorithm>
#include <iterator>
#include <map>
@@ -106,6 +108,18 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
return lang == "Fortran";
}
+std::string cmNinjaTargetGenerator::LanguageDyndepRule(
+ const std::string& lang) const
+{
+ return lang + "_DYNDEP__" +
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
+}
+
+bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang) const
+{
+ return lang == "Fortran";
+}
+
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
{
return "cmake_order_depends_target_" + this->GetTargetName();
@@ -277,6 +291,29 @@ std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
return path;
}
+std::string cmNinjaTargetGenerator::GetDyndepFilePath(
+ std::string const& lang) const
+{
+ std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
+ if (!path.empty())
+ path += "/";
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/";
+ path += lang;
+ path += ".dd";
+ return path;
+}
+
+std::string cmNinjaTargetGenerator::GetTargetDependInfoPath(
+ std::string const& lang) const
+{
+ std::string path = this->Makefile->GetCurrentBinaryDirectory();
+ path += "/";
+ path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+ path += "/" + lang + "DependInfo.json";
+ return path;
+}
+
std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
{
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
@@ -361,6 +398,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
+ bool const needDyndep = this->NeedDyndep(lang);
cmMakefile* mf = this->GetMakefile();
@@ -424,6 +462,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
vars.Flags = flags.c_str();
vars.DependencyFile = depfile.c_str();
+ std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
+ ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
+ cmLocalGenerator::SHELL);
+
if (explicitPP) {
// Lookup the explicit preprocessing rule.
std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
@@ -431,7 +473,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
this->GetMakefile()->GetRequiredDefinition(ppVar);
// Explicit preprocessing always uses a depfile.
- std::string const ppDeptype = "gcc";
+ std::string const ppDeptype = ""; // no deps= for multiple outputs
std::string const ppDepfile = "$DEP_FILE";
cmLocalGenerator::RuleVariables ppVars;
@@ -467,6 +509,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
this->GetLocalGenerator()->ExpandRuleVariables(*i, ppVars);
}
+ // Run CMake dependency scanner on preprocessed output.
+ std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ ppCmds.push_back(
+ cmake + " -E cmake_ninja_depends"
+ " --tdi=" +
+ tdi + " --pp=$out"
+ " --dep=$DEP_FILE" +
+ (needDyndep ? " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE" : ""));
+
std::string const ppCmdLine =
this->GetLocalGenerator()->BuildCommandLine(ppCmds);
@@ -484,6 +536,35 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
/*generator*/ false);
}
+ if (needDyndep) {
+ // Write the rule for ninja dyndep file generation.
+ std::vector<std::string> ddCmds;
+
+ // Run CMake dependency scanner on preprocessed output.
+ std::string const cmake = this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
+ ddCmds.push_back(cmake + " -E cmake_ninja_dyndep"
+ " --tdi=" +
+ tdi + " --dd=$out"
+ " $in");
+
+ std::string const ddCmdLine =
+ this->GetLocalGenerator()->BuildCommandLine(ddCmds);
+
+ std::ostringstream ddComment;
+ ddComment << "Rule to generate ninja dyndep files for " << lang << ".";
+ std::ostringstream ddDesc;
+ ddDesc << "Generating " << lang << " dyndep file $out";
+ this->GetGlobalGenerator()->AddRule(
+ this->LanguageDyndepRule(lang), ddCmdLine, ddDesc.str(), ddComment.str(),
+ /*depfile*/ "",
+ /*deps*/ "",
+ /*rspfile*/ "",
+ /*rspcontent*/ "",
+ /*restat*/ "",
+ /*generator*/ false);
+ }
+
// Rule for compiling object file.
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
@@ -632,6 +713,25 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
}
+ if (!this->DDIFiles.empty()) {
+ std::string const ddComment;
+ std::string const ddRule = this->LanguageDyndepRule("Fortran");
+ cmNinjaDeps ddOutputs;
+ cmNinjaDeps ddImplicitOuts;
+ cmNinjaDeps const& ddExplicitDeps = this->DDIFiles;
+ cmNinjaDeps ddImplicitDeps;
+ cmNinjaDeps ddOrderOnlyDeps;
+ cmNinjaVars ddVars;
+
+ this->WriteTargetDependInfo("Fortran");
+
+ ddOutputs.push_back(this->GetDyndepFilePath("Fortran"));
+
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetBuildFileStream(), ddComment, ddRule, ddOutputs, ddImplicitOuts,
+ ddExplicitDeps, ddImplicitDeps, ddOrderOnlyDeps, ddVars);
+ }
+
this->GetBuildFileStream() << "\n";
}
@@ -702,6 +802,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
orderOnlyDeps);
}
+ // For some cases we need to generate a ninja dyndep file.
+ bool const needDyndep = this->NeedDyndep(language);
+
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(language);
if (explicitPP) {
@@ -745,6 +848,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
// depends on the already-preprocessed source.
vars.erase("DEP_FILE");
+ if (needDyndep) {
+ // Tell dependency scanner the object file that will result from
+ // compiling the preprocessed source.
+ ppVars["OBJ_FILE"] = objectFileName;
+
+ // Tell dependency scanner where to store dyndep intermediate results.
+ std::string const ddiFile = ppFileName + ".ddi";
+ ppVars["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+ ppImplicitOuts.push_back(ddiFile);
+ this->DDIFiles.push_back(ddiFile);
+ }
+
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
ppVars);
@@ -752,6 +867,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
}
+ if (needDyndep) {
+ std::string const dyndep = this->GetDyndepFilePath(language);
+ orderOnlyDeps.push_back(dyndep);
+ vars["dyndep"] = dyndep;
+ }
EnsureParentDirectoryExists(objectFileName);
@@ -786,6 +906,49 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
}
+void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang)
+{
+ Json::Value tdi(Json::objectValue);
+ tdi["language"] = lang;
+ tdi["compiler-id"] =
+ this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID");
+
+ if (lang == "Fortran") {
+ std::string mod_dir = this->GeneratorTarget->GetFortranModuleDirectory(
+ this->Makefile->GetHomeOutputDirectory());
+ if (mod_dir.empty()) {
+ mod_dir = this->Makefile->GetCurrentBinaryDirectory();
+ }
+ tdi["module-dir"] = mod_dir;
+ }
+
+ tdi["dir-cur-bld"] = this->Makefile->GetCurrentBinaryDirectory();
+ tdi["dir-cur-src"] = this->Makefile->GetCurrentSourceDirectory();
+ tdi["dir-top-bld"] = this->Makefile->GetHomeOutputDirectory();
+ tdi["dir-top-src"] = this->Makefile->GetHomeDirectory();
+
+ Json::Value& tdi_include_dirs = tdi["include-dirs"] = Json::arrayValue;
+ std::vector<std::string> includes;
+ this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
+ lang, this->GetConfigName());
+ for (std::vector<std::string>::iterator i = includes.begin();
+ i != includes.end(); ++i) {
+ tdi_include_dirs.append(*i);
+ }
+
+ Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] =
+ Json::arrayValue;
+ std::vector<std::string> linked = this->GetLinkedTargetDirectories();
+ for (std::vector<std::string>::iterator i = linked.begin();
+ i != linked.end(); ++i) {
+ tdi_linked_target_dirs.append(*i);
+ }
+
+ std::string const tdin = this->GetTargetDependInfoPath(lang);
+ cmGeneratedFileStream tdif(tdin.c_str());
+ tdif << tdi;
+}
+
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
std::string const& objectDir, std::string const& objectFileName,
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index e6816db..f5e6511 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -72,6 +72,8 @@ protected:
std::string LanguageCompilerRule(const std::string& lang) const;
std::string LanguagePreprocessRule(std::string const& lang) const;
bool NeedExplicitPreprocessing(std::string const& lang) const;
+ std::string LanguageDyndepRule(std::string const& lang) const;
+ bool NeedDyndep(std::string const& lang) const;
std::string OrderDependsTargetForTarget();
@@ -112,6 +114,12 @@ protected:
/// @return the preprocessed source file path for the given @a source.
std::string GetPreprocessedFilePath(cmSourceFile const* source) const;
+ /// @return the dyndep file path for this target.
+ std::string GetDyndepFilePath(std::string const& lang) const;
+
+ /// @return the target dependency scanner info file path
+ std::string GetTargetDependInfoPath(std::string const& lang) const;
+
/// @return the file path where the target named @a name is generated.
std::string GetTargetFilePath(const std::string& name) const;
@@ -123,6 +131,7 @@ protected:
void WriteObjectBuildStatements();
void WriteObjectBuildStatement(cmSourceFile const* source,
bool writeOrderDependsTargetForTarget);
+ void WriteTargetDependInfo(std::string const& lang);
void ExportObjectCompileCommand(
std::string const& language, std::string const& sourceFileName,
@@ -166,6 +175,7 @@ private:
cmLocalNinjaGenerator* LocalGenerator;
/// List of object files for this target.
cmNinjaDeps Objects;
+ cmNinjaDeps DDIFiles; // TODO: Make per-language.
std::vector<cmCustomCommand const*> CustomCommands;
cmNinjaDeps ExtraFiles;
};