我的Visual Studio 2008项目有一些适度的构建前和构建后的事件脚本(实际上它主要是构建后的事件脚本)。它们工作正常,因为它们正常运行,当我exit 0
构建成功时,当exit 1
构建失败并出现错误时。但是,这个错误是巨大的,并且是这样的:
The command "if Release == Debug goto Foo
if Release == Release goto Bar
exit 0
:Foo
mkdir "abc"
copy "$(TargetDir)file.dll" "abc"
[...]
" exited with code 1.
你明白了。整个脚本始终作为错误描述的一部分转出。在构建发生时,整个脚本也会在“输出”窗口中转储出来。那么,为什么我在Web上看到了在这些脚本中使用echo
的各种引用?例如,这是一个特定网站上的示例的一部分:
:BuildEventFailed
echo POSTBUILDSTEP for $(ProjectName) FAILED
exit 1
:BuildEventOK
echo POSTBUILDSTEP for $(ProjectName) COMPLETED OK
有没有办法让Visual Studio除了echo
之外的所有脚本输出(因此只使用echo
输出你想要的内容),或者是这些例子只是被误导了,他们没有意识到整个剧本总是被抛弃?
答案 0 :(得分:8)
好的 - 问题的核心似乎是Visual Studio C ++和C#构建引擎完全不同。
C ++构建引擎执行项目的构建前或构建后事件“命令行”中指定的批处理代码,而不用将实际代码转储到“输出”窗口;它只是转出代码echo
的内容,以及代码执行的命令发送的内容(例如copy
命令的'2个文件被复制'等。)我在Web上看到的示例可能是针对Visual Studio的C ++构建引擎的,因为如果您将C#构建前或构建后的批处理代码放在C#构建引擎中,则无需真正回应任何内容。 C#项目的'事件命令行'框。
这是因为我正在使用的C#构建引擎 将该框中的所有代码转储到“输出”窗口。更重要的是,如果代码失败,它会在错误消息中的该框中包含整个代码块,该错误消息将显示在“错误列表”中 - C ++构建引擎不会(稍后会详细介绍)。
因此,我发现的最佳解决方案是最小化您在C#项目的构建前或构建后事件命令行框中放入的代码量。放在那里的所有东西都会在执行时被转储到Output窗口。最小化代码的最佳方法是使其只执行批处理文件,并将必要的参数传递给批处理文件。批处理文件的内容不会被转储到“输出”窗口,但是(与C ++构建引擎的“命令行”中的代码一样)echo
批处理文件代码执行的命令的输出和输出将是;这是控制C#预构建或后构建脚本输出的好方法。然后,C ++构建引擎正在处理“命令行”框中指定的代码,其方式与C#引擎处理批处理文件中的代码的方式相同;它不会转储代码本身,只会转储代码的输出。
所以基本上,如果您在Visual Studio中编译C ++项目,您可以将所有批处理脚本放在“命令行”框中,并且不会将它们全部转储到“输出”窗口。但是,如果要编译C#项目,我建议将批处理脚本放在单独的.bat
文件中,并使用构建前或构建后事件命令行框中的相应参数调用该文件。我最终得到了我的C#post-build事件命令行框,如下所示:
..\..\BuildScripts\PostBuild.bat $(ConfigurationName) $(ProjectName) "$(TargetDir)" "$(ProjectDir)"
...和我的PostBuild.bat文件看起来像这样:
@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
:StartProcessing
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
:CopyFailure
echo Post-build processing for %_projectName% FAILED: Failed to copy file(s) to common assemblies directory!
exit 1
@REM Post-build success
:PostBuildSuccess
echo Post-build processing for %_projectName% completed OK.
exit 0
这样可以更加整齐地控制输出,只有此批处理脚本中的echo
内容才会输出到“输出”窗口。
最后,如上所述,当构建后处理失败时,C#和C ++构建引擎也会在“错误列表”中显示的错误消息中输出不同的内容(即,批处理代码以除{以外的代码退出{1}})。 C ++构建引擎似乎总是说:
0
但是,C#构建引擎将在错误消息中包含构建前或构建后事件命令行框的整个内容(以较少者为准),例如:
Error result 1 returned from 'C:\Windows\system32\cmd.exe'.
对于单个错误消息仍然有点满口,但比将我们移入批处理文件中的所有代码包含在错误消息中更容易管理!
即便如此,能够自定义错误列表中显示的此错误消息以显示我定义的内容会更好。我怀疑这是可能的,但如果有人知道如何做到这一点,请不要犹豫,将其作为评论发布!
答案 1 :(得分:5)
如果你把你的脚本放在一个批处理文件中,VS对此非常沉默。当您需要访问$(projectName)等时,您必须将它们作为参数传递给批处理文件。我查找了可能影响输出但无法找到任何设置的设置。
使用此批处理文件(d:\ test.bat)进行测试;甚至不需要 @echo off :
@echo off
echo "I'm Gonna Fail"
exit 1
将Pre-Build Event->Command Line
设置为 d:\ test.bat ,将Description
保留为空(说明是显示的而不是执行预建事件... 。在VS2008中,我在C ++项目的构建输出窗口中得到了它:
Performing Pre-Build Event...
"I'm Gonna Fail"
Project : error PRJ0002 : Error result 1 returned from 'C:\Windows\system32\cmd.exe'.
对于C#项目,显示的是(MSBuild verbosity
设置为正常):
Target PreBuildEvent:
d:\test.bat
"I'm gonna fail"
Microsoft.Common.targets(895,9) error MSB3073: The command "d:\test.bat" exited with code 1.
答案 2 :(得分:1)
@Jez你的答案很棒,但我会改进批处理文件如下: 通过使用%~1,它将更容易从args中删除引号:
@echo off
if "%~1"=="" (set ErrorMessage=Parameter 1 missing. It has to be the Config name. & GOTO :EndError)
if "%~2"=="" (set ErrorMessage=Parameter 2 missing. It has to be the Project name. & GOTO :EndError)
if "%~3"=="" (set ErrorMessage=Parameter 3 missing. It has to be the Targetdir. & GOTO :EndError)
if "%~4"=="" (set ErrorMessage=Parameter 4 missing. It has to be the Projectdir. & GOTO :EndError)
cd /D "%~dp0" &:: setting current directory to there where the batchfile is.
:: With ~ the quotes are removed
set _configName=%~1
set _projectName=%~2
set _targetDir=%~3
set _projectDir=%~4
set _outDir=%~5
rd Plugins\%_projectName% /S /Q
if errorlevel 1 (set ErrorMessage=remove directory failed!!. & GOTO :EndError)
md Plugins\%_projectName%
if errorlevel 1 (set ErrorMessage=make directory failed!!. & GOTO :EndError)
xcopy %_targetDir%* Plugins\%_projectName% /E /Q
if errorlevel 1 (set ErrorMessage=Copy failed!!. & GOTO :EndError)
exit 0
:EndError
echo --! Error in %~nx0 !--
echo %ErrorMessage%
pause
exit 1