【问题标题】:Visual Studio: How to "Copy to Output Directory" without copying the folder structure?Visual Studio:如何在不复制文件夹结构的情况下“复制到输出目录”?
【发布时间】:2013-09-11 14:26:28
【问题描述】:

我的项目文件夹的 \lib 文件夹中有一些 dll 文件。在 dll 的属性页中,我选择了“Build Action”作为“Content”,“Copy to Output Directory”选择了“Copy always”。

在构建之后,我实际上是在复制 dll,但它们在 \bin\Release\lib 中,而不是在 \bin\Release 中。

有没有办法将 dll 文件复制到 \bin\Release(而不是 \bin\Release\lib),而无需编写构建后脚本或求助于 nant 等?

【问题讨论】:

    标签: c# visual-studio-2010


    【解决方案1】:

    使用<ContentWithTargetPath> 代替<Content> 并指定目标路径,如下所示:

    <ItemGroup>
      <ContentWithTargetPath Include="lib\some_file.dat">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        <TargetPath>some_file.dat</TargetPath>
      </ContentWithTargetPath>
      <None Include="lib\some_file.dat" />
    </ItemGroup>
    

    请注意,此条目可能在 Visual Studio(2012、2015、2017)中不可见,但一旦手动添加到 csproj,它就会出现在 Visual Studio 中。目标路径将无法通过 UI 进行编辑。

    为文件添加&lt;None&gt; 条目将确保它仍显示在 Visual Studio 的 UI 中。

    【讨论】:

    • 我没有看到 ContentWithTargetPath 作为 VS 2015 中的构建操作选项。有没有办法添加它?
    • 在 .csproj 文件中手动添加条目后,它在 IDE 中显示为一个选项。但是我仍然无法从 IDE 编辑目标路径。
    • 我唯一担心的是,未来版本的 MSBuild/.NET/Visual Studio/Whatever 将不支持此功能,因为 VS2015 UI 不显示此选项或 TargetPath 属性。
    • 这对我有用。其他答案都不适合我。这应该是答案。
    • 请注意,使用 ContentWithTargetPath 会破坏增量编译(在 VS 2017 15.9.9 上测试)
    【解决方案2】:

    将它们保存在 $(ProjectDir)\Lib 中,但将这些文件“As a link”添加到 .csproj 的根目录中。现在它们将被复制到 bin\Debug(或任何其他输出文件夹)而不在 lib 中。

    编辑:当 ContentWithTargetPath 在我使用的 VS/MSBuild 版本中不可用时,这个答案被写了回来。为可能不得不使用旧版本 VS 的人留下这个答案。请停止对此发表评论,我们都知道现在有更好的方法。

    【讨论】:

    • 感谢 ananthonline。我尝试了您的步骤,但没有帮助。可能是我做错了什么。这就是我正在做的事情,如果您认为不正确,请更正: 1. 从项目中排除这些 dll,但让它们在 lib 2. 右键单击​​项目并“添加现有项目”。从 lib 中选择 dll 并将它们添加为“作为链接” 3. 右键单击​​ dll 并再次在“复制到输出目录”中选择“始终复制”。 4. 清理和重建。结果:我再次在 \bin\release\lib 中获得了那些 dll
    • 请在配置后发布您的解决方案文件夹的屏幕截图
    • 如果我尝试向项目树中已有的文件添加链接,它会拒绝,而是再次将文件包含到项目中......
    • 就像@Nyerguds 我遇到的问题是您无法将链接添加到项目树中已经存在的文件中,因此此答案无法解决问题。
    • 它不会淹没解决方案资源管理器中项目目录的根目录吗?对于许多这样的文件,这可能是一个问题。通常项目目录的根目录已经包含太多的各种文件。
    【解决方案3】:

    如果您的主要目的是在不弄乱项目根目录的情况下包含 DLL,另一种解决方案是将 DLL 移动到单独的共享项目,并将其作为参考添加到原始项目中。

    (请注意,这篇文章没有直接回答这个问题,因为它没有保留文件夹和项目结构,但我发现这种方法很有用,因为我能够在我的案例中重组我的项目,而且我想避免其他方法的一些缺点。)

    步骤

    • 右键单击您的Solution -&gt; Add -&gt; New Project -&gt; Shared Project
    • 将 DLL 添加到此项目(在此项目的根目录中,而不是在“lib”子文件夹中)
    • (检查DLL文件属性设置是否正确,例如Build Action: ContentCopy to Output Directory: Copy Always
    • 右击原项目的References -&gt; Add Reference -&gt; Shared Projects
    • 选择您之前创建的共享项目

    设置如下:

    【讨论】:

    • 迄今为止保持项目整洁的简单而优雅的解决方案。
    • 我无法让它与 UAP 和 *.bin 文件一起使用。
    【解决方案4】:

    添加 dll 文件作为对项目的引用,并在引用上将“复制本地”设置为 true。

    【讨论】:

    • 谢谢埃里克。除了我无法添加作为参考的一个 dll 之外,这非常有效。添加为引用时出现的错误是无法添加对“libeay32.dll”的引用。请确保该文件是可访问的,并且它是一个有效的程序集或 COM 组件。
    • @MAnthony:只能将.NET 程序集或COM 互操作程序集添加为项目引用;本机 DLL 不能。您需要找到其他方法将 DLL 复制到 \bin\Release。
    • 感谢 Erik、Michael 和 ananthonline。抱歉,由于我没有所需的声望点,因此无法为您的答案和 cmets 投票。
    • 对于非托管DLL,你需要使用我下面建议的方法。
    【解决方案5】:

    如果需要将文件从Libs目录复制到VS2017的根文件夹:

    <ItemGroup Condition="'$(Platform)' == 'x64'">
        <None Include="Libs\x64\**" Link="\%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
    </ItemGroup>
    <ItemGroup Condition="'$(Platform)' == 'x86'">
        <None Include="Libs\x86\**" Link="\%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
    </ItemGroup>
    

    到任何其他文件夹,包括 Libs(RecursiveDir) 文件夹

    <ItemGroup Condition="'$(Platform)' == 'x86'">
        <None Include="Libs\x86\**" Link="mycustomfolder\%(RecursiveDir)%(Filename)%(Extension)" CopyToOutputDirectory="PreserveNewest" />
    </ItemGroup>
    

    【讨论】:

      【解决方案6】:

      要将我的帽子添加到此处,如果您想要包含整个目录并且不想在 Visual Studio 中跟踪每个单独的文件,那么您可以将其添加到您的项目文件中(对我来说,这个是 UWP C++ 项目的.vcxproj 文件):

      <ItemGroup>
          <Content Include="Content\**">
              <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
          </Content>
      </ItemGroup>
      

      请注意,Content 目录必须与项目文件位于同一目录中,以保留目录结构。

      【讨论】:

        【解决方案7】:

        似乎在 VisualStudio 2015 中,如果您“使用链接添加”的 dll 在同一项目的子文件夹中 - 它们将自动放置在文件夹中,并且输出也会放置在你看到的文件夹中。

        如果 dll 在磁盘上的另一个项目或目录中而不是在项目的子文件夹中,您可以“使用链接添加”,它们将被放置在根目录中就好了。

        【讨论】:

        • VS2012 相同。它拒绝让它们成为链接,只是将它们添加为内容。最后,遗憾的是,最简单的解决方案似乎是将它们转储到项目根目录中。
        【解决方案8】:

        上述解决方案在Visual Studio 2019 Professional v16.8.2 中对我来说并不可靠。有时文件会复制,有时不会。经过多次尝试,感觉在 VS 的最新更新中可能出现了问题。

        这个答案展示了如何使用构建后脚本...... OP 要求 做的事情!因此,此答案仅适用于那些(像我一样)无法使用更传统方法的人。

        • 右键单击项目并选择添加 > 现有项...
        • 导航到lib 文件夹并选择要添加的项目
        • Add 右侧,单击向下箭头并选择Add As Link
        • 右键单击项目中新“lib”文件夹中的每个文件,并将“复制到输出目录”设置为“不复制”
        • 打开项目属性Build Events 并添加以下构建后事件

        ,

        rem Copy 3rd party DLL(s) to the output directory on successful build
        COPY $(ProjectDir)lib\Something.dll $(TargetDir)
        COPY $(ProjectDir)lib\SomethingElse.dll $(TargetDir)
        

        请注意,您可以在构建后事件中使用通配符来复制多个文件。

        【讨论】:

        • 这是我在从事的项目中看到的最常见的方法。此外,您可以将 xcopy 与 /d /y 标志一起使用,因此它只会复制较新的文件。 xcopy 还有一些可能对构建事件有用的选项。
        【解决方案9】:

        另一种方法是将项目保留为None 类型。在解决方案资源管理器中,单击要部署的那些并将Content 属性设置为True

        注意:我是在 VS2019 中做的,而且随着版本的不同,事情可能会发生变化。

        要让它工作,现在右键单击您的项目,然后选择“卸载项目”。然后右击卸载的项目,选择“Edit project_name.vcxproj”。

        在编辑器中,一直到文件底部,并在尾随 &lt;/Project&gt; 标记之前插入此目标:

          <Target Name="CopyContent" AfterTargets="Build">
            <Copy SourceFiles="@(None)" Condition="'%(None.DeploymentContent)' == 'true'" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
          </Target>
        

        现在右键单击卸载的项目并选择“重新加载项目”。如果出现提示,请选择保存并关闭。

        我还将OutputDirectory 设置为:

        $(SolutionDir)bin\$(Configuration)\$(Platform)\

        IntermediateDirectory 到:

        $(SolutionDir)obj\$(Configuration)\$(ProjectName)\$(Platform)\

        在项目属性常规页面中。这会将输出放在“bin”文件夹中,并将中间体放在解决方案根目录中的“obj”文件夹中。

        注意:从命令行运行 MSBuild 时未定义 $(SolutionDir)。您可以使用一个技巧来使用 GetDirectoryNameOfFileAbove 将其定义到 .sln 文件所在的文件夹。 (留给读者作为练习)。此外,看起来他们在 2019 年无论如何都在命令行上正确处理了这个问题。是的 :) $(SolutionDir) 包含一个尾随反斜杠,因此后面没有。每个结果的结尾都必须有一个反斜杠。

        现在,如果您拥有 Pro 或更高版本,请不要在每次需要创建项目时都这样做。那会很蹩脚。相反,一旦您按照自己喜欢的方式设置项目,请选择Project -&gt; Export Template。你给它一个名字,下次你想创建一个像那个一样的项目时,只需在“新建项目”对话框中选择该名称。 (在旧版本中,我认为这是Files -&gt; Export Teamplate...。)

        【讨论】:

          【解决方案10】:

          关于您的问题,以下步骤在 Visual Studio 2019 中对我有用:

          在 Visual Studio 编辑器中,为您的 dll 设置“构建操作”设置为“内容”(这可能是可选的),“复制到输出目录”设置为 ”请勿复制”

          然后将在项目 csproj 文件中生成以下内容:

          <ItemGroup>
            <Content Include="lib\IncludedDLL.dll" />
          </ItemGroup>
          

          将条目改为以下内容:

          <ItemGroup>
            <Content Include="lib\IncludedDLL.dll" />
            <Content Include="lib\IncludedDLL.dll">
              <Link>IncludedDLL.dll</Link>
              <CopyToOutputDirectory>Always</CopyToOutputDirectory>
            </Content>
          </ItemGroup>
          

          您可以将项目 csproj 文件中的 "CopyToOutputDirectory" 选项手动设置为 "Always"“PreserveNewest”

          在 Visual Studio 编辑器中,仍会将文件“复制到输出目录”设置为“不复制”,但文件将被复制重建时的根输出目录

          如果您不想将文件复制到根输出目录,则不需要上述更改,因此,如果是这种情况,您可以手动删除项目 csproj 文件中的上述更改以恢复为非复制行为。

          【讨论】:

            【解决方案11】:

            我在使用 Visual Studio 2010 / C# 项目时遇到了同样的问题。

            对于程序集(即具有 .NET 接口),请使用解决方案资源管理器中项目下的文件夹“References”。右键单击它,选择“添加现有项目”并找到您的 .dll 程序集。

            常见的 .dll 文件可以放在子文件夹中(如上面提到的“\lib”)并在属性中选择:

            • 构建操作 = "HelpFiles"
            • 复制到 OutputDirectory = "如果较新"

            这完全符合我的要求 - 在构建期间,.DLL 被复制到没有“\lib”子文件夹的输出目录。

            【讨论】:

              猜你喜欢
              • 2010-11-04
              • 2010-12-19
              • 1970-01-01
              • 2013-07-18
              • 1970-01-01
              • 1970-01-01
              • 2020-04-06
              相关资源
              最近更新 更多