When using
MSBuild you may find your self wanting to copy some existing directory structure somewhere.
If you have a directory structure, the output of a solution for example, like the following:
output_dir/
- bin/
- thing.dll
- thing.pdb
- lib/
- thing.lib
- inc/
- thing.h
You'll notice that doing this:
<ItemGroup>
<out_files Include='output_dir/**/*'/>
</ItemGroup>
<Target Name='copy_files'>
<Copy SourceFiles='@(out_files)' DestinationFolder='deployment_dir'/>
</Target>
Will flatten your output file structure to this:
deployment_dir/
- thing.dll
- thing.pdb
- thing.lib
- thing.h
In order to preserve your file structure you could create separate specifications for the
bin/
,
lib/
and
inc/
directories (which would not only add a maintenance burden in the case that these directories changed, but also require you to type them out in the first place) or you could simply take advantage of the metadata that MSBuild attaches to the path information it returns from a recursive directory search.
The
RecursiveDir
property is attached to each file name in the array yielded by the search; it holds the value of the recursive directory directive (
**
) as evaluated for each file found, so doing this:
<ItemGroup>
<out_files Include='output_dir/**/*'/>
</ItemGroup>
<Target Name='copy_files'>
<Copy SourceFiles='@(out_files)' DestinationFolder='deployment_dir/%(out_files.RecursiveDir)'/>
</Target>
Will give you the structure you were after:
deployment_dir/
- bin/
- thing.dll
- thing.pdb
- lib/
- thing.lib
- inc/
- thing.h
You've got loads of control over what gets captured too, say you want to exclude debug symbols, you'd do this:
<ItemGroup>
<out_files Include='output_dir/**/*' Exclude='output_dir/**/*.pdb'/>
</ItemGroup>
<Target Name='copy_files'>
<Copy SourceFiles='@(out_files)' DestinationFolder='deployment_dir/%(out_files.RecursiveDir)'/>
</Target>
To get this:
deployment_dir/
- bin/
- thing.dll
- lib/
- thing.lib
- inc/
- thing.h
Using these constructs allows you to manage builds of multiple solutions from a central MSBuild project without requiring that that project know all the solutions' intimate details - it gives you good separation of concerns and hence fewer headaches.