我在MSBuild中有一个后期构建目标来复制一些构建输出。
此链接作为AfterBuild
目标的依赖关系(由Microsoft.CSharp.targets
公开):
<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
如果构建实际上没有重新构建,有没有办法避免复制文件?
例如,当MSBuild依赖关系分析声明项目不需要构建因为它的源文件都没有更新时,它不会构建,但仍然执行我的复制目标。有什么方法可以阻止这种情况吗?
答案 0 :(得分:8)
我只是用Google搜索,发现了这个岁月的答案。我找到了一种方法,通过从核心目标中窃取一个想法来更轻松地做到这一点。覆盖BeforeBuild和AfterBuild,并执行以下操作:
<Target Name="BeforeBuild">
<PropertyGroup>
<MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime)
</MyBeforeCompileTimestamp>
</PropertyGroup>
</Target>
<Target Name="AfterBuild">
<CallTarget Condition="$(MyBeforeCompileTimestamp) !=
%(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" />
</Target>
答案 1 :(得分:7)
由于您要覆盖AfterBuild目标,因此它将始终在构建发生后执行。这是重建或正常构建的情况。如果要在重建(而不是构建)之后执行某些操作,则应该扩展Rebuild目标的依赖项属性。因此,在重建发生后注入目标的情况下,项目文件应如下所示:
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<RebuildDependsOn>
$(RebuildDependsOn);
InstallUtil;
CopyPostBuildFiles
</RebuildDependsOn>
</PropertyGroup>
</Project>
此方法扩展了Rebuild目标用于声明其所依赖的目标的属性。我在文章Inside MSBuild中对此进行了详细介绍,请参阅扩展构建过程部分。
如果您可以指定哪些文件将“触发”更新发生,那么AfterBuild目标可能会实现您要完成的任务。换句话说,您可以在目标中指定一组“输入”,并将一组“输出”指定为两个文件。如果所有输出都是在所有输入之后创建的,则目标将被考虑为最新并跳过。这个概念被称为增量构建,我在文章MSBuild Best Practices Part 2中介绍了它。另外,我在我的书Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build中详细说明了这一点。
编辑:添加BuildDependsOn示例
如果希望目标仅在实际构建文件时执行,而不是仅在执行重建目标时执行。然后,您应该将项目创建为如下所示:
<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>
我刚刚复制了Microsoft.CSharp.targets中的 CoreCompile 目标的输入和输出(我假设您在这里使用C#)并将其粘贴到此处。这意味着只要执行 CoreCompile 目标,就会跳过目标。此外,由于我扩展了BuildDependsOn,我们知道无论何时构建项目,MSBuild都会尝试执行它。
答案 2 :(得分:6)
如何使用输入和输出目标的属性,就像在编译目标中完成的那样。
<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>
您可以在 CopyPostBuildFiles 和 InstallUtil 上使用,或直接在 AfterBuild 上使用。
的更多信息,请参阅此页面答案 3 :(得分:0)
构建目标定义是:
<Target Name = "Build" DependsOnTargets="BeforeBuild;CoreBuild;AfterBuild"/>
我认为如果您的文件没有更改,CoreBuild就不会执行,因此您可以尝试使用AfterCompile 而不是AfterBuild。
<Target Name="AfterCompile" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
答案 4 :(得分:0)
这是怎么回事。
- BuildBreak 。当a时设置为true 发生编译错误,否则 假。可用于构建中断 目标是确定它们是否存在 在编译错误或执行后执行 正常执行。
http://blogs.msdn.com/aaronhallberg/archive/2008/02/12/team-build-2008-property-reference.aspx
我没试过,但听起来很有希望。
答案 5 :(得分:0)
当且仅当重建了项目目标文件时,才会调用AfterBuild目标:
<Target Name="AfterBuild"
DependsOnTargets="InstallUtil;CopyPostBuildFiles"
Inputs="$(TargetPath)"
Outputs="$(DeployPath)\$(TargetFileName)" />
这假定您已定义了一个属性$(DeployPath)
,用于标识复制目标输出文件的文件夹。
答案 6 :(得分:-1)
我对MSBuild知之甚少,但对于Visual Studio for C#使用的MSBuild项目,有一个简单的选择:使用Post-build构建事件而不是AfterBuild目标。
您可以通过Visual Studio项目属性对话框在第三个“构建事件”选项卡上设置构建后构建事件。在某些情况下,可能需要在此对话框中输入一些命令,然后在确定其工作原理后直接编辑.csproj文件。
请记住在对话框中选择“运行此构建后事件:构建更新项目输出时” - 这是获取OP请求的功能的关键。
就像我说的,我对MSBuild知之甚少,而且Post-build构建事件可能不适用于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”。另请注意使用“暂停” - 这样可以通过双击BAT文件来测试脚本,然后您可以在cmd窗口中看到任何错误消息。当脚本通过MSBuild运行时,忽略“暂停”。