When you specify the DestinationFolder task to copy, it takes all the items from the SourceFiles collection and copies them to the DestinationFolder. This is expected since the Copy task does not allow to determine which part of each element path must be replaced by a DestinationFolder in order to preserve the tree structure. For example, if your SourceDir collection is defined as follows:
<ItemGroup> <SourceDir Include="$(Source)\**\*" /> <SourceDir Include="E:\ExternalDependencies\**\*" /> <SourceDir Include="\\sharedlibraries\gdiplus\*.h" /> </ItemGroup>
What do you expect from the destination folder tree?
To save the tree, you need to perform an identity transformation and create one destination for each element in the SourceFiles collection. Here is an example:
<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'$(DropPath)%(Identity)')" />
The Copy task takes each element in the SourceFiles collection and transforms its path, replacing the part before ** in the source specification with $ (DropPath).
It can be argued that the DestinationFolder property should have been written as a shortcut to the following conversion:
<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'$(DestinationFolder)%(Identity)')" />
Alas, this will prevent a deep copy script that you are trying to avoid, but other people can use them in the build process.
Franci penov
source share