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.
This commit is contained in:
Brad King 2011-04-08 10:40:57 -04:00
parent a961ecdad0
commit 06fcbc4757
4 changed files with 35 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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