Search code examples
visual-studiomsbuildconan

How to use an msbuild CopyTask to copy a list of directories recursively


I would like to copy a list of directories recursively using a CopyTask.

The list is defined by a macro like so;

<ConanBinaryDirectories>some/path/;another/path/;</ConanBinaryDirectories>

I know a CopyTask can copy a single directory recursively, but how to deal with the specified format.


Solution

  • The ConanBinaryDirectories seems to be a MSBuild Property. If so, I assume you can use Msbuild Property Functions to get the single path.

    Something like this:

    <PropertyGroup>
        <ConanBinaryDirectories>C:\Users\xxx\Desktop\Path1;C:\Users\xxx\Desktop\Path2;</ConanBinaryDirectories>
      </PropertyGroup>
    
      <PropertyGroup>
        <SourcePath1>$(ConanBinaryDirectories.Split(";")[0])</SourcePath1> //C:\Users\xxx\Desktop\Path1
        <SourcePath2>$(ConanBinaryDirectories.Split(";")[1])</SourcePath2> //C:\Users\xxx\Desktop\Path2
      </PropertyGroup>
    

    After you get the property which represents the single directory, you can use either 1.Copy task or 2.Exec task with xcopy command in it like this to copy the single directory to destination path.

    All you need to do is to call the corresponding task twice in your custom target.

    I know maybe what you want when you ask this question is a way like turn the MSBuild property to an MSBuild Item as the input of a task and do the copy job. But after my check: 1. The msbuild copy task actually doesn't support the input format like this some/path/ 2.We can use something like some/path/**/*.*, but it doesn't work well when our input could be something like @(...)/**/*.*.

    So I suggest you split the macro to several paths and then use them into copy job.

    Update:

    The msbuild property doesn't support wildcard well. So to use something like **/*.*, you need to use Item instead of Property. You can have a look at this similar issue.

    For a Property whose value is Path/*.*, it only represents a string Path/*.* most of the time while for an Item <MyItem Include="Path/*.*"/>, it represents all the files in the specified path. So no matter which way(copy task or xcopy command) we choose to do the copy job,the input should be an Item.

    The script which works after test:

    <PropertyGroup>
    

    C:\Users\xxx\Desktop\Path1;C:\Users\xxx\Desktop\Path2

      <PropertyGroup>
        <SourcePath1>$(ConanBinaryDirectories.Split(";")[0])</SourcePath1>
        <SourcePath2>$(ConanBinaryDirectories.Split(";")[1])</SourcePath2>
      </PropertyGroup>
    
      <ItemGroup>
        <MySourceFiles Include="$(SourcePath1)\**\*.*" />
        <MySourceFiles Include="$(SourcePath2)\**\*.*" />
      </ItemGroup>
    
      <Target Name="TestItem" AfterTargets="build">
        <Copy SourceFiles="@(MySourceFiles)" DestinationFolder="$(OutputPath)"/>
      </Target>
    

    $(OutputPath) for C#, $(OutDir) for C++.