|
|
|
|
@@ -93,6 +93,19 @@ std::string cmNinjaTargetGenerator::LanguageCompilerRule(
|
|
|
|
|
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
|
|
|
|
|
std::string const& lang) const
|
|
|
|
|
{
|
|
|
|
|
return lang + "_PREPROCESS__" +
|
|
|
|
|
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool cmNinjaTargetGenerator::NeedExplicitPreprocessing(
|
|
|
|
|
std::string const& lang) const
|
|
|
|
|
{
|
|
|
|
|
return lang == "Fortran";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget()
|
|
|
|
|
{
|
|
|
|
|
return "cmake_order_depends_target_" + this->GetTargetName();
|
|
|
|
|
@@ -229,6 +242,41 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath(
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string cmNinjaTargetGenerator::GetPreprocessedFilePath(
|
|
|
|
|
cmSourceFile const* source) const
|
|
|
|
|
{
|
|
|
|
|
// Choose an extension to compile already-preprocessed source.
|
|
|
|
|
std::string ppExt = source->GetExtension();
|
|
|
|
|
if (cmHasLiteralPrefix(ppExt, "F")) {
|
|
|
|
|
// Some Fortran compilers automatically enable preprocessing for
|
|
|
|
|
// upper-case extensions. Since the source is already preprocessed,
|
|
|
|
|
// use a lower-case extension.
|
|
|
|
|
ppExt = cmSystemTools::LowerCase(ppExt);
|
|
|
|
|
}
|
|
|
|
|
if (ppExt == "fpp") {
|
|
|
|
|
// Some Fortran compilers automatically enable preprocessing for
|
|
|
|
|
// the ".fpp" extension. Since the source is already preprocessed,
|
|
|
|
|
// use the ".f" extension.
|
|
|
|
|
ppExt = "f";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Take the object file name and replace the extension.
|
|
|
|
|
std::string const& objName = this->GeneratorTarget->GetObjectName(source);
|
|
|
|
|
std::string const& objExt =
|
|
|
|
|
this->GetGlobalGenerator()->GetLanguageOutputExtension(*source);
|
|
|
|
|
assert(objName.size() >= objExt.size());
|
|
|
|
|
std::string const ppName =
|
|
|
|
|
objName.substr(0, objName.size() - objExt.size()) + "-pp." + ppExt;
|
|
|
|
|
|
|
|
|
|
std::string path = this->LocalGenerator->GetHomeRelativeOutputPath();
|
|
|
|
|
if (!path.empty())
|
|
|
|
|
path += "/";
|
|
|
|
|
path += this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
|
|
|
|
|
path += "/";
|
|
|
|
|
path += ppName;
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string cmNinjaTargetGenerator::GetTargetOutputDir() const
|
|
|
|
|
{
|
|
|
|
|
std::string dir = this->GeneratorTarget->GetDirectory(this->GetConfigName());
|
|
|
|
|
@@ -311,6 +359,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
|
|
|
|
vars.ObjectDir = "$OBJECT_DIR";
|
|
|
|
|
vars.ObjectFileDir = "$OBJECT_FILE_DIR";
|
|
|
|
|
|
|
|
|
|
// For some cases we do an explicit preprocessor invocation.
|
|
|
|
|
bool const explicitPP = this->NeedExplicitPreprocessing(lang);
|
|
|
|
|
|
|
|
|
|
cmMakefile* mf = this->GetMakefile();
|
|
|
|
|
|
|
|
|
|
std::string flags = "$FLAGS";
|
|
|
|
|
@@ -331,7 +382,9 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
|
|
|
|
std::string deptype;
|
|
|
|
|
std::string depfile;
|
|
|
|
|
std::string cldeps;
|
|
|
|
|
if (this->NeedDepTypeMSVC(lang)) {
|
|
|
|
|
if (explicitPP) {
|
|
|
|
|
// The explicit preprocessing step will handle dependency scanning.
|
|
|
|
|
} else if (this->NeedDepTypeMSVC(lang)) {
|
|
|
|
|
deptype = "msvc";
|
|
|
|
|
depfile = "";
|
|
|
|
|
flags += " /showIncludes";
|
|
|
|
|
@@ -371,6 +424,66 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang)
|
|
|
|
|
vars.Flags = flags.c_str();
|
|
|
|
|
vars.DependencyFile = depfile.c_str();
|
|
|
|
|
|
|
|
|
|
if (explicitPP) {
|
|
|
|
|
// Lookup the explicit preprocessing rule.
|
|
|
|
|
std::string const ppVar = "CMAKE_" + lang + "_PREPROCESS_SOURCE";
|
|
|
|
|
std::string const ppCmd =
|
|
|
|
|
this->GetMakefile()->GetRequiredDefinition(ppVar);
|
|
|
|
|
|
|
|
|
|
// Explicit preprocessing always uses a depfile.
|
|
|
|
|
std::string const ppDeptype = "gcc";
|
|
|
|
|
std::string const ppDepfile = "$DEP_FILE";
|
|
|
|
|
|
|
|
|
|
cmLocalGenerator::RuleVariables ppVars;
|
|
|
|
|
ppVars.RuleLauncher = vars.RuleLauncher;
|
|
|
|
|
ppVars.CMTarget = vars.CMTarget;
|
|
|
|
|
ppVars.Language = vars.Language;
|
|
|
|
|
ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
|
|
|
|
|
ppVars.PreprocessedSource = "$out";
|
|
|
|
|
ppVars.DependencyFile = ppDepfile.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.
|
|
|
|
|
ppVars.Flags = vars.Flags;
|
|
|
|
|
|
|
|
|
|
// Move preprocessor definitions to the preprocessor rule.
|
|
|
|
|
ppVars.Defines = vars.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;
|
|
|
|
|
|
|
|
|
|
// Rule for preprocessing source file.
|
|
|
|
|
std::vector<std::string> ppCmds;
|
|
|
|
|
cmSystemTools::ExpandListArgument(ppCmd, ppCmds);
|
|
|
|
|
|
|
|
|
|
for (std::vector<std::string>::iterator i = ppCmds.begin();
|
|
|
|
|
i != ppCmds.end(); ++i) {
|
|
|
|
|
this->GetLocalGenerator()->ExpandRuleVariables(*i, ppVars);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string const ppCmdLine =
|
|
|
|
|
this->GetLocalGenerator()->BuildCommandLine(ppCmds);
|
|
|
|
|
|
|
|
|
|
// Write the rule for preprocessing file of the given language.
|
|
|
|
|
std::ostringstream ppComment;
|
|
|
|
|
ppComment << "Rule for preprocessing " << lang << " files.";
|
|
|
|
|
std::ostringstream ppDesc;
|
|
|
|
|
ppDesc << "Building " << lang << " preprocessed $out";
|
|
|
|
|
this->GetGlobalGenerator()->AddRule(this->LanguagePreprocessRule(lang),
|
|
|
|
|
ppCmdLine, ppDesc.str(),
|
|
|
|
|
ppComment.str(), ppDepfile, ppDeptype,
|
|
|
|
|
/*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);
|
|
|
|
|
@@ -589,6 +702,57 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
|
|
|
|
|
orderOnlyDeps);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For some cases we do an explicit preprocessor invocation.
|
|
|
|
|
bool const explicitPP = this->NeedExplicitPreprocessing(language);
|
|
|
|
|
if (explicitPP) {
|
|
|
|
|
std::string const ppComment;
|
|
|
|
|
std::string const ppRule = this->LanguagePreprocessRule(language);
|
|
|
|
|
cmNinjaDeps ppOutputs;
|
|
|
|
|
cmNinjaDeps ppImplicitOuts;
|
|
|
|
|
cmNinjaDeps ppExplicitDeps;
|
|
|
|
|
cmNinjaDeps ppImplicitDeps;
|
|
|
|
|
cmNinjaDeps ppOrderOnlyDeps;
|
|
|
|
|
cmNinjaVars ppVars;
|
|
|
|
|
|
|
|
|
|
std::string const ppFileName =
|
|
|
|
|
this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source));
|
|
|
|
|
ppOutputs.push_back(ppFileName);
|
|
|
|
|
|
|
|
|
|
// Move compilation dependencies to the preprocessing build statement.
|
|
|
|
|
std::swap(ppExplicitDeps, explicitDeps);
|
|
|
|
|
std::swap(ppImplicitDeps, implicitDeps);
|
|
|
|
|
std::swap(ppOrderOnlyDeps, orderOnlyDeps);
|
|
|
|
|
std::swap(ppVars["IN_ABS"], vars["IN_ABS"]);
|
|
|
|
|
|
|
|
|
|
// The actual compilation will now use the preprocessed source.
|
|
|
|
|
explicitDeps.push_back(ppFileName);
|
|
|
|
|
|
|
|
|
|
// Preprocessing and compilation use the same flags.
|
|
|
|
|
ppVars["FLAGS"] = vars["FLAGS"];
|
|
|
|
|
|
|
|
|
|
// Move preprocessor definitions to the preprocessor build statement.
|
|
|
|
|
std::swap(ppVars["DEFINES"], vars["DEFINES"]);
|
|
|
|
|
|
|
|
|
|
// Copy include directories to the preprocessor build statement. The
|
|
|
|
|
// Fortran compilation build statement still needs them for the INCLUDE
|
|
|
|
|
// directive.
|
|
|
|
|
ppVars["INCLUDES"] = vars["INCLUDES"];
|
|
|
|
|
|
|
|
|
|
// Explicit preprocessing always uses a depfile.
|
|
|
|
|
ppVars["DEP_FILE"] =
|
|
|
|
|
cmGlobalNinjaGenerator::EncodeDepfileSpace(ppFileName + ".d");
|
|
|
|
|
// The actual compilation does not need a depfile because it
|
|
|
|
|
// depends on the already-preprocessed source.
|
|
|
|
|
vars.erase("DEP_FILE");
|
|
|
|
|
|
|
|
|
|
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
|
|
|
|
|
ppVars);
|
|
|
|
|
|
|
|
|
|
this->GetGlobalGenerator()->WriteBuild(
|
|
|
|
|
this->GetBuildFileStream(), ppComment, ppRule, ppOutputs, ppImplicitOuts,
|
|
|
|
|
ppExplicitDeps, ppImplicitDeps, ppOrderOnlyDeps, ppVars);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EnsureParentDirectoryExists(objectFileName);
|
|
|
|
|
|
|
|
|
|
vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
|
|
|
|
|
|