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?
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.
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.
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.
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.
NOTE: This workaround is not officially supported by Microsoft, so there is no guarantee that it will work forever.
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}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With