8

I would like to run my powershell script for only one time before the build process. In my mind this should be easily done, simply calling the script before the PreBuildEvent would be OK. Well, it does work for normal projects.

However, for multi-targeting projects,the script would be called multiple times before each build for all the targeting framework.

Here is my project file, in which I target at 3 frameworks:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net40;net45;netstandard1.4</TargetFrameworks>
    <AssemblyName>abc</AssemblyName>
    <Version>1.0.0</Version>
  </PropertyGroup>
  <ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
    <Reference Include="System" />
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
    <Reference Include="System" />
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="PowerShell -ExecutionPolicy Unrestricted -File script.ps1/>
  </Target>
</Project>

And when I build the project, the PreBuild target was called 3 times.

So far, I have tried:

1) At first, I guessed that the builds was going in a sequence, so I added a condition to my target:

  <Target Name="PreBuild" BeforeTargets="PreBuildEvent" Condition=" '$(TargetFramework)' == 'net40' ">
    <Exec Command="PowerShell -ExecutionPolicy Unrestricted -File script.ps1/>
  </Target>

, which did not work. It turned out that mutli-target builds were going concurrently. Sometimes, net40's build would be later, so my script was not running before all the builds.

2) And then I tried to use environment variables to do the synchronization, but it did not work out, either. It seemed the builds didn’t share the environment variables.

3) At last, I turned to other MSBuild targets to replace the PreBuildEvent, but I have found no proper one.

So how do I call my scripts before all the builds and for only once in a multi-targeting project. Please help me.

Jaren Duan
  • 155
  • 2
  • 10

1 Answers1

8

You can hook in your target into the multi-targeting msbuild target that will call the TargetFramework-specific builds like this:

  <PropertyGroup>
    <TargetFrameworks>netstandard2.0;netstandard1.4</TargetFrameworks>
  </PropertyGroup>

  <Target Name="OuterPreBuild" BeforeTargets="DispatchToInnerBuilds">
    <Message Importance="high" Text="Outer before build" />
  </Target>

</Project>

In this case BeforeTargets="Build" Condition="'$(IsCrossTargetingBuild)' == 'true'" will not work because the multi-targeting Build target depends on the "inner projects" being built already.

Martin Ullrich
  • 94,744
  • 25
  • 252
  • 217
  • This is great, and it can solve my problem. But I have another one: how to pass msbuild predefined properties, such as $(ProjectPath) to my scripts? For example, what if I want this: ` – Jaren Duan Apr 30 '18 at 03:29
  • You may want to use `$(MSBuildProjectDirectory)` instead, see [MSBuild Reserved and Well-Known Properties](https://learn.microsoft.com/en-gb/visualstudio/msbuild/msbuild-reserved-and-well-known-properties) – Martin Ullrich Apr 30 '18 at 05:23
  • Cool. You saved me. Thank you. – Jaren Duan Apr 30 '18 at 07:40
  • BTW, I would like to know how you found the right target "DispatchToInnerBuilds"? I went through MSBuild .targets files and failed. – Jaren Duan Apr 30 '18 at 07:42
  • 1
    It’s in the .CrossTargeting.targets file – Martin Ullrich Apr 30 '18 at 07:46
  • Is there a reverse target I can use to [call a command after all builds were done](https://stackoverflow.com/q/71015510/5333340)? – Kjara Feb 08 '22 at 12:50
  • 2
    @Kjara you can try `AfterTargets="DispatchtoInnterBuilds"` – Martin Ullrich Feb 08 '22 at 14:25
  • @MartinUllrich If you make this an answer in my linked question, I'll accept it. You'll get points! :) – Kjara Feb 09 '22 at 07:27
  • Okay, if it has to do with BUILD, one can utilize the `DispatchToInnerBuilds` target... But what if it does not have to do with BUILD? Like a final cleanup - after CLEAN was done for all projects? – Kjara Feb 10 '22 at 08:56
  • The problem with DispatchToInnerBuilds is that it doesn't execute when building a referencing project. – Max Toro Mar 28 '22 at 20:22
  • @JarenDuan Do I miss something here? I'm having the same problem. If I change the value of `BeforeTargets` from `PreBuildEvent` to `DispatchToInnerBuilds` nothing is called. Even the specified example showing a message does not work. I'm using VS2022 building against `net472` and `net60-windows`. – Sebastian Schumann May 15 '23 at 07:47