Merge topic 'llvm-rc-CMAKE_RC_FLAGS'

ea03f50842 llvm_rc: add llvm_rc option filter to correctly pick up all options

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !5412
diff --git a/Modules/Platform/Windows-Clang.cmake b/Modules/Platform/Windows-Clang.cmake
index 2261c90..6275043 100644
--- a/Modules/Platform/Windows-Clang.cmake
+++ b/Modules/Platform/Windows-Clang.cmake
@@ -112,7 +112,9 @@
     endif()
     if(DEFINED CMAKE_RC_PREPROCESSOR)
       set(CMAKE_DEPFILE_FLAGS_RC "${clang_option_prefix}-MD ${clang_option_prefix}-MF ${clang_option_prefix}<DEPFILE>")
-      set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> /fo <OBJECT> <OBJECT>.pp")
+      # The <FLAGS> are passed to the preprocess and the resource compiler to pick
+      # up the eventual -D / -C options passed through the CMAKE_RC_FLAGS.
+      set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_COMMAND> -E cmake_llvm_rc <SOURCE> <OBJECT>.pp <${CMAKE_RC_PREPROCESSOR}> <DEFINES> -DRC_INVOKED <INCLUDES> <FLAGS> -E -- <SOURCE> ++ <CMAKE_RC_COMPILER> <DEFINES> -I <SOURCE_DIR> <INCLUDES> <FLAGS> /fo <OBJECT> <OBJECT>.pp")
       if(CMAKE_GENERATOR MATCHES "Ninja")
         set(CMAKE_NINJA_CMCLDEPS_RC 0)
         set(CMAKE_NINJA_DEP_TYPE_RC gcc)
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index ea1f968..f094085 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -58,6 +58,7 @@
 #include "cmsys/Directory.hxx"
 #include "cmsys/FStream.hxx"
 #include "cmsys/Process.h"
+#include "cmsys/RegularExpression.hxx"
 #include "cmsys/Terminal.h"
 
 int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
@@ -1711,7 +1712,6 @@
 int cmcmd::RunPreprocessor(const std::vector<std::string>& command,
                            const std::string& intermediate_file)
 {
-
   cmUVProcessChainBuilder builder;
 
   uv_fs_t fs_req;
@@ -1743,7 +1743,6 @@
 
     return 1;
   }
-
   return 0;
 }
 
@@ -1761,19 +1760,56 @@
     std::cerr << "Invalid cmake_llvm_rc arguments";
     return 1;
   }
+
   const std::string& intermediate_file = args[3];
   const std::string& source_file = args[2];
   std::vector<std::string> preprocess;
   std::vector<std::string> resource_compile;
   std::vector<std::string>* pArgTgt = &preprocess;
