应用程序构建期间自动将文件复制到输出目录

66

在C#项目中,文件有一个名为复制到输出目录的属性。但是在VC++项目中,该属性不存在。我知道,在VC++中可以使用生成事件,然后在那里编写类似以下内容的代码:

xcopy /y /d %(FullPath) $(OutDir)

有没有一种方法可以避免使用CMD(和其他脚本方法)?msbuild能在这种情况下提供帮助吗?

8个回答

98

MSBuild能在这种情况下提供帮助吗?

我使用 MSVC 2012,以下方法适用:

假设你的 C++ 项目中有一个名为 "Data/ThisIsData.txt" 的文件。

先卸载项目(右键单击 --> 卸载项目)。
编辑项目 XML 文件(右键单击 --> 编辑 .vcxproj 文件)
现在你可以在编辑器中以 XML 格式看到项目的 MSBuild 文件。

找到 "ThisIsData.txt"。它应该长成这个样子:

<ItemGroup>
<None Include="Data\ThisIsData.txt" />
...
</ItemGroup>

现在添加另一个类似于这样的项目组:

<ItemGroup>
<Content Include="Data\ThisIsData.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
...
</ItemGroup>

重新加载项目并构建。
你的文件"ThisIsData.txt"应该会被复制到$(OutDir)\Data\ThisIsData.txt。

为什么要重复ItemGroup?

如果你只是将None include更改为content include,IDE似乎不再喜欢它,并且不会显示它。因此为了保持数据文件的快速编辑选项,我决定保留重复的条目。


谢谢 (+1)。你试过 @AntonK 的解决方案吗? - Loom
1
这已经是我第二次忘记了并使用了这个答案,希望我能投两次赞。 - Indy9000
4
为了让该项在IDE中保留,您需要同时在.vcxproj.filters文件中重命名元素,将您在.vcxproj文件中修改的相同文件的<None替换为<Content。 - birdypme
1
甚至可以通过IDE实现这一点。只需转到项目属性并手动将“内容”输入到项目类型字段中即可。 - Vertigo
2
@Vertigo,你说的不是真的,在Visual Studio 2017中至少不是这样。我收到的错误是“此项目项提供程序不支持内容项目类型”。 - Gam
@James,我在2015年和2017年重新检查了这个问题,它是真实的。唯一的区别是2015年没有修改.vcxproj.filters文件,而2017年修改了。 - Vertigo

20
在Visual Studio 2017中,您可以在IDE中完成此操作。我不确定早期版本是否支持。
只需将文件添加为包含的项目文件,以便它显示在“解决方案资源管理器”中。然后右键单击文件并选择“属性”菜单。
将内容更改为“Yes”,并将项类型更改为“复制文件”。
如果您查看项目文件所做的更改,您会发现它添加了以下内容:
<ItemGroup>
  <CopyFileToFolders Include="Filename.txt">
    <DeploymentContent>true</DeploymentContent>
    <FileType>Document</FileType>
  </CopyFileToFolders>
</ItemGroup>

2
这也是Visual Studio 2019的最佳解决方案。 - Will Custode
2
可以确认这在VS 2017中有效。谢谢@Eric。再次强调 - 确保右键单击并选择属性以打开属性对话框。当您只选择文件时,“项目类型”设置在“属性”视图(在“解决方案资源管理器”视图下)中不可用。当您只选择文件时,您<b>可以</b>将内容设置更改为True(相当于属性对话框中的“Yes”)。这可能看起来很吹毛求疵,但它让我花费了大约30分钟的心痛。 - TheLastGIS
1
只是提一下,看起来“复制文件”项目类型是在VS 2017中添加的 - 它在VS 2015中不存在。 - Jasongiss
在我的VS2019 C++ DLL项目中也无法工作:https://i.imgur.com/MEglijk.png - KulaGGin
这个也适用于在Visual Studio 2022中使用旧式的C++ MFC项目。 - iCode

19

在VS 2015中,可以为C语言项目添加与C#相同的功能。(灵感来自于jochen的回答。) 不需要添加另一个ItemGroup,只需修改给定的ItemGroup并添加CopyTo元素即可。例如,在使用他的示例时,只需增强原始条目:

