Ver Fonte

VS10: Fix working directory of consecutive custom commands (#11938)

The VS 10 msbuild tool uses a single command shell to invoke all the
custom command scripts in a project.  Isolate the environment and
working directory of custom commands using setlocal/endlocal.  The
form of each command is

  set errlev=
  setlocal
  cd c:\work\dir
  if %errorlevel% neq 0 goto :cmEnd
  c:
  if %errorlevel% neq 0 goto :cmEnd
  command1 ...
  if %errorlevel% neq 0 goto :cmEnd
  ...
  commandN ...
  if %errorlevel% neq 0 goto :cmEnd
  :cmEnd
  endlocal & set errlev=%errorlevel%
  if %errlev% neq 0 goto :VCEnd

so that all changes to the environment and working directory are
isolated within the script and the return code is preserved.
Brad King há 14 anos atrás
pai
commit
06fcbc4757

+ 2 - 2
Source/cmLocalVisualStudio10Generator.cxx

@@ -119,7 +119,7 @@ void cmLocalVisualStudio10Generator
 }
 
 //----------------------------------------------------------------------------
-std::string cmLocalVisualStudio10Generator::CheckForErrorLine()
+const char* cmLocalVisualStudio10Generator::ReportErrorLabel() const
 {
-  return "if errorlevel 1 goto :VCEnd";
+  return ":VCEnd";
 }

+ 1 - 1
Source/cmLocalVisualStudio10Generator.h

@@ -38,7 +38,7 @@ public:
                                         const char* path);
 
 protected:
-  virtual std::string CheckForErrorLine();
+  virtual const char* ReportErrorLabel() const;
 
 private:
 };

+ 28 - 14
Source/cmLocalVisualStudioGenerator.cxx

@@ -154,15 +154,15 @@ void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements
 }
 
 //----------------------------------------------------------------------------
-std::string cmLocalVisualStudioGenerator::CheckForErrorLine()
+const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const
 {
-  return "if errorlevel 1 goto :VCReportError";
+  return ":VCReportError";
 }
 
 //----------------------------------------------------------------------------
-std::string cmLocalVisualStudioGenerator::GetCheckForErrorLine()
+const char* cmLocalVisualStudioGenerator::GetReportErrorLabel() const
 {
-  return this->CheckForErrorLine();
+  return this->ReportErrorLabel();
 }
 
 //----------------------------------------------------------------------------
@@ -170,35 +170,43 @@ std::string
 cmLocalVisualStudioGenerator
 ::ConstructScript(cmCustomCommand const& cc,
                   const char* configName,
-                  const char* newline_text)
+                  const char* newline)
 {
   const cmCustomCommandLines& commandLines = cc.GetCommandLines();
   const char* workingDirectory = cc.GetWorkingDirectory();
   cmCustomCommandGenerator ccg(cc, configName, this->Makefile);
   RelativeRoot relativeRoot = workingDirectory? NONE : START_OUTPUT;
 
-  // Avoid leading or trailing newlines.
-  const char* newline = "";
+  // Line to check for error between commands.
+  std::string check_error = newline;
+  check_error += "if %errorlevel% neq 0 goto :cmEnd";
 
   // Store the script in a string.
   std::string script;
+
+  // Open a local context.
+  script += "set errlev=";
+  script += newline;
+  script += "setlocal";
+
   if(workingDirectory)
     {
     // Change the working directory.
     script += newline;
-    newline = newline_text;
     script += "cd ";
     script += this->Convert(workingDirectory, FULL, SHELL);
+    script += check_error;
 
     // Change the working drive.
     if(workingDirectory[0] && workingDirectory[1] == ':')
       {
       script += newline;
-      newline = newline_text;
       script += workingDirectory[0];
       script += workingDirectory[1];
+      script += check_error;
       }
     }
+
   // for visual studio IDE add extra stuff to the PATH
   // if CMAKE_MSVCIDE_RUN_PATH is set.
   if(this->Makefile->GetDefinition("MSVC_IDE"))
@@ -208,18 +216,17 @@ cmLocalVisualStudioGenerator
     if(extraPath)
       {
       script += newline;
-      newline = newline_text;
       script += "set PATH=";
       script += extraPath;
       script += ";%PATH%";
       }
     }
+
   // Write each command on a single line.
   for(unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c)
     {
     // Start a new line.
     script += newline;
-    newline = newline_text;
 
     // Add this command line.
     std::string cmd = ccg.GetCommand(c);
@@ -230,10 +237,17 @@ cmLocalVisualStudioGenerator
     // If there was an error, jump to the VCReportError label,
     // skipping the run of any subsequent commands in this
     // sequence.
-    //
-    script += newline_text;
-    script += this->GetCheckForErrorLine();
+    script += check_error;
     }
 
+  // Close the local context.
+  script += newline;
+  script += ":cmEnd";
+  script += newline;
+  script += "endlocal & set errlev=%errorlevel%";
+  script += newline;
+  script += "if %errlev% neq 0 goto ";
+  script += this->GetReportErrorLabel();
+
   return script;
 }

+ 4 - 5
Source/cmLocalVisualStudioGenerator.h

@@ -37,13 +37,12 @@ public:
                               const char* configName,
                               const char* newline = "\n");
 
-  /** Line of batch file text that skips to the end after
-    * a failed step in a sequence of custom commands.
-    */
-  std::string GetCheckForErrorLine();
+  /** Label to which to jump in a batch file after a failed step in a
+      sequence of custom commands. */
+  const char* GetReportErrorLabel() const;
 
 protected:
-  virtual std::string CheckForErrorLine();
+  virtual const char* ReportErrorLabel() const;
 
   /** Construct a custom command to make exe import lib dir.  */
   cmsys::auto_ptr<cmCustomCommand>