【问题标题】:Copy all files and folders using msbuild使用 msbuild 复制所有文件和文件夹
【发布时间】:2010-09-12 06:24:50
【问题描述】:

只是想知道是否有人可以帮助我编写一些我正在尝试编写的 msbuild 脚本。我想做的是使用 msbuild 将所有文件和子文件夹从一个文件夹复制到另一个文件夹。

{ProjectName}
      |----->Source
      |----->Tools
              |----->Viewer
                       |-----{about 5 sub dirs}

我需要做的是将所有文件和子文件夹从工具文件夹复制到应用程序的调试文件夹中。这是我到目前为止的代码。

<ItemGroup>
    <Viewer Include="..\$(ApplicationDirectory)\Tools\viewer\**\*.*" />
</ItemGroup>

<Target Name="BeforeBuild">
    <Copy SourceFiles="@(Viewer)" DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" />
</Target>

构建脚本运行但不复制任何文件或文件夹。

谢谢

【问题讨论】:

    标签: build scripting msbuild


    【解决方案1】:

    我也在寻找这方面的帮助。我花了一段时间,但这是我所做的,效果非常好。

    <Target Name="AfterBuild">
        <ItemGroup>
            <ANTLR Include="..\Data\antlrcs\**\*.*" />
        </ItemGroup>
        <Copy SourceFiles="@(ANTLR)" DestinationFolder="$(TargetDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
    </Target>
    

    这递归地将名为antlrcs的文件夹的内容复制到$(TargetDir)

    【讨论】:

    • 是的,这是最好的答案。与 msdn 博客上推荐的相同:blogs.msdn.com/b/msbuild/archive/2005/11/07/490068.aspx
    • 诀窍似乎是将%(RecursiveDir) 添加到目标文件夹将重新创建目录结构。否则输出是平坦的。这是最佳答案。
    • 需要放在.fsproj文件的底部,不然不用。
    • 对我有用的关键时刻是在 AfterBuild 下移动变量声明 ()目标。在我的情况下,它是在外部范围内声明的并且不起作用。
    • 这是个好主意!我在 MSBuild 知名项元数据 中找到了%(RecursiveDir)docs.microsoft.com/en-us/visualstudio/msbuild/…
    【解决方案2】:

    我认为问题可能在于您如何创建 ItemGroup 和调用 Copy 任务。看看这是否有意义:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        <PropertyGroup>
            <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
            <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
        </PropertyGroup>
    
        <Target Name="BeforeBuild">
            <CreateItem Include="$(YourSourceDirectory)\**\*.*">
                <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
            </CreateItem>
    
            <Copy SourceFiles="@(YourFilesToCopy)"
                    DestinationFiles="@(YourFilesToCopy->'$(YourDestinationDirectory)\%(RecursiveDir)%(Filename)%(Extension)')" />
        </Target>
    </Project>
    

    【讨论】:

    【解决方案3】:

    我对 MSBuild 有点陌生,但我发现 EXEC 任务在这种情况下很方便。我在我的项目中遇到了同样的挑战,这对我有用,而且要简单得多。如果这不是一个好习惯,请告诉我。

    <Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
        <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
    </Target>
    

    【讨论】:

    • 我敢反过来问这个问题。是否有任何理由使用日志填充 msbuild 复制任务?
    • 可能。如果您有构建场(Jenkins、TeamCity 等),代理服务可能会在路径中没有 xcopy 的不同帐户下运行。您可以在路径中尝试 %windir%\system32 之类的东西,但即使这样有时也不起作用。
    • 这是对我有用的解决方案。我也不需要设置 WorkingDirectory。
    • 仅供参考,我需要添加 /Y 来禁止文件/文件夹覆盖提示。另外如果$(DeploymentDirectory)是一个文件夹,在路径后留下一个“\”会去掉提示:“destination is folder or file?”
    • 我知道这个问题不会经常出现,但我使用Copy 任务而不是命令的主要原因是兼容性。我之前使用 Mono 在 Linux 上构建过,显然 xcopy 在那里不起作用。
    【解决方案4】:
    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
        <PropertyGroup>
            <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
            <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
        </PropertyGroup>
    
        <Target Name="BeforeBuild">
            <CreateItem Include="$(YourSourceDirectory)\**\*.*">
                <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
            </CreateItem>
    
            <Copy SourceFiles="@(YourFilesToCopy)"
                    DestinationFiles="$(YourFilesToCopy)\%(RecursiveDir)" />
        </Target>
    </Project>
    

    \**\*.* 帮助从所有文件夹中获取文件。 RecursiveDir 帮助把所有文件放到各自的文件夹中...

    【讨论】:

    • 目标文件是指 1 项,源文件是指 33 项。它们必须具有相同数量的项目。呃.. msbuild 可能很棒,但有时记录如此糟糕的垃圾。
    • CreateItem 任务已弃用。正则表达式有替代方案。 msdn.microsoft.com/en-us/library/s2y3e43x.aspx
    【解决方案5】:

    这是一个有效的例子:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
       <ItemGroup>
          <MySourceFiles Include="c:\MySourceTree\**\*.*"/>
       </ItemGroup>
    
       <Target Name="CopyFiles">
          <Copy
            SourceFiles="@(MySourceFiles)"
            DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')"
           />
        </Target>
    
    </Project>
    

    来源:https://msdn.microsoft.com/en-us/library/3e54c37h.aspx

    【讨论】:

      【解决方案6】:

      您是否尝试指定具体的目标目录而不是

      DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" ? 
      

      我对高级 MSBuild 语法不是很精通,但是

      @(Viewer->'$(OutputPath)\\Tools') 
      

      我觉得很奇怪。脚本看起来不错,所以问题可能出在 $(ApplicationDirectory)$(OutputPath) 的值上

      这是一篇可能有用的博文:

      How To: Recursively Copy Files Using the <Copy> Task

      【讨论】:

      • 链接+1,比zXen接受的答案更简洁。
      【解决方案7】:

      这是我在我自己的项目中使用的复制任务,它对我来说非常有效,可以成功地将带有子文件夹的文件夹复制到目的地:

      <ItemGroup >
      <MyProjectSource Include="$(OutputRoot)/MySource/**/*.*" />
      </ItemGroup>
      
      <Target Name="AfterCopy" AfterTargets="WebPublish">
      <Copy SourceFiles="@(MyProjectSource)" 
       OverwriteReadOnlyFiles="true" DestinationFolder="$(PublishFolder)api/% (RecursiveDir)"/>
      

      在我的情况下,我将项目的发布文件夹复制到另一个目标文件夹,我认为这与您的情况类似。

      【讨论】:

      • 其他答案都不适用于 Sdk 类型的项目,因为没有调用“AfterBuild”。像您一样设置“AfterTargets”依赖项是让目标在“现代”msbuild 中触发另一个目标的适当方法。就我而言,我使用 AfterTargets="Build" 将一些 dll 复制到另一个文件夹。
      【解决方案8】:

      我个人使用了 CopyFolder,它是 SDC 任务库的一部分。

      http://sdctasks.codeplex.com/

      【讨论】:

        【解决方案9】:

        使用 MSBuild 将文件从一个目录递归复制到另一个目录的最佳方法是使用带有 SourceFiles 和 DestinationFiles 作为参数的 Copy 任务。例如 - 将所有文件从构建目录复制到备份目录将是

        <PropertyGroup>
        <BuildDirectory Condition="'$(BuildDirectory)' == ''">Build</BuildDirectory>
        <BackupDirectory Condition="'$(BackupDiretory)' == ''">Backup</BackupDirectory>
        </PropertyGroup>
        
        <ItemGroup>
        <AllFiles Include="$(MSBuildProjectDirectory)/$(BuildDirectory)/**/*.*" />
        </ItemGroup>
        
        <Target Name="Backup">
        <Exec Command="if not exist $(BackupDirectory) md $(BackupDirectory)" />
        <Copy SourceFiles="@(AllFiles)" DestinationFiles="@(AllFiles-> 
        '$(MSBuildProjectDirectory)/$(BackupDirectory)/%(RecursiveDir)/%(Filename)% 
        (Extension)')" />
        </Target>
        

        现在在上面的复制命令中遍历所有源目录并将文件复制到目标目录。

        【讨论】:

          【解决方案10】:

          如果您使用的是典型的 C++ 工具链,另一种方法是将您的文件添加到标准 CopyFileToFolders 列表中

          <ItemGroup>
            <CopyFileToFolders Include="materials\**\*">
              <DestinationFolders>$(MainOutputDirectory)\Resources\materials\%(RecursiveDir)</DestinationFolders>
            </CopyFileToFolders>
          </ItemGroup>
          

          除了简单之外,这是一个不错的方法,因为 CopyFilesToFolders 任务将生成适当的输入、输出甚至TLog files,因此确保复制操作仅在输入文件之一或输出之一发生更改时运行文件丢失。借助 TLog,Visual Studio 还将正确地将项目识别为“最新”或不是(它为此使用了单独的 U2DCheck 机制)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-09-20
            • 1970-01-01
            • 1970-01-01
            • 2011-07-04
            • 2022-11-10
            相关资源
            最近更新 更多