MSBuild: Ignore Goals That Don't Exist

Solution1.sln contains two projects:

  • ProjectA.csproj
  • ProjectB.csproj

ProjectB has a custom target called "Foo." I want to run:

msbuild Solution1.sln / t: Foo

This will not succeed because ProjectA does not define the target "Foo".

Is there a way to make the decision ignore the missing target? (For example, do nothing if the target does not exist for a specific project) without changing the SLN files or the project?

+7
source share
4 answers

There is a two-component solution if you do not want to edit solution files or projects, and you are happy that it works from the MSBuild command line, but not from Visual Studio.

Firstly, the error you get at startup:

MSBuild Solution1.sln /t:Foo 

Is it not that ProjectA does not contain the target Foo, but the solution itself does not contain the target Foo. As @Jaykul suggests, setting the MSBuildEmitSolution environment variable will show the default targets contained in the meta-solution of the solution.

Using metapride as inspiration, you can enter a new file "before.Solution1.sln.targets" next to the solution file (the file name template is important) with the following contents:

 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Target Name="Foo"> <MSBuild Projects="@(ProjectReference)" Targets="Foo" BuildInParallel="True" Properties="CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)" /> </Target> </Project> 

The MSBuild element is basically just copied from the metaproj Publish Target solution. Adjust the target name and any other data according to your scenario.

With this file in place, you will now receive an error message that ProjectA does not contain the target Foo. ProjectB may or may not build in any case depending on cross-project dependencies.

So, secondly, to solve this problem, we need to give each project an empty Foo target, which is then redefined in projects that actually already contain one.

We do this by entering another file, for example, "EmptyFoo.targets" (the name is not important), which looks like this:

 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Target Name="Foo" /> </Project> 

And then we get each project to automatically import this target file either by launching MSBuild with an additional property, for example:

 MSBuild Solution1.sln /t:Foo /p:CustomBeforeMicrosoftCommonTargets=c:\full_path_to\EmptyFoo.targets 

Or, include the CustomerBeforeMicrosoftCommonTargets property in the Properties attribute in the MSBuild element in the first goals file, where you can specify the full path relative to the $ (SolutionDir) property.

However, if you are ready to run Foo in conjunction with any default solution targets (e.g. Build, Rebuild, Clean, or Publish), you might be a little inspired to see how Pipeline Web Publishing in MSBuild uses the DeployOnBuild property to invoke the target publication on the web -projects in a solution containing other types of projects that do not support publication.


More information about before.Solution1.sln.targets file: http://sedodream.com/2010/10/22/MSBuildExtendingTheSolutionBuild.aspx

+6
source

This may not be the best answer, but a reasonable hack.

 msbuild ProjectA.csproj msbuild ProjectB.csproj /t:Foo 
+1
source

You can target them by project name, for example / t: project: target (quotes may be required, I can’t remember).

You can find all the generated targets by setting the environment variable MSBuildEmitSolution = 1 ..., which forces msbuild to save the temp.metaproj file that it generates for your solution. This file has all the goals defined in it, just open it and see :)

+1
source

When the solution for building msbuild - msbuild throws only a limited set of goals into it. Metaplanetary file and afaik - you cannot create a custom target through the building sln file, you must use the original project 1.csproj or a custom build script.

+1
source

All Articles