mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-15 20:46:37 +08:00
Ninja: Add helper functions to generate Fortran preprocess rule
This commit is contained in:
@@ -509,6 +509,91 @@ void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language,
|
|||||||
this->WriteCompileRule(language, config);
|
this->WriteCompileRule(language, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Create the command to run the dependency scanner
|
||||||
|
std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi,
|
||||||
|
const std::string& lang, const std::string& ppFile,
|
||||||
|
bool needDyndep, const std::string& ddiFile)
|
||||||
|
{
|
||||||
|
std::string ccmd =
|
||||||
|
cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang,
|
||||||
|
" --pp=", ppFile, " --dep=$DEP_FILE");
|
||||||
|
if (needDyndep) {
|
||||||
|
ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile);
|
||||||
|
}
|
||||||
|
return ccmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create dependency scanning rule, with optional
|
||||||
|
// explicit preprocessing step if preprocessCommand is non-empty
|
||||||
|
cmNinjaRule GetPreprocessScanRule(
|
||||||
|
const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars,
|
||||||
|
const std::string& responseFlag, const std::string& flags,
|
||||||
|
const std::string& launcher,
|
||||||
|
cmRulePlaceholderExpander* const rulePlaceholderExpander,
|
||||||
|
std::string scanCommand, cmLocalNinjaGenerator* generator,
|
||||||
|
const std::string& preprocessCommand = "")
|
||||||
|
{
|
||||||
|
cmNinjaRule rule(ruleName);
|
||||||
|
// Explicit preprocessing always uses a depfile.
|
||||||
|
rule.DepType = ""; // no deps= for multiple outputs
|
||||||
|
rule.DepFile = "$DEP_FILE";
|
||||||
|
|
||||||
|
cmRulePlaceholderExpander::RuleVariables ppVars;
|
||||||
|
ppVars.CMTargetName = vars.CMTargetName;
|
||||||
|
ppVars.CMTargetType = vars.CMTargetType;
|
||||||
|
ppVars.Language = vars.Language;
|
||||||
|
ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
|
||||||
|
ppVars.PreprocessedSource = "$out";
|
||||||
|
ppVars.DependencyFile = rule.DepFile.c_str();
|
||||||
|
|
||||||
|
// Preprocessing uses the original source, compilation uses
|
||||||
|
// preprocessed output or original source
|
||||||
|
ppVars.Source = vars.Source;
|
||||||
|
vars.Source = "$in";
|
||||||
|
|
||||||
|
// Copy preprocessor definitions to the preprocessor rule.
|
||||||
|
ppVars.Defines = vars.Defines;
|
||||||
|
|
||||||
|
// Copy include directories to the preprocessor rule. The Fortran
|
||||||
|
// compilation rule still needs them for the INCLUDE directive.
|
||||||
|
ppVars.Includes = vars.Includes;
|
||||||
|
|
||||||
|
// Preprocessing and compilation use the same flags.
|
||||||
|
std::string ppFlags = flags;
|
||||||
|
|
||||||
|
// If using a response file, move defines, includes, and flags into it.
|
||||||
|
if (!responseFlag.empty()) {
|
||||||
|
rule.RspFile = "$RSP_FILE";
|
||||||
|
rule.RspContent =
|
||||||
|
cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
|
||||||
|
ppFlags = cmStrCat(responseFlag, rule.RspFile);
|
||||||
|
ppVars.Defines = "";
|
||||||
|
ppVars.Includes = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
ppVars.Flags = ppFlags.c_str();
|
||||||
|
|
||||||
|
// Rule for preprocessing source file.
|
||||||
|
std::vector<std::string> ppCmds;
|
||||||
|
|
||||||
|
if (!preprocessCommand.empty()) {
|
||||||
|
// Lookup the explicit preprocessing rule.
|
||||||
|
cmExpandList(preprocessCommand, ppCmds);
|
||||||
|
for (std::string& i : ppCmds) {
|
||||||
|
i = cmStrCat(launcher, i);
|
||||||
|
rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run CMake dependency scanner on either preprocessed output or source file
|
||||||
|
ppCmds.emplace_back(std::move(scanCommand));
|
||||||
|
rule.Command = generator->BuildCommandLine(ppCmds);
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
||||||
const std::string& config)
|
const std::string& config)
|
||||||
{
|
{
|
||||||
@@ -566,82 +651,26 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
|
|||||||
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
|
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
|
||||||
|
|
||||||
if (explicitPP) {
|
if (explicitPP) {
|
||||||
cmNinjaRule rule(this->LanguagePreprocessRule(lang, config));
|
// Combined preprocessing and dependency scanning
|
||||||
// Explicit preprocessing always uses a depfile.
|
const auto ppScanCommand = GetScanCommand(
|
||||||
rule.DepType = ""; // no deps= for multiple outputs
|
cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE");
|
||||||
rule.DepFile = "$DEP_FILE";
|
const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
|
||||||
|
|
||||||
cmRulePlaceholderExpander::RuleVariables ppVars;
|
auto ppRule = GetPreprocessScanRule(
|
||||||
ppVars.CMTargetName = vars.CMTargetName;
|
this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags,
|
||||||
ppVars.CMTargetType = vars.CMTargetType;
|
launcher, rulePlaceholderExpander.get(), ppScanCommand,
|
||||||
ppVars.Language = vars.Language;
|
this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar));
|
||||||
ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
|
|
||||||
ppVars.PreprocessedSource = "$out";
|
|
||||||
ppVars.DependencyFile = rule.DepFile.c_str();
|
|
||||||
|
|
||||||
// Preprocessing uses the original source,
|
|
||||||
// compilation uses preprocessed output.
|
|
||||||
ppVars.Source = vars.Source;
|
|
||||||
vars.Source = "$in";
|
|
||||||
|
|
||||||
// Preprocessing and compilation use the same flags.
|
|
||||||
std::string ppFlags = flags;
|
|
||||||
|
|
||||||
if (!compilePPWithDefines) {
|
|
||||||
// Move preprocessor definitions to the preprocessor rule.
|
|
||||||
ppVars.Defines = vars.Defines;
|
|
||||||
vars.Defines = "";
|
|
||||||
} else {
|
|
||||||
// Copy preprocessor definitions to the preprocessor rule.
|
|
||||||
ppVars.Defines = vars.Defines;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy include directories to the preprocessor rule. The Fortran
|
|
||||||
// compilation rule still needs them for the INCLUDE directive.
|
|
||||||
ppVars.Includes = vars.Includes;
|
|
||||||
|
|
||||||
// If using a response file, move defines, includes, and flags into it.
|
|
||||||
if (!responseFlag.empty()) {
|
|
||||||
rule.RspFile = "$RSP_FILE";
|
|
||||||
rule.RspContent =
|
|
||||||
cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
|
|
||||||
ppFlags = cmStrCat(responseFlag, rule.RspFile);
|
|
||||||
ppVars.Defines = "";
|
|
||||||
ppVars.Includes = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
ppVars.Flags = ppFlags.c_str();
|
|
||||||
|
|
||||||
// Rule for preprocessing source file.
|
|
||||||
std::vector<std::string> ppCmds;
|
|
||||||
{
|
|
||||||
// Lookup the explicit preprocessing rule.
|
|
||||||
std::string ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
|
|
||||||
cmExpandList(this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::string& i : ppCmds) {
|
|
||||||
i = cmStrCat(launcher, i);
|
|
||||||
rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
|
|
||||||
i, ppVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run CMake dependency scanner on preprocessed output.
|
|
||||||
{
|
|
||||||
std::string ccmd =
|
|
||||||
cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
|
|
||||||
" --lang=", lang, " --pp=$out --dep=$DEP_FILE");
|
|
||||||
if (needDyndep) {
|
|
||||||
ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
|
|
||||||
}
|
|
||||||
ppCmds.emplace_back(std::move(ccmd));
|
|
||||||
}
|
|
||||||
rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
|
|
||||||
|
|
||||||
// Write the rule for preprocessing file of the given language.
|
// Write the rule for preprocessing file of the given language.
|
||||||
rule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
|
ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
|
||||||
rule.Description = cmStrCat("Building ", lang, " preprocessed $out");
|
ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
|
||||||
this->GetGlobalGenerator()->AddRule(rule);
|
|
||||||
|
this->GetGlobalGenerator()->AddRule(ppRule);
|
||||||
|
|
||||||
|
if (!compilePPWithDefines) {
|
||||||
|
// Remove preprocessor definitions from compilation step
|
||||||
|
vars.Defines = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needDyndep) {
|
if (needDyndep) {
|
||||||
|
Reference in New Issue
Block a user