这与“AfterBuild”目标(由“Microsoft.CSharp.targets”公开)相关联作为依赖项:
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
如果构建实际上没有重新构建,有没有办法避免文件被复制?
例如,当MSBuild依赖分析断言项目不需要构建,因为它的源文件没有更新时,它不会构建,但仍会执行我的复制目标。有没有办法防止这种情况发生?
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
如果构建实际上没有重新构建,有没有办法避免文件被复制?
例如,当MSBuild依赖分析断言项目不需要构建,因为它的源文件没有更新时,它不会构建,但仍会执行我的复制目标。有没有办法防止这种情况发生?
我刚刚谷歌搜索了这个问题,并找到了几年前的答案。我发现可以通过从核心目标中借鉴一个想法来更轻松地完成此操作。覆盖BeforeBuild和AfterBuild,然后执行以下操作:
<Target Name="BeforeBuild">
<PropertyGroup>
<MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime)
</MyBeforeCompileTimestamp>
</PropertyGroup>
</Target>
<Target Name="AfterBuild">
<CallTarget Condition="$(MyBeforeCompileTimestamp) !=
%(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" />
</Target>
由于你覆盖了 AfterBuild 目标,它将始终在构建之后执行。这适用于重建或正常构建。如果你想在重建后执行一些操作(而不是构建),那么你应该扩展 Rebuild 目标的依赖属性。因此,在你的情况下,为了在重建发生后注入目标,你的项目文件应该类似于:
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<RebuildDependsOn>
$(RebuildDependsOn);
InstallUtil;
CopyPostBuildFiles
</RebuildDependsOn>
</PropertyGroup>
</Project>
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomAfterBuild;
</BuildDependsOn>
</PropertyGroup>
<Target Name="CustomAfterBuild" Inputs="$(MSBuildAllProjects);
@(Compile);
@(_CoreCompileResourceInputs);
$(ApplicationIcon);
$(AssemblyOriginatorKeyFile);
@(ReferencePath);
@(CompiledLicenseFile);
@(EmbeddedDocumentation);
$(Win32Resource);
$(Win32Manifest);
@(CustomAdditionalCompileInputs)"
Outputs="@(DocFileItem);
@(IntermediateAssembly);
@(_DebugSymbolsIntermediatePath);
$(NonExistentFile);
@(CustomAdditionalCompileOutputs)">
<!-- Content here -->
</Target>
</Project>
在编译目标中使用输入和输出目标属性,那么使用它们有何不同呢?
<PropertyGroup>
<PostBuildDir>CopiedFilesDirectory</PostBuildDir>
</PropertyGroup>
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
<Target Name="CopyPostBuildFiles"
Inputs="@(PostBuildFiles)"
Outputs="@(PostBuildFiles -> '$(PostBuildDir)%(Filename)%(Extension)'">
<Copy SourceFiles="@(PostBuildFiles)"
DestinationFolder="PostBuildDir"/>
</Target>
只有在项目目标文件已经重建的情况下,才会调用AfterBuild目标:
<Target Name="AfterBuild"
DependsOnTargets="InstallUtil;CopyPostBuildFiles"
Inputs="$(TargetPath)"
Outputs="$(DeployPath)\$(TargetFileName)" />
这假设您已经定义了一个属性$(DeployPath)
,该属性标识了您复制目标输出文件的文件夹。
这个怎么样?
- BuildBreak。当编译错误发生时设置为true,否则为false。可以在构建中断目标中使用,以确定它们是在编译错误后执行还是正常执行。
http://blogs.msdn.com/aaronhallberg/archive/2008/02/12/team-build-2008-property-reference.aspx
我没有尝试过,但听起来非常有前途。
构建目标定义是:
<Target Name = "Build" DependsOnTargets="BeforeBuild;CoreBuild;AfterBuild"/>
<Target Name="AfterCompile" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
关于MSBuild,我不是很了解,但在C#中,对于Visual Studio使用的MSBuild项目,有一个简单的替代方案:使用后生成事件(Post-build build event)而不是AfterBuild目标。
您可以通过Visual Studio项目属性对话框上的第三个选项卡“生成事件”设置后生成事件。对于某些情况,可能需要在此对话框中输入一些命令,然后在确定其工作方式后直接编辑.csproj文件。
记得在对话框上选择“运行此后生成事件:当生成更新项目输出时”-这是获得OP要求的功能的关键。
就像我说的那样,我不太了解MSBuild,后生成事件可能不适用于一些AfterBuild目标所能做的事情。但我已经将其用于复制文件和运行BAT脚本,效果很好。
编辑:
我会添加一些关于如何在我的C#项目中通常使用后生成事件的注释。
为了分离不同的功能区域,我通常创建一个名为PostBuildEvent.bat的BAT脚本,并将其放置在与.csproj文件相同的文件夹中。然后我的后生成事件只包含两行:
cd $(ProjectDir)
PostBuildEvent.bat
然后我将想要的命令放在PostBuildEvent.bat文件中。这是一个例子:
copy "..\..\..\..\..\Shared Bin\Merlinia.CommonClasses.NamedPipesNative.dll" bin
copy "..\..\..\..\..\Shared Bin\Merlinia.CommonClasses.NamedPipesNative.pdb" bin
cd Packed-NonObfuscated
call PackForWindowsSystem32-NonObfuscated.bat
cd ..\
cd Packed-Obfuscated
call PackForWindowsSystem32-Obfuscated.bat
cd ..\
pause
请记住,要从BAT脚本中调用另一个BAT脚本,您需要显式指定“call”。还要注意使用“pause” - 这使得通过双击BAT文件测试脚本成为可能,然后您可以在cmd窗口中查看任何错误消息。当通过MSBuild运行脚本时,“pause”将被忽略。