项目参考的“复制本地”是否可传递?

时间:2014-10-02 14:43:10

标签: c# .net visual-studio msbuild copy-local

WRT。拟议的欺骗行为:由于这里的问题与linked question相反,我更倾向于认为它是而不是一个骗局。

首先,我确实阅读了What is the best practice for “Copy Local” and with project references?(也是this),无论如何我都要尝试这一点,但获得一般反馈似乎是必要的,关于这些东西的docs是可怕的,我只是在VS2010上,也许他们在新版本中改变了一些很好的东西。

第二次,我只对这个问题的 项目 参考感兴趣,因为我&#39 ; ve read that assemblies from the GAC are handled differently和GAC与我的问题无关。

第三次,在阅读了建议的欺骗之后,但更多的是@Albireo的好answer,它似乎也很重要,区分文件依赖项,其中依赖项引用dll程序集文件和项目依赖项(即我要问的内容),其中依赖项引用项目并隐式输出该项目的文件。

无论如何,这里的情况,我认为有些奇怪,但仍然:

  • 2个C#可执行项目
  • n C#dll装配项目
  • 2个可执行文件具有不同的输出目录,因为它们将单独部署,并且它们也会在开发人员计算机上分离
  • 这两个可执行文件依赖于某些DLL程序集(可能相互依赖)
  • 有三个输出目录:
    • /x1用于可执行文件1项目
    • /x2用于可执行文件2项目
    • 所有dll程序集
    • /lib

DLL程序集所有Copy Local设置为false作为项目引用,因为它们都构建到同一输出目录。

对于他们直接引用的所有DLL程序集项目引用,2个可执行项目已将Copy Local设置为 true ,因此DLL将会分别复制到/x1 /x2

问题现在是wrt。对于可执行项目直接引用的的DLL,但通过引用的程序集传递:将仅 的程序集通过另一个程序集传递,被复制到可执行文件的输出文件夹,当"复制本地" 在第一次装配时设置为true?

示例:

  • x1.csproj(例如,输出= x1/one.exe
    • 参考:dlA.csproj(例如输出= lib/a.dllCopy Local = *true*
    • (没有直接参考b.dll)
  • dlA.csproj(例如输出= lib/a.dll
    • 参考:dlB.csproj(例如输出= lib/b.dllCopy Local = **false**
    • (没有直接引用c.dll)
  • dlC.csproj(例如输出= lib/c.dll
    • (没有进一步的相关参考资料)

因此,我们有one.exe -> a.dll -> b.dll -> c.dll的逻辑依赖关系,其中只有a.dll显然被复制到one.exe的输出目录。 其他两个dll是否也会被复制到输出目录? 这是否记录在某处?


而且,是的,我试过了。并且,是的,它似乎可以工作,但我还没有足够努力地戳它,无论如何可能还有更多我可能错过的东西。 (还有那个问题。任何官方文档。)

2 个答案:

答案 0 :(得分:27)

  

它似乎也很重要,区分文件依赖项,其中依赖项引用dll程序集文件和项目依赖项(即我要问的内容),其中依赖项引用项目并隐式地引用该文件的输出文件项目

不是,不。

MSBuild并不关心引用是指向解决方案中的另一个项目还是指向DLL。

如果ProjectA依赖于ProjectB构建ProjectA ProjectB必须已经构建(并且是最新的),那么MSBuild将提取其DLL(而非其C#代码)并将其链接到ProjectA

为方便起见,添加项目引用而不是DLL是“语法糖”:这样MSBuild知道必须选择引用项目的输出,无论输出是什么。

否则,您必须手动预构建依赖项,找到其DLL并将其链接到项目,每当您切换构建配置,移动或重命名时重复该过程。不太实际。

  

其他两个dll是否也会被复制到输出目录?

如果直接从引用程序集的项目中使用依赖项中的任何类型的元素,那么将复制该引用。

一个例子可能是这个解决方案布局:

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

使用此依赖关系链:

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

如果您构建此解决方案,您会注意到在MySolution.ConsoleApplication输出目录中会有MySolution.FirstDependencyMySolution.SecondDependencyMySolution.ThirdDependency的DLL,但MySolution.FourthDependency没有DLL 1}}。

为什么会这样? 当MSBuild构建MySolution.SecondDependency时,它注意到向MySolution.FourthDependency声明了一个依赖项,但由于它无法在MySolution.FourthDependency中找到MySolution.SecondDependency中任何类型元素的任何用法代码它决定执行一些“优化”并从输出中省略MySolution.FourthDependency程序集

当我通过NuGet AutoMapper添加“深度依赖”时,同样的问题让我感到困惑:添加AutoMapper会添加两个程序集引用,AutoMapperAutoMapper.Net4,其中第二个程序集由第一次通过反射,它需要对.NET Framework 4引入的新集合对象执行某种操作。由于第二个程序集是通过反射加载的,因此MSBuild认为它未被使用,并且不需要复制它。

所以,,只要您直接使用,就会复制它们,而不是通过反思。

  

这是在某处记录的吗?

这种行为似乎是MSBuild的一个“功能”,当我遇到这个问题时,我设法找到了一些来自微软的人的博客文章,但我现在再也找不到了。

答案 1 :(得分:19)

这是非常直接的,与Copy Local没有任何关系。 MSBuild查看程序集的元数据以查看程序集的依赖项。你也可以在程序集上运行ildasm.exe并双击Manifest。一定要尝试这一点来获得洞察力。您将看到.assembly指令。编译器在构建程序集时插入,只列出代码中实际使用的引用程序集。

如果MSBuild可以在同一目录中找到这样的程序集,那么它将自动复制它。如果没有,那么它将默默地跳过副本。

由此,您可以推断出故障模式。它无法复制非托管DLL,它们不会出现在元数据中。它不能通过Assembly.Load / From()复制您具有间接依赖关系的程序集,它们也不会出现在元数据中。它无法复制尚未构建的程序集,即构建顺序问题。并且它无法复制其Copy Local属性设置为False的程序集。如果程序集存在于GAC中,通常只有一个有效的选择,不需要复制。

对于这种情况,您需要提供帮助,XCOPY在构建后的事件中完成工作。