Add USES_TERMINAL option for custom commands

Teach the add_custom_command and add_custom_target commands a new
USES_TERMINAL option.  Use it to tell the generator to give the command
direct access to the terminal if possible.
This commit is contained in:
Peter Collingbourne 2014-11-05 21:37:52 +01:00 committed by Brad King
parent ad6ee42627
commit fe5d6e8c0f
17 changed files with 123 additions and 17 deletions

View File

@ -18,7 +18,8 @@ The first signature is for adding a custom command to produce an output::
[IMPLICIT_DEPENDS <lang1> depend1 [IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...] [<lang2> depend2] ...]
[WORKING_DIRECTORY dir] [WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM] [APPEND]) [COMMENT comment]
[VERBATIM] [APPEND] [USES_TERMINAL])
This defines a command to generate specified ``OUTPUT`` file(s). This defines a command to generate specified ``OUTPUT`` file(s).
A target created in the same directory (``CMakeLists.txt`` file) A target created in the same directory (``CMakeLists.txt`` file)
@ -120,6 +121,11 @@ The options are:
as a file on disk it should be marked with the :prop_sf:`SYMBOLIC` as a file on disk it should be marked with the :prop_sf:`SYMBOLIC`
source file property. source file property.
``USES_TERMINAL``
The command will be given direct access to the terminal if possible.
With the :generator:`Ninja` generator, this places the command in
the ``console`` pool.
``VERBATIM`` ``VERBATIM``
All arguments to the commands will be escaped properly for the All arguments to the commands will be escaped properly for the
build tool so that the invoked command receives each argument build tool so that the invoked command receives each argument
@ -151,7 +157,8 @@ target is already built, the command will not execute.
COMMAND command1 [ARGS] [args1...] COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...] [COMMAND command2 [ARGS] [args2...] ...]
[WORKING_DIRECTORY dir] [WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM]) [COMMENT comment]
[VERBATIM] [USES_TERMINAL])
This defines a new command that will be associated with building the This defines a new command that will be associated with building the
specified target. When the command will happen is determined by which specified target. When the command will happen is determined by which

View File

@ -9,7 +9,8 @@ Add a target with no output so it will always be built.
[COMMAND command2 [args2...] ...] [COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ] [DEPENDS depend depend depend ... ]
[WORKING_DIRECTORY dir] [WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM] [COMMENT comment]
[VERBATIM] [USES_TERMINAL]
[SOURCES src1 [src2...]]) [SOURCES src1 [src2...]])
Adds a target with the given name that executes the given commands. Adds a target with the given name that executes the given commands.
@ -74,6 +75,11 @@ The options are:
is platform specific because there is no protection of is platform specific because there is no protection of
tool-specific special characters. tool-specific special characters.
``USES_TERMINAL``
The command will be given direct access to the terminal if possible.
With the :generator:`Ninja` generator, this places the command in
the ``console`` pool.
``WORKING_DIRECTORY`` ``WORKING_DIRECTORY``
Execute the command with the given current working directory. Execute the command with the given current working directory.
If it is a relative path it will be interpreted relative to the If it is a relative path it will be interpreted relative to the

View File

