Поскольку вы переопределяете цель AfterBuild, она всегда будет выполняться после сборки. Это случай перестроения или нормальной сборки. Если вы хотите выполнить некоторые действия после перестроения (а не сборки), вам следует расширить свойство зависимостей для цели перестроения. Таким образом, в вашем случае для внедрения целей после перестройки файл вашего проекта должен выглядеть примерно так:
<Project ...>
<!-- some content here -->
<Import Project="... Microsoft.Csharp.targets" />
<PropertyGroup>
<RebuildDependsOn>
$(RebuildDependsOn);
InstallUtil;
CopyPostBuildFiles
</RebuildDependsOn>
</PropertyGroup>
</Project>
Этот метод расширяет свойство, которое использует цели Rebuild, чтобы объявить, от каких целей он зависит. Я подробно рассказал об этом в статье Внутри MSBuild , см. Раздел Расширение процесса сборки .
Кроме того, цель, которую вы пытаетесь выполнить, может быть достигнута целью AfterBuild, если вы можете указать, какие файлы будут « вызывать » для обновления. Другими словами, вы можете указать набор «входов» в цель и набор «выходов», которые оба являются файлами. Если все выходы были созданы после всех входов, то цель будет считаться актуальной и пропущена. эта концепция известна как Постепенное построение, и я освещал ее в статье Лучшая практика MSBuild, часть 2 . Также я подробно описал это в своей книге Внутри Microsoft Build Engine: использование MSBuild и Team Foundation Build .
РЕДАКТИРОВАТЬ: Добавление BuildDependsOn пример
Если вы хотите, чтобы цель выполнялась только тогда, когда файлы фактически собраны, а не только когда цель Rebuild выполняется. Затем вы должны создать свой проект, подобный следующему:
<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>
Я просто скопировал входы и выходы из цели CoreCompile внутри Microsoft.CSharp.targets ( Я предполагаю, что вы используете C # здесь ) и вставил ее здесь. Это означает, что цель будет пропущена при выполнении цели CoreCompile . Кроме того, поскольку я расширил BuildDependsOn, мы знаем, что MSBuild попытается выполнить его всякий раз, когда проект будет собран.