Browse Source

Ninja: Exclude NVHPC -Werror flags during Fortran preprocessing

The Ninja generator preprocesses Fortran separately in order to scan for
module dependencies.  NVHPC's `nvfortran` does not support its `-Werror`
flag while preprocessing with `-E`, so filter it out.

Fixes: #24665
Brad King 2 years ago
parent
commit
6b58cdd4cf
2 changed files with 24 additions and 2 deletions
  1. 1 0
      Modules/Compiler/NVHPC-Fortran.cmake
  2. 23 2
      Source/cmNinjaTargetGenerator.cxx

+ 1 - 0
Modules/Compiler/NVHPC-Fortran.cmake

@@ -1,3 +1,4 @@
 include(Compiler/PGI-Fortran)
 include(Compiler/NVHPC)
 __compiler_nvhpc(Fortran)
+set(CMAKE_Fortran_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX "(^| )-Werror +[a-z][a-z-]+( |$)")

+ 23 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -21,6 +21,8 @@
 #include <cm3p/json/value.h>
 #include <cm3p/json/writer.h>
 
+#include "cmsys/RegularExpression.hxx"
+
 #include "cmComputeLinkInformation.h"
 #include "cmCustomCommandGenerator.h"
 #include "cmDyndepCollation.h"
@@ -1259,6 +1261,7 @@ namespace {
 cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
                                    const std::string& ppFileName,
                                    bool compilePP, bool compilePPWithDefines,
+                                   cmValue ppExcludeFlagsRegex,
                                    cmNinjaBuild& objBuild, cmNinjaVars& vars,
                                    const std::string& objectFileName,
                                    cmLocalGenerator* lg)
@@ -1287,6 +1290,20 @@ cmNinjaBuild GetScanBuildStatement(const std::string& ruleName,
   // Scanning and compilation generally use the same flags.
   scanBuild.Variables["FLAGS"] = vars["FLAGS"];
 
+  // Exclude flags not valid during preprocessing.
+  if (compilePP && !ppExcludeFlagsRegex.IsEmpty()) {
+    std::string in = std::move(scanBuild.Variables["FLAGS"]);
+    std::string out;
+    cmsys::RegularExpression regex(*ppExcludeFlagsRegex);
+    std::string::size_type pos = 0;
+    while (regex.find(in.c_str() + pos)) {
+      out = cmStrCat(out, in.substr(pos, regex.start()), ' ');
+      pos += regex.end();
+    }
+    out = cmStrCat(out, in.substr(pos));
+    scanBuild.Variables["FLAGS"] = std::move(out);
+  }
+
   if (compilePP && !compilePPWithDefines) {
     // Move preprocessor definitions to the scan/preprocessor build statement.
     std::swap(scanBuild.Variables["DEFINES"], vars["DEFINES"]);
@@ -1511,18 +1528,22 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
 
     std::string scanRuleName;
     std::string ppFileName;
+    cmValue ppExcludeFlagsRegex;
     if (compilePP) {
       scanRuleName = this->LanguagePreprocessAndScanRule(language, config);
       ppFileName = this->ConvertToNinjaPath(
         this->GetPreprocessedFilePath(source, config));
+      ppExcludeFlagsRegex = this->Makefile->GetDefinition(cmStrCat(
+        "CMAKE_", language, "_PREPROCESS_SOURCE_EXCLUDE_FLAGS_REGEX"));
     } else {
       scanRuleName = this->LanguageScanRule(language, config);
       ppFileName = cmStrCat(objectFileName, ".ddi.i");
     }
 
     cmNinjaBuild ppBuild = GetScanBuildStatement(
-      scanRuleName, ppFileName, compilePP, compilePPWithDefines, objBuild,
-      vars, objectFileName, this->LocalGenerator);
+      scanRuleName, ppFileName, compilePP, compilePPWithDefines,
+      ppExcludeFlagsRegex, objBuild, vars, objectFileName,
+      this->LocalGenerator);
 
     if (compilePP) {
       // In case compilation requires flags that are incompatible with