Przeglądaj źródła

ENH: Added VERBATIM option to ADD_CUSTOM_COMMAND and ADD_CUSTOM_TARGET commands. This option enables full escaping of custom command arguments on all platforms. See bug#3786.

Brad King 19 lat temu
rodzic
commit
d01b6f1281

+ 15 - 7
Source/cmAddCustomCommandCommand.cxx

@@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand::InitialPass(
   std::string source, target, comment, main_dependency,
     working;
   std::vector<std::string> depends, outputs, output;
+  bool verbatim = false;
 
   // Accumulate one command line at a time.
   cmCustomCommandLine currentLine;
@@ -90,6 +91,10 @@ bool cmAddCustomCommandCommand::InitialPass(
       {
       cctype = cmTarget::POST_BUILD;
       }
+    else if(copy == "VERBATIM")
+      {
+      verbatim = true;
+      }
     else if(copy == "TARGET")
       {
       doing = doing_target;
@@ -211,28 +216,31 @@ bool cmAddCustomCommandCommand::InitialPass(
     }
 
   // Choose which mode of the command to use.
+  bool escapeOldStyle = !verbatim;
   if(source.empty() && output.empty())
     {
     // Source is empty, use the target.
     std::vector<std::string> no_depends;
     this->Makefile->AddCustomCommandToTarget(target.c_str(), no_depends,
-                                         commandLines, cctype,
-                                         comment.c_str(), working.c_str());
+                                             commandLines, cctype,
+                                             comment.c_str(), working.c_str(),
+                                             escapeOldStyle);
     }
   else if(target.empty())
     {
     // Target is empty, use the output.
     this->Makefile->AddCustomCommandToOutput(output, depends,
-                                         main_dependency.c_str(),
-                                         commandLines, comment.c_str(),
-                                         working.c_str());
+                                             main_dependency.c_str(),
+                                             commandLines, comment.c_str(),
+                                             working.c_str(), false,
+                                             escapeOldStyle);
     }
   else
     {
     // Use the old-style mode for backward compatibility.
     this->Makefile->AddCustomCommandOldStyle(target.c_str(), outputs, depends,
-                                         source.c_str(), commandLines,
-                                         comment.c_str());
+                                             source.c_str(), commandLines,
+                                             comment.c_str());
     }
   return true;
 }

+ 11 - 3
Source/cmAddCustomCommandCommand.h

@@ -72,7 +72,7 @@ public:
       "                     [MAIN_DEPENDENCY depend]\n"
       "                     [DEPENDS [depends...]]\n"
       "                     [WORKING_DIRECTORY dir]\n"
-      "                     [COMMENT comment])\n"
+      "                     [COMMENT comment] [VERBATIM])\n"
       "This defines a new command that can be executed during the build "
       "process. The outputs named should be listed as source files in the "
       "target for which they are to be generated. "
@@ -93,7 +93,7 @@ public:
       "                     COMMAND command1 [ARGS] [args1...]\n"
       "                     [COMMAND command2 [ARGS] [args2...] ...]\n"
       "                     [WORKING_DIRECTORY dir]\n"
-      "                     [COMMENT comment])\n"
+      "                     [COMMENT comment] [VERBATIM])\n"
       "This defines a new command that will be associated with "
       "building the specified target. When the command will "
       "happen is determined by which of the following is specified:\n"
@@ -104,7 +104,15 @@ public:
       "Studio 7 or later. For all other generators PRE_BUILD "
       "will be treated as PRE_LINK. "
       "If WORKING_DIRECTORY is specified the command will be executed "
-      "in the directory given.";
+      "in the directory given.\n"
+      "If VERBATIM is given then all the arguments to the commands will be "
+      "passed exactly as specified no matter the build tool used. "
+      "Note that one level of escapes is still used by the CMake language "
+      "processor before ADD_CUSTOM_TARGET even sees the arguments. "
+      "Use of VERBATIM is recommended as it enables correct behavior. "
+      "When VERBATIM is not given the behavior is platform specific. "
+      "In the future VERBATIM may be enabled by default. The only reason "
+      "it is an option is to preserve compatibility with older CMake code.";
     }
   
   cmTypeMacro(cmAddCustomCommandCommand, cmCommand);

+ 10 - 2
Source/cmAddCustomTargetCommand.cxx