<ItemGroup>
  <None Include="Data\ThisIsData.txt" />
    <DeploymentContent>true</DeploymentContent>
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
...
</ItemGroup>

无需其他ItemGroup。通过添加CopyTo元素,您可以添加“包含在项目中”属性。

添加“包含在项目中”属性的VS 2015 C Property


1
在我的Visual Studio 2017中可以工作。谢谢! - habakuk
1
在我的VS 2017中无法工作。当VS尝试加载项目时,它会给我这个错误:Items outside Target elements must have one of the following operations: Include, Update or Remove. [vcxproj filename],我的代码是:<ItemGroup> <None Include="..\IncludedLibraries\jpeglib\libjpeg-9.dll" /> <DeploymentContent>true</DeploymentContent> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </ItemGroup> - Draex_

15

这取决于您使用的Visual Studio版本。在Visual Studio 2008中,VC++项目文件的格式不是MSBuild,因此在PostBuildStep中使用xcopy是一个不错的选择。

在Visual Studio 2010中的VC++项目具有MSBuild格式。 因此,有MSBuild Copy任务的功能。

下面是一个示例:

<Copy
    SourceFiles="%(FullPath)"
    DestinationFolder="$(OutDir)"
/>
如果目标目录不存在,它会被自动创建。
MSDN的复制任务参考可以在这里找到。

2
非常好的答案 - 这就是我缺少的步骤。我认为可以通过说明您提供的<Copy.../>代码应该添加到哪个文件中以及文件中的位置来改进它。 - RoG
@Snaptastic 这就是为什么有一个详细描述的 MSDN 链接。 - Anton K
7
我被提供了一个包含5个vcproj文件的C++解决方案,总共大约有4900行代码,所以我认为这对答案是一个有用的补充。这并没有在提供的链接中直接说明,而且链接作为答案通常不被看好。虽然我没有问题自己查找信息,但是SO的目的之一就是为了节省我和其他人这样的工作时间,对吧? - RoG
2
我需要在 <Target Name="MyCopyTarget" AfterTargets="Build"></Target> 中再次包装复制。我的目标元素是项目文件中根 Project 元素的一个元素。 - Fredrick

7

henri-socha's answer 关于 VS2015(可能也包括 VS2013 和 VS2012,或者任何使用 MSBuild 样式项目的工具)中,ItemGroup 项类型很重要。

具体来说,<Text> 项不会被复制,而 <Content> 项会被复制。

因此,如果一个项目目录 Data 包含一个文本文件 ThisIsData.txt,那么这将在 $(OutDir) 目录下创建一个子目录 Data,并将该文件从项目中复制到该目录下(如果文件是新的):

<ItemGroup>
  <Content Include="Data\ThisIsData.txt">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
</ItemGroup>

尽管这是Visual Studio IDE将文本文件添加到项目并设置Content属性为True时插入的内容,但它不会起作用。

<ItemGroup>
  <Text Include="Data\ThisIsData.txt">
    <DeploymentContent>true</DeploymentContent>
  </Text>
</ItemGroup>

换句话说,您需要通过IDE添加文件,以使其意识到文件已包含在项目中(这将添加

5
在 Visual Studio 2019 中,将文件设置为“包含在项目中”后,您可以编辑属性并选择项目类型为“复制文件”(如 https://istack.dev59.com/vac2b.webp 所示)。这避免了手动编辑 vcxproj 文件的麻烦。

2
您可以在项目文件中指定复制方式,如在另一个问题中Jeff G回答所述:

In the *.vcxproj file, change:

<Text Include="Filename.txt" />

to:

<Content Include="Filename.txt">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

Then in the *.vcxproj.filters file, change:

<Text Include="Filename.txt">
    <Filter>Resource Files</Filter>
</Text>

to:

<Content Include="Filename.txt">
    <Filter>Resource Files</Filter>
</Content>

其中<Text ...>标签用于指定文本文件(对于图像文件等,将使用<Image ...>


-4
如果它是一个COM dll,您可以将其添加到项目的根目录中,将其标记为“内容”,并将复制到输出目录设置为“始终”。我不得不为签名捕获COM程序集执行此操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接