Compartilhar via


Executar um destino exatamente uma vez

Se você estiver criando um projeto .NET para várias frameworks usando multitargeting do SDK do .NET, geralmente cada build é um build completo de todos os destinos relevantes. No entanto, em alguns casos, você deseja que um determinado destino seja executado apenas uma vez, por exemplo, um destino que incremente uma versão.

Configurar os alvos

A solução mostrada aqui executa o MyBeforeBuildTarget uma vez e uma única vez, independentemente de um único framework estar sendo criado ou se vários frameworks estão sendo criados, sem uma alteração no próprio destino.

  1. Adicione Condition expressões que usam a Multitarget propriedade para decidir se devem ser criadas várias estruturas ou apenas uma.

    <PropertyGroup>
     <TargetFrameworks Condition=" '$(Multitarget)' == 'true' ">net7.0;net8.0</TargetFrameworks>
     <TargetFramework  Condition=" '$(Multitarget)' != 'true' ">net8.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
     <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
    </PropertyGroup>
    
  2. Adicione três destinos ao projeto: o que você deseja executar apenas uma vez (MyBeforeBuildTarget) e os outros dois, conforme mostrado aqui.

    <Project Sdk="Microsoft.NET.Sdk">
    
    <PropertyGroup>
        <TargetFrameworks Condition=" '$(Multitarget)' == 'true' ">net7.0;net8.0</TargetFrameworks>
        <TargetFramework  Condition=" '$(Multitarget)' != 'true' ">net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
    </PropertyGroup>
    
    <Target Name="MyBeforeBuildTarget">
        <Warning Text="MyBeforeBuildTarget" />
    </Target>
    
    <Target Name="BuildMyBeforeBuildTargetBeforeOuterBuild"
            DependsOnTargets="MyBeforeBuildTarget"
            BeforeTargets="DispatchToInnerBuilds"
            />
    
    <Target Name="BuildMyBeforeBuildTargetBeforeInnerBuild"
            BeforeTargets="BeforeBuild">
       <MSBuild Projects="$(MSBuildProjectFullPath)"
             Targets="MyBeforeBuildTarget"
             RemoveProperties="TargetFramework" />
    </Target>
    
    </Project>
    

Esse método depende da maneira como o multitargeting funciona em projetos do SDK do .NET. Os builds externos definem TargetFrameworks, enquanto os builds internos definem TargetFramework para cada alvo desejado. Portanto, para compilar uma vez para o build interno, remova a TargetFramework propriedade. Isso invoca a compilação externa com o destino desejado ao invés de executá-la em cada uma das compilações internas.

Compilar o projeto

  1. Na linha de comando, compile sem multitargeting:

    dotnet msbuild -nologo -tl:false -bl -clp:nosummary -p:Multitarget=false

    ExtendMaybeMultitargeted.csproj(12,5): warning : MyBeforeBuildTarget
    ExtendMaybeMultitargeted -> ExtendMaybeMultitargeted\bin\Debug\net8.0\ExtendMaybeMultitargeted.dll
    
  2. Agora tente criar com multitargeting:

    dotnet msbuild -nologo -tl:false -bl -clp:nosummary -p:Multitarget=true

    ExtendMaybeMultitargeted\ExtendMaybeMultitargeted.csproj(12,5): warning : MyBeforeBuildTarget
      ExtendMaybeMultitargeted -> ExtendMaybeMultitargeted\bin\Debug\net8.0\ExtendMaybeMultitargeted.dll
      ExtendMaybeMultitargeted -> ExtendMaybeMultitargeted\bin\Debug\net7.0\ExtendMaybeMultitargeted.dll
    

Como você pode ver na saída, o aviso só foi emitido uma vez, independentemente de o multitargeting ter sido usado ou não.

A solução mostrada aqui funciona porque o destino ao qual você deseja executar uma vez, MyBeforeBuildTargetestá vinculado a um destino diferente usando BeforeTargets, mas independentemente de o multitargeting ser verdadeiro ou falso, o destino ao qual ele está anexado é sempre um que é executado uma vez. O build externo é um único destino, DispatchToInnerBuilds que executa o build interno para todos os diferentes frameworks especificados em TargetFrameworks; DispatchToInnerBuilds é executado apenas uma vez para um build multissegmentado, mas para um único build direcionado, ele não é executado. Para um único build direcionado, você configura BeforeTargets para BeforeBuild como de costume para rodar seu alvo, mas Condition assegura que ele esteja anexado a BeforeBuild apenas no caso de alvo único.

Multialvo do SDK do .NET