Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBuild - Project-specific targets for solution does not work

I have a solution that has multiple projects in it, including a web application. I want MSBuild to execute "WebPublish" target against the web application project and "default target" for all other projects in the solution.

This MSDN article says that I can do it specifying the command line

msbuild SlnFolders.sln /t:NotInSlnfolder:Rebuild;NewFolder\InSolutionFolder:Clean 

But I never could make it work - MSBuild return an error, something like "NotInSlnFolder:Rebuild" target does not exist. It does not matter what target to specify, Build, Rebuild or Clean - it does not work in any case.

How can I achieve my goal of specifying project-specific targets for a solution?

The MSDN documentation does not work. Or have I missed something?

like image 615
Philipp Munin Avatar asked Aug 20 '12 10:08

Philipp Munin


People also ask

How do you build specific targets in solutions using MSBuild exe?

To build a specific target of a specific project in a solution. At the command line, type MSBuild.exe <SolutionName>. sln , where <SolutionName> corresponds to the file name of the solution that contains the target that you want to execute.

Will MSBuild compile without any target?

If MSBuild determines that any output files are out of date with respect to the corresponding input file or files, then MSBuild executes the target. Otherwise, MSBuild skips the target. After the target is executed or skipped, any other target that lists it in an AfterTargets attribute is run.

How do you clean MSBuild solution?

Cleaning up specific projects: msbuild MyProjectFile1 /t:Clean msbuild MyProjectFile2 /t:Clean ... This has to be repeated for all projects you need to clean, because MSBuild only accepts single project on command line.

What are targets in MSBuild?

A target element can have both Inputs and Outputs attributes, indicating what items the target expects as input, and what items it produces as output. If all output items are up-to-date, MSBuild skips the target, which significantly improves the build speed. This is called an incremental build of the target.


2 Answers

NOTE: This workaround is not officially supported by Microsoft, so there is no guarantee that it will work forever.


Short Answer

In folder with the SLN file, create the file before.{YourSolution}.sln.targets, with the following content: (Replace what in curly brackets to whatever you need.)

<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">   <Target Name="{MyCompany_MyProduct_WebApp:WebPublish}">     <MSBuild         Condition="'%(ProjectReference.Identity)' == '{$(SolutionDir)MyCompany.MyProduct.WebApp\MyCompany.MyProduct.WebApp.csproj}'"         Projects="@(ProjectReference)"         Targets="{WebPublish}"         BuildInParallel="True"         ToolsVersion="4.0"         Properties="BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)"         SkipNonexistentProjects="%(ProjectReference.SkipNonexistentProjects)" />   </Target> </Project> 

After that you can execute the command line:

msbuild {YourSolution}.sln /t:{MyCompany_MyProduct_WebApp:WebPublish} 

Long Answer

If you add environment variable MSBUILDEMITSOLUTION, setting its value to 1, MSBuild will not delete temporary files generated for the solution and projects.

This will allow you to find {YourSolution}.sln.metaproj and {YourSolution}.sln.metaproj.tmp files generated in the solution folder, which are just standard MSBuild project files.

For MSBuild 3.5, the generated file is {YourSolution}.sln.cache and is retained regardless of environment variables. Analyzing those files, you will understand low-level details of the process and to see the customization opportunities available.

After executing MSBuild with some project-specific target in the .Metaproj file you will find out that the list of project-specific targets is hardcoded and only standard targets are supported (Build, Rebuild, Clean, Compile, Publish; note: Publish and WebPublish are not the same). MSBuild 3.5 only generates Clean, Rebuild and Publish targets as well as a target with just the project's name that means "Build".

You also can see that NotInSlnfolder:Rebuild is just a name of an autogenerated target. In reality MSBuild does not parse it and does not care about project names and location. Also note that the autogenerated target names specify the project name with solution folders hierarchy if it's in one, e.g. SolFolder\SolSubfolder\ProjectName:Publish.

One more critically important thing you will find: The MSBuild Target Name does not support dots. All dots in project names are replaced with underscores. For example, for a project named MyCompany.MyProduct.Components you will have to specify in the command line:

/t:MyCompany_MyProduct_Components:Rebuild 

That's why even standard project-specific target Build didn't work - my project name contained dots.

Analyzing file {YourSolution}.sln.metaproj.tmp, you will find out that at runtime it tries to import targets from file named before.{YourSolution}.sln.targets and after.{YourSolution}.sln.targets, if those files exist. This has a key to the workaround for this MSBuild limitation/bug.

like image 88
Philipp Munin Avatar answered Sep 19 '22 23:09

Philipp Munin


You can open your solution file in text editor and check whether following line is exist or not if not then you can add

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> inside the <Project> tag.

Hope this help you.

like image 28
imdadhusen Avatar answered Sep 21 '22 23:09

imdadhusen