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.

This commit is contained in:
Brad King 2006-09-28 11:30:49 -04:00
parent 16f8da8b14
commit d01b6f1281
8 changed files with 102 additions and 26 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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;
}