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

3

28

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.

Southwestward answered 5/11, 2009 at 17:7 Comment(3)
Set CopyLocal=false can cause different issues during deployment time. See my blog post "Do NOT Change "Copy Local” project references to false, unless understand subsequences." ( geekswithblogs.net/mnf/archive/2012/12/09/…)Balsa
Doesn't answer your question but hopefully MS can fix this natively: visualstudio.uservoice.com/forums/121579-visual-studio-2015/…Arquebus
starting with msbuild 15 you can do this easy, see my answer below https://mcmap.net/q/151683/-how-do-i-override-copylocal-private-setting-for-references-in-net-from-msbuildJed
G
32

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>
Gutsy answered 6/11, 2009 at 7:59 Comment(6)
This worked great, and I was able to simple add another node like this: <ProjectReference> <Private>False</Private> </ProjectReference> To get the same behavior on my project references (as opposed to just the file refs).Southwestward
Only thing to note is that this sets the default for <Private>. If it's set on any individual <Reference>, that value will override the one specified here.Ransack
Is there any way to override the setting, if it IS configured in the .csproj ?Syllabub
Note this also works for project references, if you replace <Reference> with <ProjectReference>.Lurlinelusa
There is a trick: set the reference Copy Local to false and then again to true, and Visual Studio adds the Private metadata automatically for that reference. At least VS 2010 does.Lanham
@Martin in this case you don't want it explicitly added to the item itself. if that was the case then the above wouldn't help. It provides a default value if its not specified.Gutsy
K
8

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.

Kibbutz answered 5/11, 2009 at 22:19 Comment(6)
This doesn't seem to work for me. It is definitely running the BeforeBuild target (I put a message task in there to check to make sure it is showing up) for each project, but it doesn't appear to be doing anything to the references. This feels like the right direction, but something is still off with the target presented above.Southwestward
Try printing the references before and after changing them, in the BeforeBuild Target itself. Print like this: "ref: %(Reference.Identity) : %(Reference.Private)"Kibbutz
I was able to get this method to work eventually for the references (I had something else wrong in the filter file), but I think Sayed's solution above is cleaner.Southwestward
Note this also works for project references, if you replace <Reference> with <ProjectReference>.Lurlinelusa
This seems to work, but it is also copying the GAC dlls or rather Dlls apart from my own. How shall i filter? Or exclude System.dll etc.?Orthography
Set 'CopyLocalDependenciesWhenParentReferenceInGac' to true to suppress that behaviour.Maseru
J
2

Starting with msbuild v 15 you can copy a single file called Directory.Build.props in the root folder that contains your source.

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

This works well with Visual Studio 2017 and the vNext Build. May you have to close Visual Studio and than open your solution again to take the file effect.

https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build#directorybuildprops-and-directorybuildtargets

Jed answered 8/6, 2018 at 7:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.