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:
parent
16f8da8b14
commit
d01b6f1281
|
@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand::InitialPass(
|
||||||
std::string source, target, comment, main_dependency,
|
std::string source, target, comment, main_dependency,
|
||||||
working;
|
working;
|
||||||
std::vector<std::string> depends, outputs, output;
|
std::vector<std::string> depends, outputs, output;
|
||||||
|
bool verbatim = false;
|
||||||
|
|
||||||
// Accumulate one command line at a time.
|
// Accumulate one command line at a time.
|
||||||
cmCustomCommandLine currentLine;
|
cmCustomCommandLine currentLine;
|
||||||
|
@ -90,6 +91,10 @@ bool cmAddCustomCommandCommand::InitialPass(
|
||||||
{
|
{
|
||||||
cctype = cmTarget::POST_BUILD;
|
cctype = cmTarget::POST_BUILD;
|
||||||
}
|
}
|
||||||
|
else if(copy == "VERBATIM")
|
||||||
|
{
|
||||||
|
verbatim = true;
|
||||||
|
}
|
||||||
else if(copy == "TARGET")
|
else if(copy == "TARGET")
|
||||||
{
|
{
|
||||||
doing = doing_target;
|
doing = doing_target;
|
||||||
|
@ -211,13 +216,15 @@ bool cmAddCustomCommandCommand::InitialPass(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose which mode of the command to use.
|
// Choose which mode of the command to use.
|
||||||
|
bool escapeOldStyle = !verbatim;
|
||||||
if(source.empty() && output.empty())
|
if(source.empty() && output.empty())
|
||||||
{
|
{
|
||||||
// Source is empty, use the target.
|
// Source is empty, use the target.
|
||||||
std::vector<std::string> no_depends;
|
std::vector<std::string> no_depends;
|
||||||
this->Makefile->AddCustomCommandToTarget(target.c_str(), no_depends,
|
this->Makefile->AddCustomCommandToTarget(target.c_str(), no_depends,
|
||||||
commandLines, cctype,
|
commandLines, cctype,
|
||||||
comment.c_str(), working.c_str());
|
comment.c_str(), working.c_str(),
|
||||||
|
escapeOldStyle);
|
||||||
}
|
}
|
||||||
else if(target.empty())
|
else if(target.empty())
|
||||||
{
|
{
|
||||||
|
@ -225,7 +232,8 @@ bool cmAddCustomCommandCommand::InitialPass(
|
||||||
this->Makefile->AddCustomCommandToOutput(output, depends,
|
this->Makefile->AddCustomCommandToOutput(output, depends,
|
||||||
main_dependency.c_str(),
|
main_dependency.c_str(),
|
||||||
commandLines, comment.c_str(),
|
commandLines, comment.c_str(),
|
||||||
working.c_str());
|
working.c_str(), false,
|
||||||
|
escapeOldStyle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
" [MAIN_DEPENDENCY depend]\n"
|
" [MAIN_DEPENDENCY depend]\n"
|
||||||
" [DEPENDS [depends...]]\n"
|
" [DEPENDS [depends...]]\n"
|
||||||
" [WORKING_DIRECTORY dir]\n"
|
" [WORKING_DIRECTORY dir]\n"
|
||||||
" [COMMENT comment])\n"
|
" [COMMENT comment] [VERBATIM])\n"
|
||||||
"This defines a new command that can be executed during the build "
|
"This defines a new command that can be executed during the build "
|
||||||
"process. The outputs named should be listed as source files in the "
|
"process. The outputs named should be listed as source files in the "
|
||||||
"target for which they are to be generated. "
|
"target for which they are to be generated. "
|
||||||
|
@ -93,7 +93,7 @@ public:
|
||||||
" COMMAND command1 [ARGS] [args1...]\n"
|
" COMMAND command1 [ARGS] [args1...]\n"
|
||||||
" [COMMAND command2 [ARGS] [args2...] ...]\n"
|
" [COMMAND command2 [ARGS] [args2...] ...]\n"
|
||||||
" [WORKING_DIRECTORY dir]\n"
|
" [WORKING_DIRECTORY dir]\n"
|
||||||
" [COMMENT comment])\n"
|
" [COMMENT comment] [VERBATIM])\n"
|
||||||
"This defines a new command that will be associated with "
|
"This defines a new command that will be associated with "
|
||||||
"building the specified target. When the command will "
|
"building the specified target. When the command will "
|
||||||
"happen is determined by which of the following is specified:\n"
|
"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 "
|
"Studio 7 or later. For all other generators PRE_BUILD "
|
||||||
"will be treated as PRE_LINK. "
|
"will be treated as PRE_LINK. "
|
||||||
"If WORKING_DIRECTORY is specified the command will be executed "
|
"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);
|
cmTypeMacro(cmAddCustomCommandCommand, cmCommand);
|
||||||
|
|
|
@ -58,12 +58,14 @@ bool cmAddCustomTargetCommand::InitialPass(
|
||||||
// Accumulate dependencies.
|
// Accumulate dependencies.
|
||||||
std::vector<std::string> depends;
|
std::vector<std::string> depends;
|
||||||
std::string working_directory;
|
std::string working_directory;
|
||||||
|
bool verbatim = false;
|
||||||
|
|
||||||
// Keep track of parser state.
|
// Keep track of parser state.
|
||||||
enum tdoing {
|
enum tdoing {
|
||||||
doing_command,
|
doing_command,
|
||||||
doing_depends,
|
doing_depends,
|
||||||
doing_working_directory
|
doing_working_directory,
|
||||||
|
doing_verbatim
|
||||||
};
|
};
|
||||||
tdoing doing = doing_command;
|
tdoing doing = doing_command;
|
||||||
|
|
||||||
|
@ -92,6 +94,11 @@ bool cmAddCustomTargetCommand::InitialPass(
|
||||||
{
|
{
|
||||||
doing = doing_working_directory;
|
doing = doing_working_directory;
|
||||||
}
|
}
|
||||||
|
else if(copy == "VERBATIM")
|
||||||
|
{
|
||||||
|
doing = doing_verbatim;
|
||||||
|
verbatim = true;
|
||||||
|
}
|
||||||
else if(copy == "COMMAND")
|
else if(copy == "COMMAND")
|
||||||
{
|
{
|
||||||
doing = doing_command;
|
doing = doing_command;
|
||||||
|
@ -141,10 +148,11 @@ bool cmAddCustomTargetCommand::InitialPass(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the utility target to the makefile.
|
// Add the utility target to the makefile.
|
||||||
|
bool escapeOldStyle = !verbatim;
|
||||||
const char* no_output = 0;
|
const char* no_output = 0;
|
||||||
this->Makefile->AddUtilityCommand(args[0].c_str(), all, no_output,
|
this->Makefile->AddUtilityCommand(args[0].c_str(), all, no_output,
|
||||||
working_directory.c_str(), depends,
|
working_directory.c_str(), depends,
|
||||||
commandLines);
|
commandLines, escapeOldStyle);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,8 +65,8 @@ public:
|
||||||
return
|
return
|
||||||
" ADD_CUSTOM_TARGET(Name [ALL] [command1 [args1...]]\n"
|
" ADD_CUSTOM_TARGET(Name [ALL] [command1 [args1...]]\n"
|
||||||
" [COMMAND command2 [args2...] ...]\n"
|
" [COMMAND command2 [args2...] ...]\n"
|
||||||
" [DEPENDS depend depend depend ... ])\n"
|
" [DEPENDS depend depend depend ... ]\n"
|
||||||
" [WORKING_DIRECTORY dir]\n"
|
" [WORKING_DIRECTORY dir] [VERBATIM])\n"
|
||||||
"Adds a target with the given name that executes the given commands. "
|
"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 "
|
"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 "
|
"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 "
|
"If WORKING_DIRECTORY is set, then the command will be run in that "
|
||||||
"directory. "
|
"directory. "
|
||||||
"Dependencies listed with the DEPENDS argument may reference files "
|
"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);
|
cmTypeMacro(cmAddCustomTargetCommand, cmCommand);
|
||||||
|
|
|
@ -554,7 +554,8 @@ cmMakefile::AddCustomCommandToTarget(const char* target,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
cmTarget::CustomCommandType type,
|
cmTarget::CustomCommandType type,
|
||||||
const char* comment,
|
const char* comment,
|
||||||
const char* workingDir)
|
const char* workingDir,
|
||||||
|
bool escapeOldStyle)
|
||||||
{
|
{
|
||||||
// Find the target to which to add the custom command.
|
// Find the target to which to add the custom command.
|
||||||
cmTargets::iterator ti = this->Targets.find(target);
|
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.
|
// Add the command to the appropriate build step for the target.
|
||||||
std::vector<std::string> no_output;
|
std::vector<std::string> no_output;
|
||||||
cmCustomCommand cc(no_output, depends, commandLines, comment, workingDir);
|
cmCustomCommand cc(no_output, depends, commandLines, comment, workingDir);
|
||||||
|
cc.SetEscapeOldStyle(escapeOldStyle);
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case cmTarget::PRE_BUILD:
|
case cmTarget::PRE_BUILD:
|
||||||
|
@ -598,7 +600,8 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
const char* comment,
|
const char* comment,
|
||||||
const char* workingDir,
|
const char* workingDir,
|
||||||
bool replace)
|
bool replace,
|
||||||
|
bool escapeOldStyle)
|
||||||
{
|
{
|
||||||
// Make sure there is at least one output.
|
// Make sure there is at least one output.
|
||||||
if(outputs.empty())
|
if(outputs.empty())
|
||||||
|
@ -686,6 +689,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
|
||||||
cmCustomCommand* cc =
|
cmCustomCommand* cc =
|
||||||
new cmCustomCommand(outputs, depends2, commandLines,
|
new cmCustomCommand(outputs, depends2, commandLines,
|
||||||
comment, workingDir);
|
comment, workingDir);
|
||||||
|
cc->SetEscapeOldStyle(escapeOldStyle);
|
||||||
file->SetCustomCommand(cc);
|
file->SetCustomCommand(cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -698,13 +702,14 @@ cmMakefile::AddCustomCommandToOutput(const char* output,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
const char* comment,
|
const char* comment,
|
||||||
const char* workingDir,
|
const char* workingDir,
|
||||||
bool replace)
|
bool replace,
|
||||||
|
bool escapeOldStyle)
|
||||||
{
|
{
|
||||||
std::vector<std::string> outputs;
|
std::vector<std::string> outputs;
|
||||||
outputs.push_back(output);
|
outputs.push_back(output);
|
||||||
this->AddCustomCommandToOutput(outputs, depends, main_dependency,
|
this->AddCustomCommandToOutput(outputs, depends, main_dependency,
|
||||||
commandLines, comment, workingDir,
|
commandLines, comment, workingDir,
|
||||||
replace);
|
replace, escapeOldStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
@ -819,7 +824,8 @@ void cmMakefile::AddUtilityCommand(const char* utilityName, bool all,
|
||||||
const char* output,
|
const char* output,
|
||||||
const char* workingDirectory,
|
const char* workingDirectory,
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
const cmCustomCommandLines& commandLines)
|
const cmCustomCommandLines& commandLines,
|
||||||
|
bool escapeOldStyle)
|
||||||
{
|
{
|
||||||
// Create a target instance for this utility.
|
// Create a target instance for this utility.
|
||||||
cmTarget target;
|
cmTarget target;
|
||||||
|
@ -833,6 +839,7 @@ void cmMakefile::AddUtilityCommand(const char* utilityName, bool all,
|
||||||
outputs.push_back(output);
|
outputs.push_back(output);
|
||||||
}
|
}
|
||||||
cmCustomCommand cc(outputs, depends, commandLines, 0, workingDirectory);
|
cmCustomCommand cc(outputs, depends, commandLines, 0, workingDirectory);
|
||||||
|
cc.SetEscapeOldStyle(escapeOldStyle);
|
||||||
target.GetPostBuildCommands().push_back(cc);
|
target.GetPostBuildCommands().push_back(cc);
|
||||||
|
|
||||||
// Add the target to the set of targets.
|
// Add the target to the set of targets.
|
||||||
|
|
|
@ -143,19 +143,22 @@ public:
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
cmTarget::CustomCommandType type,
|
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,
|
void AddCustomCommandToOutput(const std::vector<std::string>& outputs,
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
const char* main_dependency,
|
const char* main_dependency,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
const char* comment, const char* workingDir,
|
const char* comment, const char* workingDir,
|
||||||
bool replace = false);
|
bool replace = false,
|
||||||
|
bool escapeOldStyle = true);
|
||||||
void AddCustomCommandToOutput(const char* output,
|
void AddCustomCommandToOutput(const char* output,
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
const char* main_dependency,
|
const char* main_dependency,
|
||||||
const cmCustomCommandLines& commandLines,
|
const cmCustomCommandLines& commandLines,
|
||||||
const char* comment, const char* workingDir,
|
const char* comment, const char* workingDir,
|
||||||
bool replace = false);
|
bool replace = false,
|
||||||
|
bool escapeOldStyle = true);
|
||||||
void AddCustomCommandOldStyle(const char* target,
|
void AddCustomCommandOldStyle(const char* target,
|
||||||
const std::vector<std::string>& outputs,
|
const std::vector<std::string>& outputs,
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
|
@ -192,7 +195,8 @@ public:
|
||||||
const char* output,
|
const char* output,
|
||||||
const char* workingDirectory,
|
const char* workingDirectory,
|
||||||
const std::vector<std::string>& depends,
|
const std::vector<std::string>& depends,
|
||||||
const cmCustomCommandLines& commandLines);
|
const cmCustomCommandLines& commandLines,
|
||||||
|
bool escapeOldStyle = true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a link library to the build.
|
* Add a link library to the build.
|
||||||
|
|
|
@ -176,6 +176,17 @@ SET(CHECK_ARGS
|
||||||
double\"quote
|
double\"quote
|
||||||
"\\;semi-colons\\;"
|
"\\;semi-colons\\;"
|
||||||
"semi\\;colon"
|
"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:/posix/path/with space"
|
||||||
"c:\\windows\\path\\with space"
|
"c:\\windows\\path\\with space"
|
||||||
"'single quotes with space'"
|
"'single quotes with space'"
|
||||||
|
@ -184,6 +195,17 @@ SET(CHECK_ARGS
|
||||||
"double\"quote with space"
|
"double\"quote with space"
|
||||||
"\\;semi-colons with space\\;"
|
"\\;semi-colons with space\\;"
|
||||||
"semi\\;colon 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})
|
FOREACH(arg ${CHECK_ARGS})
|
||||||
SET(ARG "${arg}")
|
SET(ARG "${arg}")
|
||||||
|
@ -199,8 +221,18 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/check_command_line.c.in
|
||||||
@ONLY IMMEDIATE)
|
@ONLY IMMEDIATE)
|
||||||
ADD_EXECUTABLE(check_command_line
|
ADD_EXECUTABLE(check_command_line
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/check_command_line.c)
|
${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
|
COMMAND ${EXECUTABLE_OUTPUT_PATH}/${CMAKE_CFG_INTDIR}/check_command_line
|
||||||
${CHECK_ARGS}
|
${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)
|
ADD_DEPENDENCIES(do_check_command_line check_command_line)
|
||||||
|
|
|
@ -20,7 +20,7 @@ int main(int argc, const char* argv[])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("[%s]\n", *a);
|
/*printf("[%s]\n", *a);*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(*a || *e)
|
if(*a || *e)
|
||||||
|
@ -28,5 +28,6 @@ int main(int argc, const char* argv[])
|
||||||
fprintf(stderr, "Number of arguments does not match expected.\n");
|
fprintf(stderr, "Number of arguments does not match expected.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
printf("Command line escapes work!\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue