From d01b6f12819c4d8aec189ae3eebfd1779565bbf2 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 28 Sep 2006 11:30:49 -0400 Subject: 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. --- Source/cmAddCustomCommandCommand.cxx | 22 +++++++++++++------ Source/cmAddCustomCommandCommand.h | 14 +++++++++--- Source/cmAddCustomTargetCommand.cxx | 12 ++++++++-- Source/cmAddCustomTargetCommand.h | 14 +++++++++--- Source/cmMakefile.cxx | 17 ++++++++++----- Source/cmMakefile.h | 12 ++++++---- Tests/CustomCommand/CMakeLists.txt | 34 ++++++++++++++++++++++++++++- Tests/CustomCommand/check_command_line.c.in | 3 ++- 8 files changed, 102 insertions(+), 26 deletions(-) diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 4f6df9e..3c37d4b 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand::InitialPass( std::string source, target, comment, main_dependency, working; std::vector 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 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; } diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h index bacce8f..73bd881 100644 --- a/Source/cmAddCustomCommandCommand.h +++ b/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); diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index ccdc8a9..d9879cf 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -58,12 +58,14 @@ bool cmAddCustomTargetCommand::InitialPass( // Accumulate dependencies. std::vector 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; } diff --git a/Source/cmAddCustomTargetCommand.h b/Source/cmAddCustomTargetCommand.h index d6b38e3..a8ed7c4 100644 --- a/Source/cmAddCustomTargetCommand.h +++ b/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); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 1e1b15f..38be4ca 100644 --- a/Source/cmMakefile.cxx +++ b/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 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& 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& 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 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& 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. diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 2cb8f8f..e4eae42 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -143,19 +143,22 @@ public: const std::vector& 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& outputs, const std::vector& 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& 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& outputs, const std::vector& depends, @@ -192,7 +195,8 @@ public: const char* output, const char* workingDirectory, const std::vector& depends, - const cmCustomCommandLines& commandLines); + const cmCustomCommandLines& commandLines, + bool escapeOldStyle = true); /** * Add a link library to the build. diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt index 3af8540..f50de52 100644 --- a/Tests/CustomCommand/CMakeLists.txt +++ b/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 + &ersands& + 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" + "&ersands& 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) diff --git a/Tests/CustomCommand/check_command_line.c.in b/Tests/CustomCommand/check_command_line.c.in index a4dbe22..71d5278 100644 --- a/Tests/CustomCommand/check_command_line.c.in +++ b/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; } -- cgit v0.12