MSBuild project file: Copy item to specific location in output directory

chezy525 picture chezy525 · May 6, 2011 · Viewed 32k times · Source

In the process of cleaning up the folder/file structure on a project I inherited, I'm running into a problem with organizing the required external libraries. I want to keep them in their own .\dll\ folder, but they're not being copied to the build directory properly. They should be in the root build directory, but they're being moved to a subfolder instead.

My .csproj file contains the following xml:

<Project>
  <ItemGroup>
    <None Include="dlls\libraryA.dll">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Then, on build, the libraryA.dll file is copied to the bin\Debug\dll\ folder, but I want it in the bin\Debug\ folder.

Answer

Brian Walker picture Brian Walker · May 6, 2011

I tried this and msbuild always wants to copy the files using their directory path, but there is a workaround...

Edit the csproj file and after this line:

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

Add these lines:

  <PropertyGroup>
    <PrepareForRunDependsOn>$(PrepareForRunDependsOn);MyCopyFilesToOutputDirectory</PrepareForRunDependsOn>
  </PropertyGroup>

  <Target Name="MyCopyFilesToOutputDirectory">
    <Copy SourceFiles="@(None)" DestinationFolder="$(OutDir)" />
  </Target>

The copy of the output files happens in the PrepareForRun target. This adds your own target to the list of targets that are executed as part of PrepareForRun.

This example copies all items in the None item group. You could create your own item group (e.g. MyFiles) and do the copy on that item group if you have other "None" files you don't want copied. When I tried this I had to change the item group name by editing the csproj file directly. Visual Studio did not allow me to set the item group of a file from the UI, but after I edited the csproj and changed it, Visual Studio displayed my custom item group name correctly.