【问题标题】:Set "Copy Local" to False by default?默认情况下将“复制本地”设置为False?
【发布时间】:2010-06-23 11:13:13
【问题描述】:

我可以将 Visual Studio 中“复制本地”的默认选项设置为 False 吗?在大多数情况下,当我添加一个 dll 作为项目的依赖项时,我希望将 Copy Local 属性设置为 False。默认情况下,它是 True。有没有办法改变 Visual Studio 的默认行为? (2008)

【问题讨论】:

标签: visual-studio copy-local


【解决方案1】:

否 - Visual Studio 使用一组内部规则来确定将本地复制设置为什么。

来自MSDN

  1. 如果引用是另一个项目,称为项目到项目引用,则值为 true
  2. 如果在全局程序集缓存中找到程序集,则值为 false
  3. 作为一种特殊情况,mscorlib.dll 引用的值为false
  4. 如果在 Framework SDK 文件夹中找到程序集,则值为 false
  5. 否则,该值为true

【讨论】:

  • MSDN 链接中的内容已停用
【解决方案2】:

其实可以的。你需要几样东西:

  1. 创建 .targets 文件,使 copylocal(准确地说是<Private> 标签)false by default
  2. .csproj 文件中导入目标。您可以在最后一行添加它,在关闭 </Project> 标签之前,它看起来像 <Import Project="..\Build\yourtarget.targets" />

现在每个具有此目标的项目都默认禁用了本地复制。

缺点是您需要修改每个 csproj 文件,包括新文件。您可以通过modifying the VS project template 解决新项目问题。您需要修改Class.vstemplate(在同一个zip文件中),而不是博客文章中描述的Class.cs

使用这种方法,还有一个问题 - 路径本身。如果你在新生成的 csproj 文件中使用硬编码的相对路径,它们可能是错误的(除非你有扁平的项目结构)。

你可以:

  • 让VS生成正确的相对路径。不知道该怎么做,也不知道这是否可能。
  • 忽略它并为每个新的 csproj 手动更改路径(取决于您拥有的新项目的数量,虽然不理想,但可能是可以容忍的)。
  • 使用环境变量而不是相对路径。在这种情况下,每个开发人员都需要相同的变量集。

一定有更好的解决方案,但还没有找到。

【讨论】:

  • 这似乎是正确的答案,我已经按照指导和链接进行操作了!
  • @AnthonyMastrean:你有没有想出一个聪明的方法来将 import 放入新创建的 csproj 文件中?
  • 我们正在使用一个通用的.csproj 文件,该文件使用模板导入到每个新项目中。模板系统不是很干净,我们还不确定我们是否喜欢它。
  • 您可以使用 dir /s /b *csproj > project-files.txt 列出根目录下的每个项目文件,然后使用 for /f %i in (project-files .txt) 做记事本++ "%i"。由于 notepad++ 允许您替换所有打开的文件,您可以要求它用
【解决方案3】:

从 msbuild v 15 开始,您可以在包含源代码的根文件夹中复制一个名为 Directory.Build.props 的文件:

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

没什么可做的!这适用于 Visual Studio 2017 以及 vNext Build。您可能必须关闭 Visual Studio,然后再次打开您的解决方案才能使文件生效。

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

【讨论】:

  • 这种方法只能用于.net core项目吗?或者您也可以为较旧的 .net 项目执行此操作,例如.net 452?
  • 通过阅读 Glen Slayden 的回答,将 False 也包括在内不是更好吗?
  • @Dave Barnett 你是对的,如果这也适用于 ProjectReferences。你试过了吗?如果您愿意,可以在我的答案中添加标签。我不在我的项目中使用项目引用。我在 TFS 2018 和 Visual Studio Enterprise 2017 上使用 dll-References on.Net 4.7.1 和 vNext Build 检查了解决方案
  • 是的,我在 .net 4.5.2 项目上尝试过。这个使用了项目引用并且显然没有工作,直到我意识到我需要使用项目引用标签,然后它确实工作了。一个非常好的解决方案,因为无需编辑任何现有文件。我已添加标签并等待同行评审。
【解决方案4】:

我们不使用 .targets 文件(正如 ya23 的回答中所建议的那样),因此我们只需在文本编辑器中手动编辑 .csproj 项目文件并将 &lt;Private&gt; 元素添加到引用中,如下所示:

<Reference Include="[...]">
  <Private>False</Private>
  [...]
</Reference>

&lt;Private&gt; 元素的值与“复制本地”属性的值相匹配。例如,如果&lt;Private&gt; 设置为 False,则“复制本地”也是 false..

