165

I saw this in a project file the other day:

<ProjectReference Include="Foo\Bar\Baz.csproj">
    <Project>{A GUID HERE}</Project>
    <Name>Baz</Name>
    <Private>False</Private> <!-- ??? -->
    <ReferenceOutputAssembly>False</ReferenceOutputAssembly>
</ProjectReference>

Every node in a ProjectReference appears to be self explanatory (the referenced project file, GUID, name to show in the solution explorer, and whether or not the current project should link to the referenced project) except Private, and the Common MSBuild Project Items page doesn't document this value. (There's a Private setting documented for Reference rather than ProjectReference -- but it has Never, Always, and PreserveNewest settings, not true and false)

What does this setting do?

Ganesh Jadhav
  • 2,830
  • 1
  • 20
  • 32
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • 2
    As far as MSBuild is concerned, ProjectReference is an item group (i.e., list) and Private is item metadata for the included item. The answer to your question lies in what any includes do with it. In more general terms, what specific type of project is it? Maybe tag your question with csharp. – Tom Blodget Oct 08 '14 at 04:12
  • I meant "Imports" not "includes". – Tom Blodget Oct 08 '14 at 04:35
  • @malexander: I think your answer was good if you'd undelete it... – Billy ONeal Oct 08 '14 at 19:45
  • 2
    @Tom: Sure, strictly speaking that's true. On the other hand, the `ProjectReference` item is recognized by (at least) the C# and C++ MSBuild supporting infrastructure; it looks like it is handled mostly in the `Microsoft.Common.CurrentVersion.targets` file. – Billy ONeal Oct 08 '14 at 19:46

2 Answers2

167

Private metadata on a ProjectReference item corresponds to the "Copy Local" property on the reference node in Visual Studio's Solution Explorer.

It controls whether the reference should be copied to the output folder or not:

  • true means the reference should be copied
  • false means the reference should NOT be copied

This is documented in Common MSBuild project items, as well as the MSBuild source itself in Microsoft.Common.CurrentVersion.targets:

<!--
============================================================

                  ResolveAssemblyReferences

Given the list of assemblies, find the closure of all assemblies that they depend on. These are
what we need to copy to the output directory.

    [IN]
    @(Reference) - List of assembly references as fusion names.
    @(_ResolvedProjectReferencePaths) - List of project references produced by projects that this project depends on.

        The 'Private' attribute on the reference corresponds to the Copy Local flag in IDE.
        The 'Private' flag can have three possible values:
            - 'True' means the reference should be Copied Local
            - 'False' means the reference should not be Copied Local
            - [Missing] means this task will decide whether to treat this reference as CopyLocal or not.

    [OUT]
    @(ReferencePath) - Paths to resolved primary files.
    @(ReferenceDependencyPaths) - Paths to resolved dependency files.
    @(_ReferenceRelatedPaths) - Paths to .xmls and .pdbs.
    @(ReferenceSatellitePaths) - Paths to satellites.
    @(_ReferenceSerializationAssemblyPaths) - Paths to XML serialization assemblies created by sgen.
    @(_ReferenceScatterPaths) - Paths to scatter files.
    @(ReferenceCopyLocalPaths) - Paths to files that should be copied to the local directory.

============================================================
-->
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Mitch
  • 21,223
  • 6
  • 63
  • 86
  • 4
    If the `` is missing, then it's not equivalent to `True`. Search for "MSBuild CopyLocal bug". E.g. see https://stackoverflow.com/questions/1132243/ – xmedeko Jun 28 '18 at 12:45
  • 8
    @xmedeko, That's correct. I'm not sure where @GPR got "If it is absent then the default value of True is assumed" since the answer explicitly says "[Missing] means this task will decide whether to treat this reference as CopyLocal or not". Most of the logic is in [`msbuild\Reference.cs:949`](https://github.com/Microsoft/msbuild/blob/master/src/Tasks/AssemblyDependency/Reference.cs#L949) – Mitch Jun 28 '18 at 19:05
  • 1
    Is it possible that even if `` is set to `True`, MSBuild still does not include the reference in the Output if its not used by the application? This is the current behavior that I am getting locally... – Ninja Dec 28 '19 at 00:58
  • @Ninja, this most frequently happens if MSBuild cannot locate the referenced assembly. If it is not directly used by the code, it may still compile successfully. You can troubleshoot with [procmon](https://learn.microsoft.com/en-us/sysinternals/downloads/procmon) or [MSBuild detailed logging](https://learn.microsoft.com/en-us/visualstudio/msbuild/obtaining-build-logs-with-msbuild?view=vs-2019) – Mitch Dec 28 '19 at 04:05
  • @Mitch Ah i see. Because this is what I am seeing, strange behavior... My build is succeeding but I don't see the DLL even when I set `` to `True`... I was thinking that this could be another MSBuild Optimization? I am not 100% sure its not used by the code - but it is just a guess since the build succeeds... – Ninja Dec 30 '19 at 17:21
  • @Ninja, My bet is still on the assembly not being directly used or found. MSBuild logging should be sufficient to identify which. Feel free to open a question specific to the issue and link it here. – Mitch Dec 30 '19 at 18:15
  • Mitch, in answer to your point **_I'm not sure where @GPR got "If it is absent then the default value of True is assumed" since the answer explicitly says "[Missing] means this task will decide whether to treat this reference as CopyLocal or not"._** ...I just tried it out on a few references, and it always seemed to come out that way. You are, however, correct in pointing out that the actual logic when missing is somewhat more complex and if true is wanted, then explicit setting should be used, and leaving it out should not be relied apon. – GPR Feb 23 '21 at 10:20
2

I want just to state, that <Private>false</Private> (which you can apply to ProjectReferences) may not work when using <MSBuild Projects="$(MSBuildProjectFullPath)" Targets="Publish" Properties="$(_MSBuildProperties)" /> and project $(MSBuildProjectFullPath) have ProjectReferences that have <None><CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory></None> . I've read the source code around https://github.com/dotnet/sdk/blob/master/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets and found the solution. You need to define _GetChildProjectCopyToPublishDirectoryItems=false so an example would be: <MSBuild Projects="$(MSBuildProjectFullPath)" Targets="Publish" Properties="TargetFramework=$(TargetFramework);_GetChildProjectCopyToPublishDirectoryItems=false" />

Teneko
  • 1,417
  • 9
  • 16