@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand
std::vector<std::string> depends, outputs, output; std::vector<std::string> depends, outputs, output;
bool verbatim = false; bool verbatim = false;
bool append = false; bool append = false;
bool uses_terminal = false;
std::string implicit_depends_lang; std::string implicit_depends_lang;
cmCustomCommand::ImplicitDependsList implicit_depends; cmCustomCommand::ImplicitDependsList implicit_depends;
@ -102,6 +103,10 @@ bool cmAddCustomCommandCommand
{ {
append = true; append = true;
} }
else if(copy == "USES_TERMINAL")
{
uses_terminal = true;
}
else if(copy == "TARGET") else if(copy == "TARGET")
{ {
doing = doing_target; doing = doing_target;
@ -312,7 +317,7 @@ bool cmAddCustomCommandCommand
this->Makefile->AddCustomCommandToTarget(target, no_depends, this->Makefile->AddCustomCommandToTarget(target, no_depends,
commandLines, cctype, commandLines, cctype,
comment, working.c_str(), comment, working.c_str(),
escapeOldStyle); escapeOldStyle, uses_terminal);
} }
else if(target.empty()) else if(target.empty())
{ {
@ -321,7 +326,7 @@ bool cmAddCustomCommandCommand
main_dependency, main_dependency,
commandLines, comment, commandLines, comment,
working.c_str(), false, working.c_str(), false,
escapeOldStyle); escapeOldStyle, uses_terminal);
// Add implicit dependency scanning requests if any were given. // Add implicit dependency scanning requests if any were given.
if(!implicit_depends.empty()) if(!implicit_depends.empty())
@ -346,6 +351,11 @@ bool cmAddCustomCommandCommand
} }
} }
} }
else if (uses_terminal)
{
this->SetError("USES_TERMINAL may not be used with SOURCE signatures");
return false;
}
else else
{ {
bool issueMessage = true; bool issueMessage = true;

View File

@ -48,6 +48,7 @@ bool cmAddCustomTargetCommand
std::vector<std::string> depends; std::vector<std::string> depends;
std::string working_directory; std::string working_directory;
bool verbatim = false; bool verbatim = false;
bool uses_terminal = false;
std::string comment_buffer; std::string comment_buffer;
const char* comment = 0; const char* comment = 0;
std::vector<std::string> sources; std::vector<std::string> sources;
@ -93,6 +94,11 @@ bool cmAddCustomTargetCommand
doing = doing_nothing; doing = doing_nothing;
verbatim = true; verbatim = true;
} }
else if(copy == "USES_TERMINAL")
{
doing = doing_nothing;
uses_terminal = true;
}
else if (copy == "COMMENT") else if (copy == "COMMENT")
{ {
doing = doing_comment; doing = doing_comment;
@ -221,12 +227,20 @@ bool cmAddCustomTargetCommand
cmSystemTools::CollapseFullPath(working_directory, build_dir); cmSystemTools::CollapseFullPath(working_directory, build_dir);
} }
if (commandLines.empty() && uses_terminal)
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"USES_TERMINAL may not be specified without any COMMAND");
return true;
}
// Add the utility target to the makefile. // Add the utility target to the makefile.
bool escapeOldStyle = !verbatim; bool escapeOldStyle = !verbatim;
cmTarget* target = cmTarget* target =
this->Makefile->AddUtilityCommand(targetName, excludeFromAll, this->Makefile->AddUtilityCommand(targetName, excludeFromAll,
working_directory.c_str(), depends, working_directory.c_str(), depends,
commandLines, escapeOldStyle, comment); commandLines, escapeOldStyle, comment,
uses_terminal);
// Add additional user-specified source files to the target. // Add additional user-specified source files to the target.
target->AddSources(sources); target->AddSources(sources);

View File

@ -22,6 +22,7 @@ cmCustomCommand::cmCustomCommand()
this->HaveComment = false; this->HaveComment = false;
this->EscapeOldStyle = true; this->EscapeOldStyle = true;
this->EscapeAllowMakeVars = false; this->EscapeAllowMakeVars = false;
this->UsesTerminal = false;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -34,7 +35,8 @@ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r):
WorkingDirectory(r.WorkingDirectory), WorkingDirectory(r.WorkingDirectory),
EscapeAllowMakeVars(r.EscapeAllowMakeVars), EscapeAllowMakeVars(r.EscapeAllowMakeVars),
EscapeOldStyle(r.EscapeOldStyle), EscapeOldStyle(r.EscapeOldStyle),
Backtrace(r.Backtrace) Backtrace(r.Backtrace),
UsesTerminal(r.UsesTerminal)
{ {
} }
@ -56,6 +58,7 @@ cmCustomCommand& cmCustomCommand::operator=(cmCustomCommand const& r)
this->EscapeOldStyle = r.EscapeOldStyle; this->EscapeOldStyle = r.EscapeOldStyle;
this->ImplicitDepends = r.ImplicitDepends; this->ImplicitDepends = r.ImplicitDepends;
this->Backtrace = r.Backtrace; this->Backtrace = r.Backtrace;
this->UsesTerminal = r.UsesTerminal;
return *this; return *this;
} }
@ -184,3 +187,15 @@ void cmCustomCommand::AppendImplicitDepends(ImplicitDependsList const& l)
this->ImplicitDepends.insert(this->ImplicitDepends.end(), this->ImplicitDepends.insert(this->ImplicitDepends.end(),
l.begin(), l.end()); l.begin(), l.end());
} }
//----------------------------------------------------------------------------
bool cmCustomCommand::GetUsesTerminal() const
{
return this->UsesTerminal;
}
//----------------------------------------------------------------------------
void cmCustomCommand::SetUsesTerminal(bool b)
{
this->UsesTerminal = b;
}

