Solution-wide pre-build event?

Viewed 43678

I have a solution in Visual Studio which contains several projects. I'd like to run a command at the very beginning of every build - no matter which projects are involved and whether or not they are up-to-date.

Essentially I need something similar to a solution-wide pre-build event, but unfortunately VS does not appear to support these. Does anyone know an alternative way of achieving what I need?

8 Answers

Unusual requirement. But it can be done. Add a new project to your solution, use the Visual C++ > General > Makefile Project template. Set its NMake > Build Command Line setting to the commands you want to execute. Use Project > Project Dependencies to make all other projects depend on it.

We do this by adding an empty project and setting build events for this project. Then you have to give each project dependency to this empty project to make sure that it gets built everytime.

Another old post but inspired by @reg solution I wanted to run a simple build timer that would log the elapsed time for a solution build. I got the build events working using a powershell module which I load via the package manager console when the Visual Studio IDE starts.

So create a powershell module like BuildEvents.psm1:

<#
.SYNOPSIS
    Register solution build events

.DESCRIPTION
    Registers the OnBuildBegin and OnBuildDone events for the entire solution
    De-registers the events if called multiple times.

.EXAMPLE
    RegisterBuildEvents
#>
function RegisterBuildEvents{
  try {
    Unregister-Event -SourceIdentifier "OnBuildBegin" -Force
  } catch {
    #we don't care if this doesn't work
  }
  try {
    Unregister-Event -SourceIdentifier "OnBuildDone" -Force
  } catch {
    #we don't care if this doesn't work
  }
  $obj = [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($dte.Application.Events.BuildEvents, [EnvDTE.BuildEventsClass])
  Register-ObjectEvent -InputObject $obj -EventName OnBuildBegin -Action {
    # do stuff here on build begin
    Write-Host "Solution build started!"
  } -SourceIdentifier "OnBuildBegin"
  Register-ObjectEvent -InputObject $obj -EventName OnBuildDone -Action {
    # do stuff here on build done
    Write-Host "Solution build done!" 
  } -SourceIdentifier "OnBuildDone"
}

# export the functions from the module
export-modulemember -function RegisterBuildEvents

Import the module when the Package Manager host initialises:

  1. In the package manager console type $profile to get the location of your powershell profile
  2. Browse to that directory on disk, if there is no file there create one with the name returned by the above command (e.g. NuGet_profile.ps1)
  3. Open the file in notepad and add the following lines

    Import-Module -Name <Path to your ps module>\BuildEvents -Force
    RegisterBuildEvents
    

I know it is not a "solution"-wide, but I tried to find the any way to run script on project build, so may be helpful for people, that would like any C# script to, for example, modify solution/project files before/after build.

So, as @Hans Passant posted above - we can create new Console Application and run this .exe on build event. Please, read comments to his post, as it is only applicable in case you don't need to integrate this logic to CI/CD and etc. So usage some limited. And in general, it is not the most beautiful solution.

So, for example, we have any project (AwsLambdaProject) and you need to modify .env file inside on each build to update internal variables.

  1. create new C# Application console (in my case it's name : PreBuildEventApp)
  2. build it and open properties of your target AwsLambdaProject
  3. find build->events tab in project properties. And type there "$(SolutionDir)\PreBuild\PreBuildEventApp\bin\Debug\net6.0\PreBuildEventApp.exe -solutionPath=$(SolutionDir)"

enter image description here So here we are calling our .exe and passing there one parameter (solution folder path). *Check, that path contains your valid console app .exe file.

So, your .exe will be executed before every "AwsLambdaProject" build and modify required files.

So for example, you try to write something to file to debug it :

enter image description here

And your file will be created in AwsLambdaProject project folder, not in console project/bin folder.

Notes :

To use async inside your console app, be sure, that AwsLambdaProject contains 7.1 or higher (i use 10.0).

enter image description here

Also, you may face with issue, when first build is failed and only second time it will be succeed. It is because you need to build you console app first to have .exe in right place. You can copy it manually to any folder - it will work fine. But if you need to change code - you need to do it again.

The second way is to click to solution and click "Project Build order", there you can find your "AwsLambdaProject" and add your console app as a dependency. Now, your console app will build first and your project where you need to modify files - second.

Also, you may faced with another one issue here - build event will work only on first build or on Solution Rebuild. To call your console app on every solution build - you need to modify two projects and add there :

<PropertyGroup>    
  <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>

It means - your two projects will build every time, without caching. Be careful, it may increase your usual build time on solution build, depending on project size.

Hope, will help someone. Have a good day!

Related