Create pre and post-build event scripts enough?


I have some moderately hefty pre- and post-build event scripts for my Visual Studio 2008 projects (actually it's mainly post-build event scripts). They work OK in that they function correctly and when I exit 0 the build succeeds and when I exit 1 the build fails with an error. However, that error is enormous, and goes something like this:

The command "if Release == Debug goto Foo
if Release == Release goto Bar
exit 0

mkdir "abc"
copy "$(TargetDir)file.dll" "abc"
" exited with code 1.

You get the idea. The entire script is always dumped out as part of the error description. The entire script is also dumped out in the Output window while the build is happening, too. So, why have I seen various references on the web to using echo in these scripts? For example, here's part of an example on one particular site:

echo POSTBUILDSTEP for $(ProjectName) FAILED
exit 1

Is there a way to get Visual Studio to suppress all script output apart from what is echoed (and therefore using echo only to output what you want would make sense), or are these examples just misguided and they don't realize that the whole script is always dumped out?

OK - the core of the issue seems to be that the Visual Studio C++ and C# build engines are quite different.

The C++ build engine executes the batch code specified in the project's pre- or post-build event 'Command Line' without dumping the actual code to the Output window; it just dumps out what is echoed by the code, as well as what is sent out by commands the code executes (such as the copy command's '2 file(s) copied', etc.) The examples I've seen around the web are presumably intended for Visual Studio's C++ build engine, because there is no need really to echo anything with the C# build engine if you're putting your C# pre- or post-build batch code in the C# project's 'event command line' box.

This is because the C# build engine, which I was using, does dump all the code in that box to the Output window. Whatsmore, if the code fails, it includes the entire code block in that box in the error message that will appear in 'Error List' - the C++ build engine doesn't (more on that later).

The best solution I've found, therefore, is to minimize the amount of code you put in a C# project's pre- or post-build event command line box. Everything you put in there WILL be dumped to the Output window as it is executed. The best way to minimize the code there is to make it just execute a batch file, and pass the necessary arguments to the batch file. The contents of the batch file will NOT be dumped to the Output window, but (like with code in the 'Command Line' for the C++ build engine) echo output and output from commands the batch file code executes will be; this is a good way to control the output of a C# pre- or post-build script. The C++ build engine, then, is treating the code specified in the 'Command Line' box in the same way as the C# engine treats code in a batch file; it doesn't dump out the code itself, just the code's output.

So basically, if you're compiling a C++ project in Visual Studio, you can just put all the batch script in the 'Command Line' box and it won't all be dumped to the Output window. If compiling a C# project, though, I recommend putting your batch script in a separate .bat file, and just calling that file with the appropriate arguments from the pre- or post-build event command line box. I ended up with my C# post-build event command line box looking like this:

..\..\BuildScripts\PostBuild.bat $(ConfigurationName) $(ProjectName) "$(TargetDir)" "$(ProjectDir)"

... and my PostBuild.bat file looking like this:

@REM Store args...
set _configName=%1%
set _projectName=%2%

@REM Remove quotes from remaining args...
set _targetDir=###%3%###
set _targetDir=%_targetDir:"###=%
set _targetDir=%_targetDir:###"=%
set _targetDir=%_targetDir:###=%

set _projectDir=###%4%###
set _projectDir=%_projectDir:"###=%
set _projectDir=%_projectDir:###"=%
set _projectDir=%_projectDir:###=%

if %_configName% == Release goto StartProcessing
echo No post-build processing required.
exit 0

@REM Start post-build processing
echo Starting post-build processing.

@REM use input args to do batch script work, such as:
copy "%_targetDir%*.dll" "%_projectDir%..\..\..\..\..\CommonAssemblies"
if errorlevel 1 goto CopyFailure

@REM etc.

goto PostBuildSuccess

@REM Failure labels
echo Post-build processing for %_projectName% FAILED: Failed to copy file(s) to common assemblies directory!
exit 1

@REM Post-build success
echo Post-build processing for %_projectName% completed OK.
exit 0

This controls the output much more neatly, and only things echoed in this batch script will be output to the Output window.

Finally, as mentioned above, the C# and C++ build engines also output different things in the error message that appears in 'Error List', when post-build processing fails (ie. the batch code exits with a code other than 0). The C++ build engine always seems to just say:

Error result 1 returned from 'C:\Windows\system32\cmd.exe'.

The C# build engine, however, will include the whole contents of the pre- or post-build event command line box (whichever failed) in the error message, eg.:

The command "..\..\BuildScripts\PostBuild.bat Release MyProject "C:\Development\MyProject\bin\" "C:\Development\MyProject\"" exited with code 1.

Still a bit of a mouthful for a single error message, but much more manageable than having all of the code we moved into the batch file included in the error message!

Even so, it would be nice to be able to customize this error message that appears in the Error List to display something I define. I doubt it's possible, but if anybody knows of a way to do this, please don't hesitate to post it as a comment!