diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index 2d67b981a..cb0746b8f 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -18,7 +18,8 @@ The first signature is for adding a custom command to produce an output:: [IMPLICIT_DEPENDS depend1 [ depend2] ...] [WORKING_DIRECTORY dir] - [COMMENT comment] [VERBATIM] [APPEND]) + [COMMENT comment] + [VERBATIM] [APPEND] [USES_TERMINAL]) This defines a command to generate specified ``OUTPUT`` file(s). 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` 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`` All arguments to the commands will be escaped properly for the 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 command2 [ARGS] [args2...] ...] [WORKING_DIRECTORY dir] - [COMMENT comment] [VERBATIM]) + [COMMENT comment] + [VERBATIM] [USES_TERMINAL]) This defines a new command that will be associated with building the specified target. When the command will happen is determined by which diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst index 4f8e1903a..8b7472df8 100644 --- a/Help/command/add_custom_target.rst +++ b/Help/command/add_custom_target.rst @@ -9,7 +9,8 @@ Add a target with no output so it will always be built. [COMMAND command2 [args2...] ...] [DEPENDS depend depend depend ... ] [WORKING_DIRECTORY dir] - [COMMENT comment] [VERBATIM] + [COMMENT comment] + [VERBATIM] [USES_TERMINAL] [SOURCES src1 [src2...]]) 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 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`` Execute the command with the given current working directory. If it is a relative path it will be interpreted relative to the diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 2d1961062..410f97878 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand std::vector depends, outputs, output; bool verbatim = false; bool append = false; + bool uses_terminal = false; std::string implicit_depends_lang; cmCustomCommand::ImplicitDependsList implicit_depends; @@ -102,6 +103,10 @@ bool cmAddCustomCommandCommand { append = true; } + else if(copy == "USES_TERMINAL") + { + uses_terminal = true; + } else if(copy == "TARGET") { doing = doing_target; @@ -312,7 +317,7 @@ bool cmAddCustomCommandCommand this->Makefile->AddCustomCommandToTarget(target, no_depends, commandLines, cctype, comment, working.c_str(), - escapeOldStyle); + escapeOldStyle, uses_terminal); } else if(target.empty()) { @@ -321,7 +326,7 @@ bool cmAddCustomCommandCommand main_dependency, commandLines, comment, working.c_str(), false, - escapeOldStyle); + escapeOldStyle, uses_terminal); // Add implicit dependency scanning requests if any were given. 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 { bool issueMessage = true; diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 64e76f376..fc4f8f198 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -48,6 +48,7 @@ bool cmAddCustomTargetCommand std::vector depends; std::string working_directory; bool verbatim = false; + bool uses_terminal = false; std::string comment_buffer; const char* comment = 0; std::vector sources; @@ -93,6 +94,11 @@ bool cmAddCustomTargetCommand doing = doing_nothing; verbatim = true; } + else if(copy == "USES_TERMINAL") + { + doing = doing_nothing; + uses_terminal = true; + } else if (copy == "COMMENT") { doing = doing_comment; @@ -221,12 +227,20 @@ bool cmAddCustomTargetCommand 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. bool escapeOldStyle = !verbatim; cmTarget* target = this->Makefile->AddUtilityCommand(targetName, excludeFromAll, working_directory.c_str(), depends, - commandLines, escapeOldStyle, comment); + commandLines, escapeOldStyle, comment, + uses_terminal); // Add additional user-specified source files to the target. target->AddSources(sources); diff --git a/Source/cmCustomCommand.cxx b/Source/cmCustomCommand.cxx index c161eb63d..45369cc2b 100644 --- a/Source/cmCustomCommand.cxx +++ b/Source/cmCustomCommand.cxx @@ -22,6 +22,7 @@ cmCustomCommand::cmCustomCommand() this->HaveComment = false; this->EscapeOldStyle = true; this->EscapeAllowMakeVars = false; + this->UsesTerminal = false; } //---------------------------------------------------------------------------- @@ -34,7 +35,8 @@ cmCustomCommand::cmCustomCommand(const cmCustomCommand& r): WorkingDirectory(r.WorkingDirectory), EscapeAllowMakeVars(r.EscapeAllowMakeVars), 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->ImplicitDepends = r.ImplicitDepends; this->Backtrace = r.Backtrace; + this->UsesTerminal = r.UsesTerminal; return *this; } @@ -184,3 +187,15 @@ void cmCustomCommand::AppendImplicitDepends(ImplicitDependsList const& l) this->ImplicitDepends.insert(this->ImplicitDepends.end(), l.begin(), l.end()); } + +//---------------------------------------------------------------------------- +bool cmCustomCommand::GetUsesTerminal() const +{ + return this->UsesTerminal; +} + +//---------------------------------------------------------------------------- +void cmCustomCommand::SetUsesTerminal(bool b) +{ + this->UsesTerminal = b; +} diff --git a/Source/cmCustomCommand.h b/Source/cmCustomCommand.h index 21dbefb26..283a0e462 100644 --- a/Source/cmCustomCommand.h +++ b/Source/cmCustomCommand.h @@ -79,6 +79,11 @@ public: void AppendImplicitDepends(ImplicitDependsList 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: std::vector Outputs; std::vector Depends; @@ -90,6 +95,7 @@ private: bool EscapeOldStyle; cmListFileBacktrace Backtrace; ImplicitDependsList ImplicitDepends; + bool UsesTerminal; }; #endif diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 8a8aadc54..7e5e4e70f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -885,7 +885,8 @@ cmMakefile::AddCustomCommandToTarget(const std::string& target, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, - bool escapeOldStyle) const + bool escapeOldStyle, + bool uses_terminal) const { // Find the target to which to add the custom command. cmTargets::iterator ti = this->Targets.find(target); @@ -941,6 +942,7 @@ cmMakefile::AddCustomCommandToTarget(const std::string& target, commandLines, comment, workingDir); cc.SetEscapeOldStyle(escapeOldStyle); cc.SetEscapeAllowMakeVars(true); + cc.SetUsesTerminal(uses_terminal); switch(type) { case cmTarget::PRE_BUILD: @@ -964,7 +966,8 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle) + bool escapeOldStyle, + bool uses_terminal) { // Make sure there is at least one output. if(outputs.empty()) @@ -1071,6 +1074,7 @@ cmMakefile::AddCustomCommandToOutput(const std::vector& outputs, comment, workingDir); cc->SetEscapeOldStyle(escapeOldStyle); cc->SetEscapeAllowMakeVars(true); + cc->SetUsesTerminal(uses_terminal); file->SetCustomCommand(cc); this->UpdateOutputToSourceMap(outputs, file); } @@ -1119,13 +1123,15 @@ cmMakefile::AddCustomCommandToOutput(const std::string& output, const char* comment, const char* workingDir, bool replace, - bool escapeOldStyle) + bool escapeOldStyle, + bool uses_terminal) { std::vector outputs; outputs.push_back(output); return this->AddCustomCommandToOutput(outputs, depends, main_dependency, commandLines, comment, workingDir, - replace, escapeOldStyle); + replace, escapeOldStyle, + uses_terminal); } //---------------------------------------------------------------------------- @@ -1242,7 +1248,8 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName, const char* workingDirectory, const std::vector& depends, const cmCustomCommandLines& commandLines, - bool escapeOldStyle, const char* comment) + bool escapeOldStyle, const char* comment, + bool uses_terminal) { // Create a target instance for this utility. cmTarget* target = this->AddNewTarget(cmTarget::UTILITY, utilityName); @@ -1269,7 +1276,7 @@ cmMakefile::AddUtilityCommand(const std::string& utilityName, no_main_dependency, commandLines, comment, workingDirectory, no_replace, - escapeOldStyle); + escapeOldStyle, uses_terminal); cmSourceFile* sf = target->AddSourceCMP0049(force); // The output is not actually created so mark it symbolic. diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 824513ba4..73c299e0d 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -174,7 +174,8 @@ public: const cmCustomCommandLines& commandLines, cmTarget::CustomCommandType type, const char* comment, const char* workingDir, - bool escapeOldStyle = true) const; + bool escapeOldStyle = true, + bool uses_terminal = false) const; cmSourceFile* AddCustomCommandToOutput( const std::vector& outputs, const std::vector& depends, @@ -182,7 +183,8 @@ public: const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, - bool escapeOldStyle = true); + bool escapeOldStyle = true, + bool uses_terminal = false); cmSourceFile* AddCustomCommandToOutput( const std::string& output, const std::vector& depends, @@ -190,7 +192,8 @@ public: const cmCustomCommandLines& commandLines, const char* comment, const char* workingDir, bool replace = false, - bool escapeOldStyle = true); + bool escapeOldStyle = true, + bool uses_terminal = false); void AddCustomCommandOldStyle(const std::string& target, const std::vector& outputs, const std::vector& depends, @@ -237,7 +240,8 @@ public: const std::vector& depends, const cmCustomCommandLines& commandLines, bool escapeOldStyle = true, - const char* comment = 0); + const char* comment = 0, + bool uses_terminal = false); /** * Add a link library to the build. diff --git a/Tests/CustomCommand/CMakeLists.txt b/Tests/CustomCommand/CMakeLists.txt index b97cd1642..e2600705d 100644 --- a/Tests/CustomCommand/CMakeLists.txt +++ b/Tests/CustomCommand/CMakeLists.txt @@ -483,3 +483,26 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E touch "${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 +) diff --git a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake index a69260084..d0f429af8 100644 --- a/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_command/RunCMakeTest.cmake @@ -6,3 +6,4 @@ run_cmake(BadArgument) run_cmake(NoArguments) run_cmake(NoOutputOrTarget) run_cmake(OutputAndTarget) +run_cmake(SourceUsesTerminal) diff --git a/Tests/RunCMake/add_custom_command/SourceUsesTerminal-result.txt b/Tests/RunCMake/add_custom_command/SourceUsesTerminal-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/SourceUsesTerminal-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_custom_command/SourceUsesTerminal-stderr.txt b/Tests/RunCMake/add_custom_command/SourceUsesTerminal-stderr.txt new file mode 100644 index 000000000..1a76c549f --- /dev/null +++ b/Tests/RunCMake/add_custom_command/SourceUsesTerminal-stderr.txt @@ -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\) diff --git a/Tests/RunCMake/add_custom_command/SourceUsesTerminal.cmake b/Tests/RunCMake/add_custom_command/SourceUsesTerminal.cmake new file mode 100644 index 000000000..295fab141 --- /dev/null +++ b/Tests/RunCMake/add_custom_command/SourceUsesTerminal.cmake @@ -0,0 +1 @@ +add_custom_command(SOURCE t TARGET t USES_TERMINAL) diff --git a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake index 4e4a8ae98..a612da98f 100644 --- a/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake +++ b/Tests/RunCMake/add_custom_target/RunCMakeTest.cmake @@ -2,3 +2,4 @@ include(RunCMake) run_cmake(NoArguments) run_cmake(BadTargetName) +run_cmake(UsesTerminalNoCommand) diff --git a/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-result.txt b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-stderr.txt b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-stderr.txt new file mode 100644 index 000000000..beafa7cbf --- /dev/null +++ b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-stderr.txt @@ -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\) diff --git a/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand.cmake b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand.cmake new file mode 100644 index 000000000..b0c207b42 --- /dev/null +++ b/Tests/RunCMake/add_custom_target/UsesTerminalNoCommand.cmake @@ -0,0 +1 @@ +add_custom_target(MyTarget USES_TERMINAL)