20

I am debugging a bug in my build process that happens occasionally but I can't directly reproduce it. I'm using msbuild with teamcity.

I have a dependency hierarchy like this:

Some.Interop.dll
   Dependency-> SharedDllABC.dll

SomeService.exe
   Depenendcy-> Some.Interop

Usually the final service exectuable gets in its release directory:

Some.Interop
SharedDllABC.Dll
ServiceExectuable.exe

However I can see in our msbuild logs that sometimes the tertiary dependency gets deleted during an Incremental Clean after everything is built resulting in:

Some.Interop
ServiceExectuable.exe

You can see it here in the msbuild log:

[src\SomeService\SomeService.csproj] _TimeStampAfterCompile
[12:32:43]:  [src\SomeService\SomeService.csproj] Compile

// some other targets

[12:32:43]:  [src\SomeService\SomeService.csproj] _CopyFilesMarkedCopyLocal
[12:32:43]:      [_CopyFilesMarkedCopyLocal] Copy
[12:32:43]:          [Copy] Copying file from "C:Projects\trunk\src\Some.Interop\bin\Release\Some.Interop.dll" to "bin\Release\Some.Interop.dll".

// some other targets

[src\Project\SomeService\SomeService.csproj] IncrementalClean
[18:54:42]:         [IncrementalClean] Delete
[18:54:42]:             [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeService\bin\Release\SharedDllABC.dll".
[18:54:42]:             [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeServiceService\bin\Release\SharedDllABC.pdb".
[18:54:42]:     [src\Project\SomeService\SomeService.csproj] CoreBuild
[18:54:42]:     [src\Project\SomeService\SomeService.csproj] AfterBuild
[18:54:42]:     [src\Project\SomeService\SomeService.csproj] Build

This is my direct msbuild output, I just changed the project names/dll names to match my example. By the time this Incremental Clean has occurred the SomeService.csproj has already been built. You can see that its not getting copied. However in other msbuild logs it does properly get copied and then the incremental clean doesn't delete it.

I think incrementeal clean from this post is supposed to clean dll's that were created from previous builds, but that doesn't explain how this dll didn't get built when most of the time it does. In visual studio this always works as well.

I guess I just want to know what exactly is Incremental clean, what causes it to kick in, and maybe what things I should look for when debugging a situation like this (assembly versions, timestamps, etc?)

devshorts
  • 8,572
  • 4
  • 50
  • 73
  • 2
    `IncrementalClean` is implemented in `c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets`. There's quite a lot of logic in there... If you want to know more, add some prints in there - ``, and maybe you'll see what that logic is. – Jonathan Jul 22 '12 at 16:36
  • 1
    I'm having very similar problems. Did you ever find your culprit? – Sebastian Good Oct 18 '12 at 19:02
  • Sebastian, I wasn't able to ever figure it out. What I ended up doing was creating a hard dependency on this file from the project that needed it. It wasn't ideal but it does work. Some other solutions my team came up with was to create unit tests to test for expected dll's which would at least prevent failed builds from going out to clients/test machines. – devshorts Oct 18 '12 at 20:48
  • Ugh! Thanks for the update. I'll have to soldier on and figure out the problem here. Were you building from the command line using MSBuild or via Visual Studio (live or with devenv.exe?) – Sebastian Good Oct 19 '12 at 21:10
  • This was happening only with msbuild invoked live via a teamcity build. Building in visual studio never showed problems. – devshorts Oct 20 '12 at 01:27
  • 1
    This issue is occured in my project when I try to form package via msbuild. `msbuild.exe /t:Package` I don't know why Incremental clean removes dependent dll, but using explicit rebuild prevents this `msbuild.exe /t:Rebuild;Package` – Anatoliy Apr 27 '15 at 12:19
  • Possible duplicate of [Determining outputs of a ProjectReference in MSBuild without triggering redundant rebuilds](http://stackoverflow.com/questions/2325598/determining-outputs-of-a-projectreference-in-msbuild-without-triggering-redundan) – Paul Sweatte Oct 03 '15 at 02:50

4 Answers4

3

Try the following:

Add:

<Target Name="IncrementalClean" />

to a .targets file that's included in all projects.

From --> https://github.com/Microsoft/msbuild/issues/1054

ListenFirst
  • 139
  • 4
  • What about the "new" .csproj format (.NET SDK), this workaround doesn't work there with these settings `false` `false` `path\to\bin\$(Configuration)\` – Salaros Aug 31 '18 at 14:59
1

This could be caused by a bug in MsBuild: https://github.com/Microsoft/msbuild/issues/1054. A fix is proposed in the comments: https://github.com/Microsoft/msbuild/issues/1054#issuecomment-406438561

When MsBuild determines which items to copy from referenced projects, it should do this recursively but does not properly do this.

As a workaround the following can be added to each csproj.

<Target
    Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE" 
    BeforeTargets="_SplitProjectReferencesByFileExistence" 
    DependsOnTargets="AssignProjectConfiguration" 
/>
JJS
  • 6,431
  • 1
  • 54
  • 70
Kebabbi
  • 174
  • 3
  • 8
1

@Kebabbi recommends a good fix by editing a csproj file. As of MSBuild 15, there is a simple way to make this apply to all CSPROJ files, instead of editing each csproj file.

https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2017

Directory.Build.props and Directory.Build.targets Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.

However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.

Create a file Directory.Build.props, and place it adjacent to the SLN file.

<Project>
   <Target
     Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE" 
     BeforeTargets="_SplitProjectReferencesByFileExistence" 
     DependsOnTargets="AssignProjectConfiguration" />
</Project>
JJS
  • 6,431
  • 1
  • 54
  • 70
0

I just spent a few days trying to figure this out with a similar pattern. In our case it was nuget files that were being removed from the output folder.

NugetPackage (that drops files in x86/x64 subfolders in output folder)

LibraryA.dll
   Dependency-> NugetPackage

LibraryB.dll
   Dependency-> LibraryA.dll

In our case, we have a number of solution files that are built as part of an msbuild script in a certain order. The problem was that LibraryB.csproj was included in two solution files.

Solution1 builds and output files are all present.

Solution2 builds and sees that LibraryB.dll is present and up to date, so for some reason triggers the IncrementalClean that removes the NugetPackage files from the output folder.

Once I removed the LibraryB.csproj from solution 2, the problem is solved and the files are present in the output folder.

blackdemon
  • 131
  • 1
  • 4