29

In my project, I am running an external tool to update some binary files. These files are included in the project as "content".

At the moment the tool is set to run during "pre-build event" in C# project properties. Unfortunately, this event is only executed if the project is out of date, which is not what I need.

I am working around this by always using "rebuild" instead of "build" on my project, but this is tedious and slow.

I need to execute this tool always, irrespective of whether a project is or is not up to date. Actually, even before MSBuild even determines whether the project is up-to-date, because the tool modifies some of the files included in the project, therefore affecting the up-to-date check result.

Is there a proper way to do it?

Harish
  • 285
  • 4
  • 21
kaalus
  • 3,728
  • 3
  • 24
  • 34
  • 1
    No, modifying projects while they are loaded into the IDE is not going to come to a good end. Surely there's a better way, your question does not help us help you. – Hans Passant Mar 07 '15 at 16:12
  • 1
    @HansPassant Maybe I overengineered the question. It boils down to this: is there a way to _always_ run a command before a build? – kaalus Mar 07 '15 at 16:54
  • 1
    For C++ projects you can do this using a Target with the `BeforeTargets="BuildGenerateSources"` attribute, for C# you can do something similar and just have to figure out which of the many targets invoked in a build you're going to use for that BeforeTargets attribute. Run a verbose build and inspect the output or start looking in Microsoft.CSharp.targets or so.However as Hans says: the results might not be what you expect – stijn Mar 08 '15 at 20:49
  • When changing the sources on disk right under the nose of Visual Studio causes all kinds of funny behavior, you'll need to turn off the HostCompiler services (which will slow down Visual Studio a bit): http://blog.jessehouwing.nl/2012/06/just-in-time-updating-of-source-files.html – jessehouwing Mar 14 '15 at 14:54
  • For C# it would be the `BuildDependsOn` group, https://msdn.microsoft.com/en-us/library/ms366724.aspx or you can extend the solution itself: http://stackoverflow.com/a/5720489/736079 (see the second answer, the accepted answer is not what you're after). – jessehouwing Mar 14 '15 at 14:58

4 Answers4

46

Here's the solution. Define this property in your project file:

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

PreBuildStep will then execute every time, regardless of whether the project is or isn't up to date.

It seems that Visual Studio is bypassing normal up-to-date checks of MSBuild and using some sort of custom check that is faster, but has a side effect of breaking customized build targets.

Siewers
  • 21,728
  • 3
  • 18
  • 29
kaalus
  • 3,728
  • 3
  • 24
  • 34
9

In project level, you have three options:

1) Pre-build action

<PropertyGroup>
  <PreBuildEvent>notepad.exe Foo.txt</PreBuildEvent>
</PropertyGroup>

2) normal BeforeBuild target

<Target Name="BeforeBuild">
  <Exec Command="notepad.exe Foo.txt" />
</Target>

3) "attached" to "Build" target (like stijn suggested)

<Target Name="BeforeBuild2" BeforeTargets="Build">
  <Exec Command="notepad.exe Foo.txt" />
</Target>

Actually this solution (in case of Build) will not work, because DependsOnTargets is executed BEFORE BeforeTargets. And exactly in DependsOnTargets the real (CoreBuild) sits :) This is why they invented the 'BeforeBuild' target ;)


In both cases VS check if something is changes (files are up-to-date). Why do you even want to run external program if nothing was changed? If this program work on file (eg. "content") msbuild and VS should detect files as out-of-date and process building.


Unfortunately IDE (Visual Studio) has it's own method to deal with msbuild projects. The main mechanism is the same, but when it's came to determine what project build or not, or in which order... VS act totalny different.

You can use external tool and run "msbuild" against your solution or project. This will also compile "the proper way" and binaries will be not different, but you will have full capabilities and potentials of MsBuild

Carnifex
  • 503
  • 3
  • 8
  • 1
    I need to run the external program because it processes a very large number of files into a single binary. It would be infeasible to add all these files to Visual Studio project, so they are not in the project. MSBuild knows nothing about them. The external tool has its own up-to-date check mechanism which checks whether these files need processing, but it needs to run in the first place and VS does not want to cooperate. Is it too much to ask... – kaalus Mar 14 '15 at 00:19
  • 1
    You really should add a #4 example with the BeforeTargets="BeforeBuild" .. this helps quite alot – Aaron Hudon May 03 '18 at 00:00
  • Beware, if there are two targets with the same name, only latter would be used. Thus, as many projects already have "BeforeBuild" target, this could cause a ton of silent issues. Better to invent your-own-named targets and equip it with `BeforeTargets="Build"` attribute. – Yury Schkatula Apr 13 '21 at 17:00
3

There is also one additional pre build event that was not discussed here. Usually code analyzers are using that to check if code analyzer was downloaded by NuGet.

So if you want to execute something before code analyzers you need to use that target.

You just need to add <Target/> node under <Project/> node in your .csproj file:

<Target Name="DownloadNugetPackages" BeforeTargets="PrepareForBuild">
    <Exec Command="notepad.exe Foo.txt"/>
</Target>

PrepareForBuild event will run before pre build events.

Shoter
  • 651
  • 8
  • 17
1

None of these solutions worked for me using Visual Studio for Mac. I want to run a bash script before building the project but since I'm using Xamarin, some things are getting out of whack. I tried all different types of targets and even tried the CustomCommands in the project options but still I would get issues around MSbuild just running automatically or not truly running before the build

You can run the PreBuild events in a separate project that compiles before your main project.

  1. Create a new project and name it something like "PreBuildEvent"
  2. Add your MSbuild targets/commands as shown above to this new PreBuildEvent.csproj file for each property group/build configuration
  3. In the project where you originally to do the PreBuild work, add a reference to this new project.
  4. This new project will build first, executing any PreBuild events, and once this project is built, it will kick off the build for your original project. This is because when you add a reference to a project, visual studio makes sure to build them in the correct order
stepheaw
  • 1,513
  • 2
  • 19
  • 32