How do I override CopyLocal (Private) setting for references in .NET from MSBUILD

I have been wrestling with this for a few days and after tons of searching I can't find the path I should be on.

What I want to do is set up an MSBUILD project that will build our entire .NET application (constst of 8 solutions, and maybe 250 projects split up between them) with a number of settings overridden from the individual project files to make a debug build for myself.

Specifically I want to build our release configuration with optimizations off and full debug info / pdbs generated. Also, in order to reduce our currently ultra-long build time I want "copy local" (or private in the actual proj file xml) false for every reference of every project.

The first things were fairly easy, I can override a project level property fairly easily (you can even do this from the MSBuild command line using /p), but what I can't figure out is how to override a property on a reference. I have tried several things I saw here on StackOverflow and around the web, but nothing is a solution yet.

I can do what I want by altering Microsoft.Common.targets, commenting out the code in the _CopyFilesMarkedCopyLocal target completely skips the copying of these files. But I don't want to alter my global configuration and do this in all circumstances. I created my own alternate targets file -- which works if I alter an individual project file to point to it -- but I can't figure out how to specify this to be used at the top level (my .proj file that just builds all 8 solutions). It would be great if I could somehow override just the _CopyFilesMarkedCopyLocal target at the top level so that if MS changes the default targets file my build isn't screwed up, but I can't figure out how to make this work either.

The best possible thing would be if there was a way to just override reference level properties like you can project level properties, without having to rewrite/override the build targets stuff -- but I have found no information indicating this is possible.

Thanks in advance for any help on this.

P.S. It is not possible for me to actually just go through all the projects files and change them; I need a solution that leaves the existing code in place as is.


Try this:

Set the CustomAfterMicrosoftCommonTargets to C:\foo\filter.targets (or whatever you name the file) and have filter.targets to be:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemDefinitionGroup>
      <Reference>
        <Private>False</Private>
      </Reference>
    </ItemDefinitionGroup>
</Project>

In a file like filter.targets add a target:

<Target Name="BeforeBuild">
  <ItemGroup>
        <ReferenceNew Include="@(Reference)">
           <Private>False</Private>
        </ReferenceNew>
        <Reference Remove="@(Reference)"/>
        <Reference Include="@(ReferenceNew)"/>
  </ItemGroup>
</Target>

This will recreate the @(Reference) list to have the metadata 'Private' set to false, which will ensure that the reference doesn't get copied. Then run build your solution or project with the property $(CustomAfterMicrosoftCommonTargets) set to the path to this filter.targets file.

msbuild foo.sln /p:CustomAfterMicrosoftCommonTargets=c:\foo\filter.targets

This way, the BeforeBuild target will get invoked before building the project, and all references will be set accordingly. If you want more control over when or whether Private should be false or true, you can alter the BeforeBuild target and control that via properties.

Edit: There might be a better way to set the metadata in the BeforeBuild target.