View File

@ -79,6 +79,11 @@ public:
void AppendImplicitDepends(ImplicitDependsList const&); void AppendImplicitDepends(ImplicitDependsList const&);
ImplicitDependsList const& GetImplicitDepends() const; ImplicitDependsList const& GetImplicitDepends() const;
/** Set/Get whether this custom command should be given access to the
real console (if possible). */
bool GetUsesTerminal() const;
void SetUsesTerminal(bool b);
private: private:
std::vector<std::string> Outputs; std::vector<std::string> Outputs;
std::vector<std::string> Depends; std::vector<std::string> Depends;
@ -90,6 +95,7 @@ private:
bool EscapeOldStyle; bool EscapeOldStyle;
cmListFileBacktrace Backtrace; cmListFileBacktrace Backtrace;
ImplicitDependsList ImplicitDepends; ImplicitDependsList ImplicitDepends;
bool UsesTerminal;
}; };
#endif #endif

View File

@ -885,7 +885,8 @@ cmMakefile::AddCustomCommandToTarget(const std::string& target,
cmTarget::CustomCommandType type, cmTarget::CustomCommandType type,
const char* comment, const char* comment,
const char* workingDir, const char* workingDir,
bool escapeOldStyle) const bool escapeOldStyle,
bool uses_terminal) const
{ {
// 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);
@ -941,6 +942,7 @@ cmMakefile::AddCustomCommandToTarget(const std::string& target,
commandLines, comment, workingDir); commandLines, comment, workingDir);
cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeOldStyle(escapeOldStyle);
cc.SetEscapeAllowMakeVars(true); cc.SetEscapeAllowMakeVars(true);
cc.SetUsesTerminal(uses_terminal);
switch(type) switch(type)
{ {
case cmTarget::PRE_BUILD: case cmTarget::PRE_BUILD:
@ -964,7 +966,8 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
const char* comment, const char* comment,
const char* workingDir, const char* workingDir,
bool replace, bool replace,
bool escapeOldStyle) bool escapeOldStyle,
bool uses_terminal)
{ {
// Make sure there is at least one output. // Make sure there is at least one output.
if(outputs.empty()) if(outputs.empty())
@ -1071,6 +1074,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector<std::string>& outputs,
comment, workingDir); comment, workingDir);
cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeOldStyle(escapeOldStyle);
cc->SetEscapeAllowMakeVars(true); cc->SetEscapeAllowMakeVars(true);
cc->SetUsesTerminal(uses_terminal);
file->SetCustomCommand(cc); file->SetCustomCommand(cc);
this->UpdateOutputToSourceMap(outputs, file); this->UpdateOutputToSourceMap(outputs, file);
} }
@ -1119,13 +1123,15 @@ cmMakefile::AddCustomCommandToOutput(const std::string& output,
const char* comment, const char* comment,
const char* workingDir, const char* workingDir,
bool replace, bool replace,
bool escapeOldStyle) bool escapeOldStyle,
bool uses_terminal)
{ {
std::vector<std::string> outputs; std::vector<std::string> outputs;
outputs.push_back(output); outputs.push_back(output);
return this->AddCustomCommandToOutput(outputs, depends, main_dependency, return this->AddCustomCommandToOutput(outputs, depends, main_dependency,
commandLines, comment, workingDir, commandLines, comment, workingDir,
replace, escapeOldStyle); replace, escapeOldStyle,
uses_terminal);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1242,7 +1248,8 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName,
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, const char* comment) bool escapeOldStyle, const char* comment,
bool uses_terminal)
{ {
// Create a target instance for this utility. // Create a target instance for this utility.
cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName); cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName);
@ -1269,7 +1276,7 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName,
no_main_dependency, no_main_dependency,
commandLines, comment, commandLines, comment,
workingDirectory, no_replace, workingDirectory, no_replace,
escapeOldStyle); escapeOldStyle, uses_terminal);
cmSourceFile* sf = target->AddSourceCMP0049(force); cmSourceFile* sf = target->AddSourceCMP0049(force);
// The output is not actually created so mark it symbolic. // The output is not actually created so mark it symbolic.

