Is “Copy Local” transitive for project references?

纵饮孤独 提交于 2019-11-27 18:46:08

it would also appear that it is important to differentiate file dependencies, where the dependency references a dll assembly file and project dependencies (i.e. what I'm asking about), where the dependency references a project and implicitly the output file of that project.

Not really, no.

MSBuild doesn't really care if the reference points to another project in the solution or to a DLL.

If ProjectA depends on ProjectB to build ProjectA ProjectB must be already built (and up-to-date), MSBuild will then pull its DLL (not its C# code) and link it to ProjectA.

Adding a project reference instead of a DLL is "syntactic sugar" for your convenience: this way MSBuild knows it must pick the output of the referenced project, whatever the output is.

Otherwise, you'll have to manually pre-build the dependency, find its DLL and link it to the project, repeating the process whenever you switch build configuration, move or rename things. Not really practical.

Will the other two dlls also be copied to the output directory?

If any kind of element from a dependency is used directly from the project where the assembly is referenced, that reference will be copied.

An example could be this solution layout:

  • MySolution
    • MySolution.ConsoleApplication
    • MySolution.FirstDependency
    • MySolution.SecondDependency
    • MySolution.ThirdDependency
    • MySolution.FourthDependency

With this dependency chain:

  • MySolution.ConsoleApplication
    • MySolution.FirstDependency
      • MySolution.SecondDependency
        • MySolution.ThirdDependency
        • MySolution.FourthDependency

If you build this solution you'll notice that in MySolution.ConsoleApplication output directory there will be the DLLs for MySolution.FirstDependency, MySolution.SecondDependency and MySolution.ThirdDependency but no DLL for MySolution.FourthDependency.

Why is it so? When MSBuild builds MySolution.SecondDependency it notices that there's a dependency declared to MySolution.FourthDependency, but since it can't find any usage of any kind of element from MySolution.FourthDependency in MySolution.SecondDependency code it decides to perform some "optimization" and omits MySolution.FourthDependency assembly from the output.

This same issue bit me in the past when I added through NuGet AutoMapper to a "deep dependency": adding AutoMapper adds two assembly references, AutoMapper and AutoMapper.Net4, where the second assembly is loaded by the first through reflection when it needs to perform certain kind of action on the new collection objects introduced by the .NET Framework 4. Since the second assembly is loaded through reflection MSBuild thinks it's unused and doesn't bother to copy it around.

So, yes, they will be copied as long as you're using them directly and not through reflection.

Is this documented somewhere?

This behavior seems to be a "feature" of MSBuild, I managed to found a blog post by some folks from Microsoft back when I experienced this issue, but I can't find it again at the moment.

It is very straight forward, doesn't have anything to do with Copy Local. MSBuild looks in the metadata of an assembly to see what the dependencies are for an assembly. So can you, run ildasm.exe on the assembly and double-click the Manifest. Be sure to try this to get insight. You'll see the .assembly directives. Inserted by the compiler when it built the assembly, only the referenced assemblies you actually used in your code will be listed.

If MSBuild can find such an assembly in the same directory then it will automatically copy it. If not then it will silently skip the copy.

From this, you can deduce the failure modes. It cannot copy unmanaged DLLs, they do not appear in the metadata. It cannot copy assemblies that you have an indirect dependency on through Assembly.Load/From(), they don't appear in the metadata either. It cannot copy assemblies that haven't been built yet, a build order problem. And it cannot copy assemblies whose Copy Local property you set to False. Which is normally only a valid choice if the assembly is present in the GAC, no copy required.

For such cases you need to help, XCOPY in a post-build event gets the job done.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!