@@ -58,12 +58,14 @@ bool cmAddCustomTargetCommand::InitialPass(
   // Accumulate dependencies.
   std::vector<std::string> depends;
   std::string working_directory;
+  bool verbatim = false;
 
   // Keep track of parser state.
   enum tdoing {
     doing_command,
     doing_depends,
-    doing_working_directory
+    doing_working_directory,
+    doing_verbatim
   };
   tdoing doing = doing_command;
 
@@ -92,6 +94,11 @@ bool cmAddCustomTargetCommand::InitialPass(
       {
       doing = doing_working_directory;
       }
+    else if(copy == "VERBATIM")
+      {
+      doing = doing_verbatim;
+      verbatim = true;
+      }
     else if(copy == "COMMAND")
       {
       doing = doing_command;
@@ -141,10 +148,11 @@ bool cmAddCustomTargetCommand::InitialPass(
     }
 
   // Add the utility target to the makefile.
+  bool escapeOldStyle = !verbatim;
   const char* no_output = 0;
   this->Makefile->AddUtilityCommand(args[0].c_str(), all, no_output,
                                     working_directory.c_str(), depends,
-                                    commandLines);
+                                    commandLines, escapeOldStyle);
 
   return true;
 }

+ 11 - 3
Source/cmAddCustomTargetCommand.h

@@ -65,8 +65,8 @@ public:
     return
       "  ADD_CUSTOM_TARGET(Name [ALL] [command1 [args1...]]\n"
       "                    [COMMAND command2 [args2...] ...]\n"
-      "                    [DEPENDS depend depend depend ... ])\n"
-      "                    [WORKING_DIRECTORY dir]\n"
+      "                    [DEPENDS depend depend depend ... ]\n"
+      "                    [WORKING_DIRECTORY dir] [VERBATIM])\n"
       "Adds a target with the given name that executes the given commands. "
       "The target has no output file and is ALWAYS CONSIDERED OUT OF DATE "
       "even if the commands try to create a file with the name of the "
@@ -82,7 +82,15 @@ public:
       "If WORKING_DIRECTORY is set, then the command will be run in that "
       "directory. "
       "Dependencies listed with the DEPENDS argument may reference files "
-      "and outputs of custom commands created with ADD_CUSTOM_COMMAND.";
+      "and outputs of custom commands created with ADD_CUSTOM_COMMAND.\n"
+      "If VERBATIM is given then all the arguments to the commands will be "
+      "passed exactly as specified no matter the build tool used. "
+      "Note that one level of escapes is still used by the CMake language "
+      "processor before ADD_CUSTOM_TARGET even sees the arguments. "
+      "Use of VERBATIM is recommended as it enables correct behavior. "
+      "When VERBATIM is not given the behavior is platform specific. "
+      "In the future VERBATIM may be enabled by default. The only reason "
+      "it is an option is to preserve compatibility with older CMake code.";
     }
   
   cmTypeMacro(cmAddCustomTargetCommand, cmCommand);

+ 12 - 5
Source/cmMakefile.cxx

@@ -554,7 +554,8 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
                                      const cmCustomCommandLines& commandLines,
                                      cmTarget::CustomCommandType type,
                                      const char* comment,
-                                     const char* workingDir)
+                                     const char* workingDir,
+                                     bool escapeOldStyle)
 {
   // Find the target to which to add the custom command.
   cmTargets::iterator ti = this->Targets.find(target);
@@ -563,6 +564,7 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
     // Add the command to the appropriate build step for the target.
     std::vector<std::string> no_output;
     cmCustomCommand cc(no_output, depends, commandLines, comment, workingDir);
+    cc.SetEscapeOldStyle(escapeOldStyle);
     switch(type)
       {
       case cmTarget::PRE_BUILD:
@@ -598,7 +600,8 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
                                      const cmCustomCommandLines& commandLines,
                                      const char* comment,
                                      const char* workingDir,
-                                     bool replace)
+                                     bool replace,
+                                     bool escapeOldStyle)
 {
   // Make sure there is at least one output.
   if(outputs.empty())
@@ -686,6 +689,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
     cmCustomCommand* cc =
       new cmCustomCommand(outputs, depends2, commandLines,
                           comment, workingDir);
+    cc->SetEscapeOldStyle(escapeOldStyle);
     file->SetCustomCommand(cc);
     }
 }
@@ -698,13 +702,14 @@ cmMakefile::AddCustomCommandToOutput(const char* output,
                                      const cmCustomCommandLines& commandLines,
                                      const char* comment,
                                      const char* workingDir,
-                                     bool replace)
+                                     bool replace,
+                                     bool escapeOldStyle)
 {
   std::vector<std::string> outputs;
   outputs.push_back(output);
   this->AddCustomCommandToOutput(outputs, depends, main_dependency,
                                  commandLines, comment, workingDir,
-                                 replace);
+                                 replace, escapeOldStyle);
 }
 
 //----------------------------------------------------------------------------
@@ -819,7 +824,8 @@ void cmMakefile::AddUtilityCommand(const char* utilityName, bool all,
                                    const char* output,
                                    const char* workingDirectory,
                                    const std::vector<std::string>& depends,
-                                   const cmCustomCommandLines& commandLines)
+                                   const cmCustomCommandLines& commandLines,
+                                   bool escapeOldStyle)
 {
   // Create a target instance for this utility.
   cmTarget target;
@@ -833,6 +839,7 @@ void cmMakefile::AddUtilityCommand(const char* utilityName, bool all,
     outputs.push_back(output);
     }
   cmCustomCommand cc(outputs, depends, commandLines, 0, workingDirectory);
+  cc.SetEscapeOldStyle(escapeOldStyle);
   target.GetPostBuildCommands().push_back(cc);
 
   // Add the target to the set of targets.

+ 8 - 4
Source/cmMakefile.h

@@ -143,19 +143,22 @@ public:
                                 const std::vector<std::string>& depends,
                                 const cmCustomCommandLines& commandLines,
                                 cmTarget::CustomCommandType type,
-                                const char* comment, const char* workingDir);
+                                const char* comment, const char* workingDir,
+                                bool escapeOldStyle = true);
   void AddCustomCommandToOutput(const std::vector<std::string>& outputs,
                                 const std::vector<std::string>& depends,
                                 const char* main_dependency,
                                 const cmCustomCommandLines& commandLines,
                                 const char* comment, const char* workingDir,
-                                bool replace = false);
+                                bool replace = false,
+                                bool escapeOldStyle = true);
   void AddCustomCommandToOutput(const char* output,
                                 const std::vector<std::string>& depends,
                                 const char* main_dependency,
                                 const cmCustomCommandLines& commandLines,
                                 const char* comment, const char* workingDir,
-                                bool replace = false);
+                                bool replace = false,
+                                bool escapeOldStyle = true);
   void AddCustomCommandOldStyle(const char* target,
                                 const std::vector<std::string>& outputs,
                                 const std::vector<std::string>& depends,
@@ -192,7 +195,8 @@ public:
                          const char* output,
                          const char* workingDirectory,
                          const std::vector<std::string>& depends,
-                         const cmCustomCommandLines& commandLines);
+                         const cmCustomCommandLines& commandLines,
+                         bool escapeOldStyle = true);
 
   /**
    * Add a link library to the build.

+ 33 - 1
Tests/CustomCommand/CMakeLists.txt

@@ -176,6 +176,17 @@ SET(CHECK_ARGS
   double\"quote
   "\\;semi-colons\\;"
   "semi\\;colon"
+  `back-ticks`
+  back`tick
+  "(parens)"
+  "(lparen"
+  "rparen)"
+  $dollar-signs$
+  dollar$sign
+  &ampersands&
+  amper&sand
+  \@two-ats\@
+  one@at
   "c:/posix/path/with space"
   "c:\\windows\\path\\with space"
   "'single quotes with space'"
@@ -184,6 +195,17 @@ SET(CHECK_ARGS
   "double\"quote with space"
   "\\;semi-colons with space\\;"
   "semi\\;colon with space"
+  "`back-ticks` with space"
+  "back`tick with space"
+  "(parens) with space"
+  "(lparen with space"
+  "rparen) with space"
+  "$dollar-signs$ with space"
+  "dollar$sign with space"
+  "&ampersands& with space"
+  "amper&sand with space"
+  "\@two-ats\@ with space"
+  "one@at with space"
   )
 FOREACH(arg ${CHECK_ARGS})
   SET(ARG "${arg}")
@@ -199,8 +221,18 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/check_command_line.c.in
                @ONLY IMMEDIATE)
 ADD_EXECUTABLE(check_command_line
   ${CMAKE_CURRENT_BINARY_DIR}/check_command_line.c)
-ADD_CUSTOM_TARGET(do_check_command_line #ALL
+ADD_CUSTOM_COMMAND(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/command_line_check
+  COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/check_command_line
+  ${CHECK_ARGS}
+  VERBATIM
+  COMMENT "Checking custom command line escapes"
+  )
+ADD_CUSTOM_TARGET(do_check_command_line ALL
+  DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/command_line_check
+  COMMAND ${CMAKE_COMMAND} -E echo "Checking custom target command escapes"
   COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/check_command_line
   ${CHECK_ARGS}
+  VERBATIM
   )
 ADD_DEPENDENCIES(do_check_command_line check_command_line)

+ 2 - 1
Tests/CustomCommand/check_command_line.c.in

@@ -20,7 +20,7 @@ int main(int argc, const char* argv[])
       }
     else
       {
-      printf("[%s]\n", *a);
+      /*printf("[%s]\n", *a);*/
       }
     }
   if(*a || *e)
@@ -28,5 +28,6 @@ int main(int argc, const char* argv[])
     fprintf(stderr, "Number of arguments does not match expected.\n");
     return 1;
     }
+  printf("Command line escapes work!\n");
   return 0;
 }