View File

@ -174,7 +174,8 @@ public:
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) const; bool escapeOldStyle = true,
bool uses_terminal = false) const;
cmSourceFile* AddCustomCommandToOutput( cmSourceFile* AddCustomCommandToOutput(
const std::vector<std::string>& outputs, const std::vector<std::string>& outputs,
const std::vector<std::string>& depends, const std::vector<std::string>& depends,
@ -182,7 +183,8 @@ public:
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); bool escapeOldStyle = true,
bool uses_terminal = false);
cmSourceFile* AddCustomCommandToOutput( cmSourceFile* AddCustomCommandToOutput(
const std::string& output, const std::string& output,
const std::vector<std::string>& depends, const std::vector<std::string>& depends,
@ -190,7 +192,8 @@ public:
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); bool escapeOldStyle = true,
bool uses_terminal = false);
void AddCustomCommandOldStyle(const std::string& target, void AddCustomCommandOldStyle(const std::string& 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,
@ -237,7 +240,8 @@ public:
const std::vector<std::string>& depends, const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, const cmCustomCommandLines& commandLines,
bool escapeOldStyle = true, bool escapeOldStyle = true,
const char* comment = 0); const char* comment = 0,
bool uses_terminal = false);
/** /**
* Add a link library to the build. * Add a link library to the build.

View File

@ -483,3 +483,26 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}") COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}")
add_library(NormDepends "${gen_file}") add_library(NormDepends "${gen_file}")
# Test that USES_TERMINAL is parsed correctly.
# It seems much more difficult to test that USES_TERMINAL actually gives
# the subprocess console access, as test output is piped through CTest,
# and CTest itself might not be connected to the console.
set(gen_file "${gen_path}/bar2.cxx")
add_custom_command(
OUTPUT "${gen_file}"
DEPENDS "${gen_path}"
COMMAND ${CMAKE_COMMAND} -E touch "${gen_file}"
VERBATIM
USES_TERMINAL
)
add_library(UseConsole "${gen_file}")
add_custom_target(UseConsoleTarget ALL
COMMAND ${CMAKE_COMMAND} -E echo "Custom console target."
VERBATIM
USES_TERMINAL
)

View File

@ -6,3 +6,4 @@ run_cmake(BadArgument)
run_cmake(NoArguments) run_cmake(NoArguments)
run_cmake(NoOutputOrTarget) run_cmake(NoOutputOrTarget)
run_cmake(OutputAndTarget) run_cmake(OutputAndTarget)
run_cmake(SourceUsesTerminal)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at SourceUsesTerminal.cmake:1 \(add_custom_command\):
add_custom_command USES_TERMINAL may not be used with SOURCE signatures
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_custom_command(SOURCE t TARGET t USES_TERMINAL)

View File

@ -2,3 +2,4 @@ include(RunCMake)
run_cmake(NoArguments) run_cmake(NoArguments)
run_cmake(BadTargetName) run_cmake(BadTargetName)
run_cmake(UsesTerminalNoCommand)

View File

@ -0,0 +1,4 @@
CMake Error at UsesTerminalNoCommand.cmake:1 \(add_custom_target\):
USES_TERMINAL may not be specified without any COMMAND
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1 @@
add_custom_target(MyTarget USES_TERMINAL)