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`.
This commit is contained in:
parent
39ebfc79e6
commit
59aae29214
|
@ -29,6 +29,8 @@
|
||||||
#include "cmSystemTools.h"
|
#include "cmSystemTools.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
|
#include "cm_jsoncpp_writer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -106,6 +108,18 @@ bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
|
||||||
return lang == "Fortran";
|
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()
|
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
|
||||||
{
|
{
|
||||||
return "cmake_order_depends_target_" + this->GetTargetName();
|
return "cmake_order_depends_target_" + this->GetTargetName();
|
||||||
|
@ -277,6 +291,29 @@ std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
|
||||||
return path;
|
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 cmNinjaTargetGenerator::GetTargetOutputDir() const
|
||||||
{
|
{
|
||||||
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
|
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.
|
// For some cases we do an explicit preprocessor invocation.
|
||||||
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
|
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
|
||||||
|
bool const needDyndep = this->NeedDyndep(lang);
|
||||||
|
|
||||||
cmMakefile* mf = this->GetMakefile();
|
cmMakefile* mf = this->GetMakefile();
|
||||||
|
|
||||||
|
@ -424,6 +462,10 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
vars.Flags = flags.c_str();
|
vars.Flags = flags.c_str();
|
||||||
vars.DependencyFile = depfile.c_str();
|
vars.DependencyFile = depfile.c_str();
|
||||||
|
|
||||||
|
std::string const tdi = this->GetLocalGenerator()->ConvertToOutputFormat(
|
||||||
|
ConvertToNinjaPath(this->GetTargetDependInfoPath(lang)),
|
||||||
|
cmLocalGenerator::SHELL);
|
||||||
|
|
||||||
if (explicitPP) {
|
if (explicitPP) {
|
||||||
// Lookup the explicit preprocessing rule.
|
// Lookup the explicit preprocessing rule.
|
||||||
std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
|
std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
|
||||||
|
@ -431,7 +473,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
this->GetMakefile()->GetRequiredDefinition(ppVar);
|
this->GetMakefile()->GetRequiredDefinition(ppVar);
|
||||||
|
|
||||||
// Explicit preprocessing always uses a depfile.
|
// 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";
|
std::string const ppDepfile = "$DEP_FILE";
|
||||||
|
|
||||||
cmLocalGenerator::RuleVariables ppVars;
|
cmLocalGenerator::RuleVariables ppVars;
|
||||||
|
@ -467,6 +509,16 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
this->GetLocalGenerator()->ExpandRuleVariables(*i, ppVars);
|
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 =
|
std::string const ppCmdLine =
|
||||||
this->GetLocalGenerator()->BuildCommandLine(ppCmds);
|
this->GetLocalGenerator()->BuildCommandLine(ppCmds);
|
||||||
|
|
||||||
|
@ -484,6 +536,35 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
||||||
/*generator*/ false);
|
/*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.
|
// Rule for compiling object file.
|
||||||
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
|
const std::string cmdVar = std::string("CMAKE_") + lang + "_COMPILE_OBJECT";
|
||||||
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
|
std::string compileCmd = mf->GetRequiredDefinition(cmdVar);
|
||||||
|
@ -632,6 +713,25 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements()
|
||||||
this->WriteObjectBuildStatement(*si, !orderOnlyDeps.empty());
|
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";
|
this->GetBuildFileStream() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,6 +802,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||||
orderOnlyDeps);
|
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.
|
// For some cases we do an explicit preprocessor invocation.
|
||||||
bool const explicitPP = this->NeedExplicitPreprocessing(language);
|
bool const explicitPP = this->NeedExplicitPreprocessing(language);
|
||||||
if (explicitPP) {
|
if (explicitPP) {
|
||||||
|
@ -745,6 +848,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||||
// depends on the already-preprocessed source.
|
// depends on the already-preprocessed source.
|
||||||
vars.erase("DEP_FILE");
|
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(),
|
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
|
||||||
ppVars);
|
ppVars);
|
||||||
|
|
||||||
|
@ -752,6 +867,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
||||||
this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
|
this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
|
||||||
ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
|
ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
|
||||||
}
|
}
|
||||||
|
if (needDyndep) {
|
||||||
|
std::string const dyndep = this->GetDyndepFilePath(language);
|
||||||
|
orderOnlyDeps.push_back(dyndep);
|
||||||
|
vars["dyndep"] = dyndep;
|
||||||
|
}
|
||||||
|
|
||||||
EnsureParentDirectoryExists(objectFileName);
|
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(
|
void cmNinjaTargetGenerator::ExportObjectCompileCommand(
|
||||||
std::string const& language, std::string const& sourceFileName,
|
std::string const& language, std::string const& sourceFileName,
|
||||||
std::string const& objectDir, std::string const& objectFileName,
|
std::string const& objectDir, std::string const& objectFileName,
|
||||||
|
|
|
@ -72,6 +72,8 @@ protected:
|
||||||
std::string LanguageCompilerRule(const std::string& lang) const;
|
std::string LanguageCompilerRule(const std::string& lang) const;
|
||||||
std::string LanguagePreprocessRule(std::string const& lang) const;
|
std::string LanguagePreprocessRule(std::string const& lang) const;
|
||||||
bool NeedExplicitPreprocessing(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();
|
std::string OrderDependsTargetForTarget();
|
||||||
|
|
||||||
|
@ -112,6 +114,12 @@ protected:
|
||||||
/// @return the preprocessed source file path for the given @a source.
|
/// @return the preprocessed source file path for the given @a source.
|
||||||
std::string GetPreprocessedFilePath(cmSourceFile const* source) const;
|
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.
|
/// @return the file path where the target named @a name is generated.
|
||||||
std::string GetTargetFilePath(const std::string& name) const;
|
std::string GetTargetFilePath(const std::string& name) const;
|
||||||
|
|
||||||
|
@ -123,6 +131,7 @@ protected:
|
||||||
void WriteObjectBuildStatements();
|
void WriteObjectBuildStatements();
|
||||||
void WriteObjectBuildStatement(cmSourceFile const* source,
|
void WriteObjectBuildStatement(cmSourceFile const* source,
|
||||||
bool writeOrderDependsTargetForTarget);
|
bool writeOrderDependsTargetForTarget);
|
||||||
|
void WriteTargetDependInfo(std::string const& lang);
|
||||||
|
|
||||||
void ExportObjectCompileCommand(
|
void ExportObjectCompileCommand(
|
||||||
std::string const& language, std::string const& sourceFileName,
|
std::string const& language, std::string const& sourceFileName,
|
||||||
|
@ -166,6 +175,7 @@ private:
|
||||||
cmLocalNinjaGenerator* LocalGenerator;
|
cmLocalNinjaGenerator* LocalGenerator;
|
||||||
/// List of object files for this target.
|
/// List of object files for this target.
|
||||||
cmNinjaDeps Objects;
|
cmNinjaDeps Objects;
|
||||||
|
cmNinjaDeps DDIFiles; // TODO: Make per-language.
|
||||||
std::vector<cmCustomCommand const*> CustomCommands;
|
std::vector<cmCustomCommand const*> CustomCommands;
|
||||||
cmNinjaDeps ExtraFiles;
|
cmNinjaDeps ExtraFiles;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue