summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/Compiler/GNU-Fortran.cmake3
-rw-r--r--Modules/Compiler/Intel-Fortran.cmake3
-rw-r--r--Modules/Compiler/SunPro-Fortran.cmake3
-rw-r--r--Source/cmNinjaTargetGenerator.cxx166
-rw-r--r--Source/cmNinjaTargetGenerator.h5
5 files changed, 179 insertions, 1 deletions
diff --git a/Modules/Compiler/GNU-Fortran.cmake b/Modules/Compiler/GNU-Fortran.cmake
index fc848ac..94dc275 100644
--- a/Modules/Compiler/GNU-Fortran.cmake
+++ b/Modules/Compiler/GNU-Fortran.cmake
@@ -1,6 +1,9 @@
include(Compiler/GNU)
__compiler_gnu(Fortran)
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -cpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> -o <PREPROCESSED_SOURCE>")
+
set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-ffixed-form")
set(CMAKE_Fortran_FORMAT_FREE_FLAG "-ffree-form")
diff --git a/Modules/Compiler/Intel-Fortran.cmake b/Modules/Compiler/Intel-Fortran.cmake
index ef7aa3a..a132055 100644
--- a/Modules/Compiler/Intel-Fortran.cmake
+++ b/Modules/Compiler/Intel-Fortran.cmake
@@ -7,3 +7,6 @@ set(CMAKE_Fortran_FORMAT_FREE_FLAG "-free")
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
+
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> -fpp <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
diff --git a/Modules/Compiler/SunPro-Fortran.cmake b/Modules/Compiler/SunPro-Fortran.cmake
index a0e07d4..6607926 100644
--- a/Modules/Compiler/SunPro-Fortran.cmake
+++ b/Modules/Compiler/SunPro-Fortran.cmake
@@ -18,5 +18,8 @@ string(APPEND CMAKE_Fortran_FLAGS_RELWITHDEBINFO_INIT " -g -xO2 -DNDEBUG")
set(CMAKE_Fortran_MODDIR_FLAG "-moddir=")
set(CMAKE_Fortran_MODPATH_FLAG "-M")
+set(CMAKE_Fortran_PREPROCESS_SOURCE
+ "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F <SOURCE> -o <PREPROCESSED_SOURCE>")
+
set(CMAKE_Fortran_CREATE_PREPROCESSED_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -F <SOURCE> -o <PREPROCESSED_SOURCE>")
set(CMAKE_Fortran_CREATE_ASSEMBLY_SOURCE "<CMAKE_Fortran_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index fb09bfe..76bae6b 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -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(
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 2b26788..e6816db 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -70,6 +70,8 @@ protected:
cmMakefile* GetMakefile() const { return this->Makefile; }
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 OrderDependsTargetForTarget();
@@ -107,6 +109,9 @@ protected:
/// @return the object file path for the given @a source.
std::string GetObjectFilePath(cmSourceFile const* source) const;
+ /// @return the preprocessed source file path for the given @a source.
+ std::string GetPreprocessedFilePath(cmSourceFile const* source) const;
+
/// @return the file path where the target named @a name is generated.
std::string GetTargetFilePath(const std::string& name) const;