Подавление целей AfterBuild, когда csproj не был построен - PullRequest
8 голосов
/ 05 февраля 2009

У меня есть цель после сборки в MSBuild для копирования некоторых результатов сборки.

Это связано как зависимость с целью AfterBuild (отображается Microsoft.CSharp.targets):

<Target Name="AfterBuild" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />

Есть ли способ избежать копирования файлов, если сборка фактически не перестраивается?

Например, когда анализ зависимостей MSBuild утверждает, что проект не нужно создавать, поскольку ни один из его исходных файлов не был обновлен, он не собирается, но все еще выполняет мою цель копирования. Есть ли способ предотвратить это?

Ответы [ 7 ]

8 голосов
/ 13 декабря 2012

Я только что погуглил и нашел ответ этого года. Я нашел способ сделать это немного проще, украдя идею из основных целей. Переопределите и BeforeBuild, и AfterBuild и сделайте что-то вроде:

  <Target Name="BeforeBuild">
    <PropertyGroup>
      <MyBeforeCompileTimestamp>%(IntermediateAssembly.ModifiedTime)
                 </MyBeforeCompileTimestamp>
    </PropertyGroup>
  </Target>

  <Target Name="AfterBuild">
    <CallTarget Condition="$(MyBeforeCompileTimestamp) !=   
          %(IntermediateAssembly.ModifiedTime)" Targets="MyTarget" /> 
  </Target>
7 голосов
/ 21 декабря 2009

Поскольку вы переопределяете цель 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 попытается выполнить его всякий раз, когда проект будет собран.

6 голосов
/ 06 февраля 2009

Как насчет использования свойств цели Inputs и Outputs, как это сделано в цели компиляции.

<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 .

См. Эту страницу для получения дополнительной информации о Targets Inputs Outputs

0 голосов
/ 07 июня 2016

Это вызовет цель AfterBuild тогда и только тогда, когда целевой файл проекта был перестроен:

<Target Name="AfterBuild"
    DependsOnTargets="InstallUtil;CopyPostBuildFiles"
    Inputs="$(TargetPath)"
    Outputs="$(DeployPath)\$(TargetFileName)" />

Предполагается, что вы определили свойство $(DeployPath), которое определяет папку, в которую вы скопировали целевой выходной файл.

0 голосов
/ 08 марта 2013

Я не знаю много о MSBuild, но в случае проектов MSBuild, используемых Visual Studio для C #, есть простая альтернатива: используйте событие сборки Post-build вместо цели AfterBuild.

Вы можете настроить событие сборки после сборки через диалоговое окно свойств проекта Visual Studio на третьей вкладке «События сборки». В некоторых ситуациях может быть целесообразно ввести некоторые команды в этом диалоговом окне, а затем отредактировать файл .csproj, как только вы определите, как он работает.

Не забудьте выбрать «Запускать это событие после сборки: когда сборка обновляет выходные данные проекта» в этом диалоговом окне - это ключ к получению функциональности, запрошенной OP.

Как я уже сказал, я мало что знаю о MSBuild, и может случиться так, что событие пост-сборки не применимо для некоторых вещей, которые может сделать цель AfterBuild. Но я использовал его для копирования файлов и запуска скриптов BAT, и для этого он отлично работает.

EDIT:

Я добавлю несколько заметок о том, как я обычно использую события после сборки в своих проектах на C #.

Чтобы разделить различные области функциональности, я обычно создаю BAT-скрипт с именем PostBuildEvent.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.

0 голосов
/ 06 февраля 2009

Что насчёт этого.

  • BuildBreak . Установите в значение true, когда происходит ошибка компиляции, в противном случае ложный. Может быть использован в перерыве сборки цели, чтобы определить, являются ли они выполнение после ошибки компиляции или выполняется нормально.

http://blogs.msdn.com/aaronhallberg/archive/2008/02/12/team-build-2008-property-reference.aspx

Я не пробовал, но звучит довольно многообещающе.

0 голосов
/ 05 февраля 2009

Определение цели сборки:

<Target Name = "Build" DependsOnTargets="BeforeBuild;CoreBuild;AfterBuild"/>

Я думаю, что CoreBuild не выполняется, если ваши файлы не изменились, поэтому вы можете попробовать использовать AfterCompile вместо AfterBuild.

<Target Name="AfterCompile" DependsOnTargets="InstallUtil;CopyPostBuildFiles" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...