【讨论】:

    【解决方案5】:

    因为现在似乎有一个 nuget 包允许这样做...

    https://nuget.org/packages/CopyLocalFalse

    还没试过,希望对你有帮助。

    【讨论】:

    • 有了这个 nuget 包,没有任何保证。它在安装脚本中有一些预定义的过滤,将跳过一些引用。此外,它仅在 nuget 包的安装时出现。 nuget 包可能已经安装,同时添加了一个新的参考。此外,如果 nuget 包在其他包恢复之前被恢复,哪些其他包可能会重置其引用程序集的本地副本?不推荐的方法。最好使用目标来覆盖本地副本并拥有自己的过滤。
    【解决方案6】:

    关于@herzbube 发布的解决方案,如果您想为 .csproj 文件中的所有(或大部分)引用关闭“复制本地”,则无需设置&lt;Private&gt;False&lt;/Private&gt; 分别在每个 Reference 上,您可以直接在 .csproj 中输入以下内容:

    <ItemDefinitionGroup>
      <Reference>
        <Private>False</Private>
      </Reference>
    </ItemDefinitionGroup>
    

    这不会影响使用 &lt;ProjectReference&gt; 引用的项目,但您可以为这些项目做同样的事情 - 或者也可以这样做:

    <ItemDefinitionGroup>
      <ProjectReference>
        <Private>False</Private>
      </ProjectReference>
    </ItemDefinitionGroup>
    

    如果你想要这两个,你可以将它们合并到一个组中:

    <ItemDefinitionGroup>
      <Reference>
        <Private>False</Private>
      </Reference>
      <ProjectReference>
        <Private>False</Private>
      </ProjectReference>
    </ItemDefinitionGroup>
    

    确保将这些覆盖放在您想要影响的第一个实际&lt;Reference … &gt;&lt;ProjectReference … &gt; 之前,因为这些块仅适用于出现在它们下方的那些引用。然后,如果您确实确实想要在本地复制一些内容,则可以单独覆盖那些back(即,在单个标签本身),这次使用True

    对于更高级的情况,您可以在同一个 .csproj 文件中多次在 TrueFalse 之间来回切换覆盖值。另一种先进的技术是策略性地将您的一些引用放置在这些块下方,而其他一些则放在上面,这样后者就不会受到影响。

    所有这些都应该使您的 .csproj 中的 XML 更加清晰和易于阅读。但是还有更多好消息,请继续阅读...


    至于选择哪些项目应该标记&lt;Private&gt;False&lt;/Private&gt;,这通常取决于具体情况,但有一些基本的每个人可以应该为初学者做。这是一个如此基本、简单和有效的步骤,它提供了如此巨大的 MSBuild 可靠性改进1. 和构建时间加速 - 而且几乎没有缺点 - 每个大型解决方案使用默认(即每个项目的本地)C# 输出位置几乎总是应该进行此调整:

    在构建多个 C# 类库的任何 Visual Studio 解决方案中,具有任意数量的 &lt;ProjectReference&gt; 相互依赖关系,最终构建一个更多应用程序(即可执行文件):

    1. 在每个类库的 .csproj 顶部附近,插入上面显示的 &lt;ProjectReference&gt; 块。
      原因:任何 .dll 都不需要将它引用的任何库收集到它自己的子目录中,因为从该位置没有运行任何可执行文件。如此猖獗的复制是无用的忙碌工作,并且可能会不必要地减慢您的构建速度,甚至可能非常显着。

    2. 另一方面,不要为您解决方案的任何应用程序修改 .csproj。 原因:可执行文件需要在其各自的子目录中拥有所有他们需要的私有库,但是每个应用程序的构建应该负责单独收集每个依赖项,直接从其各自的子目录到应用程序的子目录中目录。

    这非常有效,因为一个类库的 .csproj 可以引用多个其他类库,但一个可执行文件的 .csproj 通常从不引用另一个可执行文件。因此,对于每个本地构建的库,其 bin 文件夹中唯一的 .dll 将是其自身,而每个本地构建的 application 将包含完整的本地- 构建它引用的库。

    方便的是,对于不是由您的解决方案构建的引用库,没有任何变化,因为这些库通常使用&lt;Reference&gt; 而不是&lt;ProjectReference&gt;,我们根本没有修改前一个标签。但请注意刚才提到的假设;如果您的某些项目违反了它,您可能需要进行一些调整。

    [1.] 可靠性改进可能与从依赖关系图中的多个不相交路径收集相同库时可能发生的文件冲突有关,尤其是在并发构建中。

    【讨论】:

    • 如果我错了,请纠正我,但我不认为这是正确的。通过将&lt;ProjectReference&gt; 标记为私有属性,您表示您不想将引用的项目DLL 复制到构建文件夹中。这不包括您可能在该类库中使用的其他包引用。此外,如果您最终将 false 属性包含到 &lt;Reference&gt; 节点,则应用程序项目中未显式引用的传递依赖项将不会被复制到构建文件夹。
    • @Pavisa 确实,传递引用必须由开发人员在没有 IDE 帮助的情况下维护——但仅适用于 executable csprojs,而且至关重要的是不适用 DLL。我说得很关键,因为(至少对我而言)每个 .exe 的库比率通常是压倒性的,所以当我考虑构建速度的权衡时,这并不是什么不便。这种维护“负担”更加微不足道,因为当您运行 .exe 时,您会收到关于缺少库的完整详细消息,并且仅在更改库引用后一次。根据我的经验,这完全不是问题。
    • 维护这些依赖项的建议方法是什么?您是否建议显式添加对 .csproj 文件的传递引用并让构建工具处理它或在构建过程之后手动添加它们?我想在 CI/CD 管道中找到最简单的方法。我的问题是未使用的传递依赖项使我的构建膨胀到不合理的程度。
    • @Pavisa 依赖项在 .csproj 中正常维护,根据需要混合 Visual Studio 项目引用,并且所有 IDE 编辑/构建/测试/运行功能继续正常工作。这里唯一的区别是 1.) 仅在 class lib .csproj 文件中使用&lt;private&gt;,2.) 您在上面指出的不常见(且无关紧要)的维护问题,以及 3.)作为交换,每次构建时不要将 1,000 个支持 .dll 文件复制到根据定义永远不会“执行自”的位置,后者因此使它们的存在,恕我直言,无用,甚至有害。跨度>
    • @Pavisa 总结一下,以防我不清楚,您的观点可能适用于某些构建场景,所以我的假设是:1.) 总是很少有 应用程序 与通常在所有解决方案中的大量 dll 相比 2.) 实际上,解决方案应用程序引用的大多数或所有 dll 都被这些 exe 显式引用(使您的问题没有实际意义),并且 3.) .csproj 交叉引用不会一直更改和/或调试器在运行时明确暴露的罕见错误的工作流程可以很容易地检测和解决。
    猜你喜欢
    • 2012-08-09
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    相关资源
    最近更新 更多