0
votes

I'm sure there is something small that I'm missing. Here's the problem:

I have a solution that has multiple projects which after each build will be zipped. Here is an example of the zip creation in one project (they are pretty much identical in others):

<ItemGroup>
  <CopySourceFiles Include="$(OutDir)\**\*.*" Exclude="$(OutDir)\**\*.pdb;$(OutDir)\*.mdf;$(OutDir)\*.ldf;$(OutDir)\*.vshost.*" />
</ItemGroup>

...

<Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  <MakeDir Directories="$(OutDir)\..\zip_working" />
  <!-- first copy the source files specified in the CorySourceFiles ItemGroup above. -->
  <Copy SourceFiles="@(CopySourceFiles)" DestinationFiles="@(CopySourceFiles->'$(OutDir)\..\zip_working\%(RecursiveDir)%(Filename)%(Extension)')" />
  <!-- Perform the zip by calling the UsingTask. Make sure the DestinationFiles above and the SourceDirectory below are pointing to the same place -->
  <Zip SourceDirectory="$(OutDir)\..\zip_working" OutputFilename="$(OutDir)\..\zip\$(ProjectName).zip" />
  <!-- Clean up. -->
  <RemoveDir Directories="$(OutDir)\..\zip_working" />
</Target>

There is a final project which has links to the zipped files that it combines into a package. All appears normal, but apparently only when the bin and zip_working folders already exist. I.e. if I clean the solution, delete the bin folders and then rebuild, the final zip that is created in the "zip" folder for each project is empty...

And then the zip files have content only after I build again.

So I'm guessing that during the build process, the AfterBuild target is running before the build output files exist. Does that sound right? I trigger the builds purely from within Visual Studio.

Regardless, how can I ensure that I can run a task on build output files only after they've been created?


Applies to Visual Studio 2013 Update 5 / MSBuild 12.0

1
please mention which verson of VS/msbuild since there are differences in how AfterBuild is treated (see stackoverflow.com/questions/13727351/… for example)stijn
@stijn Sure - Visual Studio 2013 Update 5/MSbuild 12.0Balah
thanks, just figured it probably doesn't matter though: seems more likely that the propblem is simply msbuild evaluation order: CopySourceFiles is evaluated when the project is loaded. Hence, if there are no files at that time it will be empty. Try moving the ItemGroup containing CopySourceFiles into the AfterBuild target so it gets evaluated when it should.stijn
@stijn That was exactly it! I moved the ItemGroup into the AfterBuild target as you said and it worked perfectly. Thanks again :)Balah

1 Answers

3
votes

If you delete everything in OutDir and then build the project, a top-level (as in, not inside a target) ItemGroup is evaluated before the build even starts. Some info can be found here for example. In other words, before a build and with an empty OutDir $(OutDir)\**\*.* evaluates to nothing and your CopySourceFiles item is empty.

The solution is simply to move the ItemGroup inside of the AfterBuild target. It will then be evaluated after the build and hence gets a proper view on the current files in outDir.