+
+  static const cmsys::RegularExpression llvm_rc_only_single_arg("^[-/](N|Y)");
+  static const cmsys::RegularExpression llvm_rc_only_double_arg(
+    "^[-/](C|LN|L)(.)?");
+  static const cmsys::RegularExpression common_double_arg(
+    "^[-/](D|U|I|FO|fo|Fo)(.)?");
+  bool acceptNextArg = false;
+  bool skipNextArg = false;
   for (std::string const& arg : cmMakeRange(args).advance(4)) {
+    if (skipNextArg) {
+      skipNextArg = false;
+      continue;
+    }
     // We use ++ as seperator between the preprocessing step definition and the
     // rc compilation step becase we need to prepend a -- to seperate the
     // source file properly from other options when using clang-cl for
     // preprocessing.
     if (arg == "++") {
       pArgTgt = &resource_compile;
+      skipNextArg = false;
+      acceptNextArg = true;
     } else {
+      cmsys::RegularExpressionMatch match;
+      if (!acceptNextArg) {
+        if (common_double_arg.find(arg.c_str(), match)) {
+          acceptNextArg = match.match(2).empty();
+        } else {
+          if (llvm_rc_only_single_arg.find(arg.c_str(), match)) {
+            if (pArgTgt == &preprocess) {
+              continue;
+            }
+          } else if (llvm_rc_only_double_arg.find(arg.c_str(), match)) {
+            if (pArgTgt == &preprocess) {
+              skipNextArg = match.match(2).empty();
+              continue;
+            }
+            acceptNextArg = match.match(2).empty();
+          } else if (pArgTgt == &resource_compile) {
+            continue;
+          }
+        }
+      } else {
+        acceptNextArg = false;
+      }
       if (arg.find("SOURCE_DIR") != std::string::npos) {
         std::string sourceDirArg = arg;
         cmSystemTools::ReplaceString(
@@ -1793,10 +1829,14 @@
     std::cerr << "Empty resource compilation command";
     return 1;
   }
+  // Since we might have skipped the last argument to llvm-rc
+  // we need to make sure the llvm-rc source file is present in the commandline
+  if (resource_compile.back() != intermediate_file) {
+    resource_compile.push_back(intermediate_file);
+  }
 
   auto result = RunPreprocessor(preprocess, intermediate_file);
   if (result != 0) {
-
     cmSystemTools::RemoveFile(intermediate_file);
     return result;
   }
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 38ab553..9fc5b69 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -565,7 +565,8 @@
 endif()
 
 
-add_RunCMake_test(CommandLine -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
+add_executable(pseudo_llvm-rc pseudo_llvm-rc.c)
+add_RunCMake_test(CommandLine -DLLVM_RC=$<TARGET_FILE:pseudo_llvm-rc> -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DCYGWIN=${CYGWIN} -DPYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
 add_RunCMake_test(CommandLineTar)
 
 if(CMAKE_PLATFORM_NO_VERSIONED_SONAME OR (NOT CMAKE_SHARED_LIBRARY_SONAME_FLAG AND NOT CMAKE_SHARED_LIBRARY_SONAME_C_FLAG))
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index b9c5aa2..c438860 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -789,7 +789,7 @@
         "test.tmp was not deleted")
   endif()
   file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir")
-  run_cmake_command(llvm_rc_full_run ${CMAKE_COMMAND} -E cmake_llvm_rc ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/source_file test.tmp ${CMAKE_COMMAND} -E echo "This is a test" ++ ${CMAKE_COMMAND} -E copy test.tmp SOURCE_DIR/llvmrc.result )
+  run_cmake_command(llvm_rc_full_run ${CMAKE_COMMAND} -E cmake_llvm_rc ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/source_file test.tmp ${CMAKE_COMMAND} -E echo "This is a test" ++ ${LLVM_RC} -bad /FO SOURCE_DIR/llvmrc.result test.tmp )
   if(EXISTS ${RunCMake_TEST_BINARY_DIR}/ExpandSourceDir/test.tmp)
       message(SEND_ERROR "${test} - FAILED:\n"
         "test.tmp was not deleted")
diff --git a/Tests/RunCMake/pseudo_llvm-rc.c b/Tests/RunCMake/pseudo_llvm-rc.c
new file mode 100644
index 0000000..7acb2a3
--- /dev/null
+++ b/Tests/RunCMake/pseudo_llvm-rc.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char* argv[])
+{
+  FILE* source;
+  FILE* target;
+  int i;
+  for (i = 1; i < argc; ++i) {
+    if (strcmp(argv[i], "-bad") == 0) {
+      fprintf(stdout, "stdout from bad command line arg '-bad'\n");
+      fprintf(stderr, "stderr from bad command line arg '-bad'\n");
+      return 1;
+    }
+  }
+  source = fopen(argv[argc - 1], "rb");
+  if (source == NULL) {
+    return 1;
+  }
+  target = fopen(argv[argc - 2], "wb");
+  if (target != NULL) {
+    char buffer[500];
+    size_t n = fread(buffer, 1, sizeof(buffer), source);
+    fwrite(buffer, 1, n, target);
+    fclose(source);
+    fclose(target);
+    return 0;
+  }
+  return 1;
+}