Browse Source

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.
Peter Collingbourne 11 years ago
parent
commit
fe5d6e8c0f

+ 9 - 2
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 <lang1> depend1
                                       [<lang2> 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

+ 7 - 1
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

+ 12 - 2
Source/cmAddCustomCommandCommand.cxx

@@ -35,6 +35,7 @@ bool cmAddCustomCommandCommand
   std::vector<std::string> 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;

+ 15 - 1
Source/cmAddCustomTargetCommand.cxx

@@ -48,6 +48,7 @@ bool cmAddCustomTargetCommand
   std::vector<std::string> depends;
   std::string working_directory;
   bool verbatim = false;
+  bool uses_terminal = false;
   std::string comment_buffer;
   const char* comment = 0;
   std::vector<std::string> 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);

+ 16 - 1
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;
+}

+ 6 - 0
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<std::string> Outputs;
   std::vector<std::string> Depends;
@@ -90,6 +95,7 @@ private:
   bool EscapeOldStyle;
   cmListFileBacktrace Backtrace;
   ImplicitDependsList ImplicitDepends;
+  bool UsesTerminal;
 };
 
 #endif

+ 13 - 6
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<std::string>& 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<std::string>& 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<std::string> 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<std::string>& 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.

+ 8 - 4
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<std::string>& outputs,
     const std::vector<std::string>& 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<std::string>& 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<std::string>& outputs,
                                 const std::vector<std::string>& depends,
@@ -237,7 +240,8 @@ public:
                               const std::vector<std::string>& 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.

+ 23 - 0
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
+)

+ 1 - 0
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)

+ 1 - 0
Tests/RunCMake/add_custom_command/SourceUsesTerminal-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
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\)

+ 1 - 0
Tests/RunCMake/add_custom_command/SourceUsesTerminal.cmake

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

+ 1 - 0
Tests/RunCMake/add_custom_target/RunCMakeTest.cmake

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

+ 1 - 0
Tests/RunCMake/add_custom_target/UsesTerminalNoCommand-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
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\)

+ 1 - 0
Tests/RunCMake/add_custom_target/UsesTerminalNoCommand.cmake

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