在构建期间将 Visual Studio 项目文件复制到输出目录

56

当我构建Visual Studio项目时,可执行文件会被写入到项目属性页指定的输出目录中。

我有一个项目,其中包含一些额外的文件(例如.ini文件),这些文件被程序使用。

如何配置该项目以将文件复制到输出目录,以便程序运行时它在其CWD中具有其他文件的副本?

我检查了该文件的属性页面,除了一个将其从构建中排除的选项(已禁用)和自定义构建工具命令为空(而且它是不需要任何处理的纯文本文件)之外,没有任何有用信息。

9个回答

52

在 Visual Studio 2003 中将文件复制到输出目录,可以使用 Post-Build 事件:

  1. 右键单击项目->属性
  2. 常规属性->生成事件
  3. 将 Post-Build 事件命令行设置为:

  4. xcopy /y $(ProjectDir)my_file.ini  $(ProjectDir)$(OutDir)
    
  5. 好的,开始构建吧!


1
那也可以(虽然你不需要xcopy,copy也可以),但问题在于它需要将文件名硬编码到项目的构建属性中。按照我展示的方式进行可以让我们单独处理每个文件并使用宏来处理文件名。 - Synetech
这要看你使用的 Visual Studio 版本。这个人特别提到了 VS 2003,而我有一个项目在其中,这对我很有帮助。2003 版本的设置很糟糕——你甚至不能在每个文件的属性上指定任何内容,比如“复制到输出目录”。 - David Storfer
1
如果您希望在项目无需构建且已经是最新的情况下仍要复制文件,请将该文件添加到项目中。 - Jonathan Livni
2
难道不应该只是$(OutDir)吗?$(ProjectDir)已经包含在其中了(除非您修改了输出位置)。您只想使用输出目录。 - Mary Ellen Bench
7
由于可能包含空格的目录路径,应该使用如下命令进行拷贝:copy /y "$(ProjectDir)my_file.ini" "$(OutDir)"。 - KIM Taegyoon
就个人经验而言,在 VS 2013 中,我发现 $(OutDir) 无法正常使用。必须使用组合语句 $(ProjectDir)$(OutDir)。这可能是因为 $(OutDir) 是相对路径,而后期构建步骤未能正确处理它。 - Tony Pulokas

38

请尝试在“解决方案资源管理器”中选择文件。然后,您应该能够在“属性窗口”中看到它的属性(如果未显示,请按F4)。您会发现有两个属性:

  • "生成操作(Build Action)"和
  • "复制到输出目录(Copy to Output Directory)"

将"生成操作"设置为"内容(Content)",然后选择适当的值设置"复制到输出目录"。

带有"生成操作"和"复制到输出目录"设置的文件属性窗口

带有"生成操作"和"复制到输出目录"设置的文件属性窗口

如果上述方法对您无效,请阅读此帖子“.inf文件的复制到输出目录问题”。然后再查看这个帖子“Visual Studio:非默认文件类型的默认生成操作”。


2
VS2003似乎没有那个功能(出于某种原因)。 - Synetech
3
适用于某些项目类型,但并非全部。例如,对于类似C#的项目类型可以使用,但对于C++则不行。 - B.K.
@B.K. 这是由于 MS Build 任务的原因,不同项目类型可能会有所不同。您可以尝试进行调整。从这里开始挖掘 https://social.msdn.microsoft.com/Forums/vstudio/en-US/af6501ed-a02c-487f-9cd1-b4bee2af3904/msbuild-custom-build-action-in-visual-studio-2010-on-c-project?forum=msbuild - Dmitry Pavlov
@DmitryPavlov没关系;我只是想指出它并不适用于任何地方。 - B.K.
@B.K. 当然,没有什么东西是在任何地方都有效的。很棒VS允许开发人员扩展并几乎做所有他们可能需要的事情。 - Dmitry Pavlov
显示剩余2条评论

8
当我在搜索文件的属性页面查找构建操作字段时,我有了一个想法:将自定义构建步骤设置为手动“复制”该文件。这比我想象的要容易。我原本以为这需要使用“cmd”或其他外部可执行文件(如“xcopy”,“robocopy”等),但事实并非如此。
我按以下方式设置自定义构建步骤:
Command Line : copy $(InputFileName) $(OutDir)
Description  : Copying foobar...
Outputs      : $(InputFileName)

正确设置输出字段非常重要,可以避免VS始终认为项目已过期并需要重新构建(我不确定是否需要在前面加上$(OutDir)\)。

在“输出”窗口中会反映出如下内容:

Copying foobar...
        1 file(s) copied.
Compiling resources...
Linking...

对于我来说,使用VS2015时,它是这样的:命令行: copy "%(FullPath)" "$(OutDir)" 描述: copy "%(FullPath)" "$(OutDir)"输出: %(FileName).%(Extension) - Fantastory

7

对于 VS 2017,Dmitry Pavlov 发布的命令如下:

xcopy /y "$(ProjectDir)my_file.ini"  "$(OutDir)"

如果项目目录中包含空格,引号就非常重要。


5

对Synetech的回答进行扩展。

在VS2019中,右键单击您要复制的文件,选择“属性”。然后在“常规”>>“项目类型”下更改为“复制文件”,然后点击应用。
现在,在属性页面中应该有目标等UI字段。


1
没有“项目类型”,只有“文件类型”,也没有“复制文件”选项。 - user7082181

3

如果有人需要帮助,我需要将正在构建的项目的输出dll复制到另一个项目中。

xcopy /y "$(ProjectDir)$(OutDir)$(TargetName)$(TargetExt)" 
"C:\Application\MyApplicationName\bin\x86\Debug"

/y = overwrite file if already exists
$(ProjectDir) = location on your machine where the project lives
$(OutDir) = is where your current build setup outputs the build
$(TargetName) = What the project being built is set to be called. Ex: XXX of XXX.dll
$(TargetExt) = the extension of the build Ex: .dll of XXX.dll

"C:/..../x86/Debug" is the location to copy to.

0

你需要额外的$(OutDir)。否则,在重建/清除步骤中,它将丢弃你的源代码。

CommandLine : copy "$(SolutionDir)last-script.js" "$(TargetDir)Debug"

Outputs  : $(TargetDir)Debug\last-script.js

0

改进Synetech的答案:

在VS 2013 C++项目命令行中:copy %(Identity) $(OutDir)。描述:复制foobar... 输出:%(Identity)。这个方法可以工作,但会导致循环依赖,即每次要求增量构建时都会执行它,无论它是否已经被复制。

为了解决这个问题,您可以将该项添加到目标文件夹中,将路径更改为$(OutDir),并在第一个添加的项中使用它作为输出。缺点是解决方案中有两个名称相似的项。

此外,在postbuild中使用带有/d /y参数的xcopy - 仅在目标文件日期较旧时才进行复制,也是非常有用的。


0

你也可以在卸载项目后(右键单击项目 >> 卸载项目),将以下内容添加到现有的 <ItemGroup> 标记中:

<Content Include="..\..\Config\db.config">
  <Link>Config\db.config</Link>
  <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  <SubType>Designer</SubType>
</Content>

在这种情况下,它将从上面的2个文件夹中获取db.config文件,并在创建一个包含db.config文件的Config文件夹后,将其放入输出文件夹(默认为bin/Debug)。

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