2

I have a Visual Studio solution comprised of five C# projects. Four of the projects are application assemblies, the fifth is an MsTest project. The dependencies between the assemblies are as follows:

Model
   Common

Ui
   Model
      Common
   UiCommon

TestProject
   Common
   Model
   Ui
   UiCommon

The application is split into frontend (Ui) and backend (Model) assemblies. Both these assemblies depend on a utility class library (Common), the Ui assembly has an additional dependency on another class library (UiCommon). The test project has dependencies on all the other projects.

If I rebuild TestProject from VS2015 it performs a multithreaded build starting with Common and UiCommon at the same time (as they don't depend on each other), followed in turn by Model and finally Ui. Each project first has its CoreClean MsBuild target executed followed by CoreCompile. This works fine.

If I instead build using MsBuild directly invoking target Rebuild then it behaves completely differently and ultimately fails to build the project due to trying to build in a stupid order that can't possibly work.

Under MsBuild the TestProject starts by executing target CoreClean on Model, which performs CoreClean on Common as a subtask. Control returns to the TestProject which calls CoreClean on Ui, after which control returns to TestProject again which calls CoreClean on UiCommon. After this TestProject calls CoreCompile on Model, which as a subtask calls CoreCompile on Common, then control returns to TestProject which then calls CoreCompile on Ui (which fails because UiCommon is not built), after which control returns to TestProject which calls CoreCompile on UiCommon which builds (but which is pointless since the build has already failed due to Ui assembly being built before UiCommon).

So MsBuild is recognising the dependence of Model on Common and cleaning and building those projects in the correct order to handle that, yet is failing to recognise the dependence of Ui on UiCommon despite that reference being defined in exactly the same way. Why should that be?

And the other thing that's odd is that rebuilding TestProject under VS2015 each project is cleaned and built in turn prior to any subsequent dependent project being cleaned and built. Whereas rebuilding TestProject with MsBuild directly results in all projects being cleaned followed by all projects being built. Why should that happen?

According to the MSDN VS2015 uses MsBuild to perform the build on the same project file as I'm passing to MsBuild when I invoke MsBuild directly. I've checked that the same (14.0.25420.1) version of MsBuild is being called in both cases, and yet the build proceeds in a completely different manner in each case.

Both builds use the same project files that define the dependencies between the projects and I haven't made any changes to those files that should cause VS and MsBuild to behave differently. I'm aware that I can override Visual Studio's multi-threaded build behavior, but I don't think that is the cause of the problem. I also recall that in the past Visual Studio has used info from the Solution file regarding intra-project dependencies but thought that mess was all in the past now and that these days that was all defined in the project files.

This doesn't make any sense to me, does anyone have a clue what is going on here please?

Neutrino
  • 8,496
  • 4
  • 57
  • 83
  • The same build engine is used by VS and msbuild.exe command line tool. So there should be no difference -- however there are different defaults -- VS builds multi-threaded by default, while command line tool defaults to single threaded build. Use option /m on command line to run multi-threaded build. However even if would make the build going, it won't fix the root cause of the problem. You likely have some custom target that does not take project dependency into account. My suggestion is turn on msbuild logging and carefully examine msbuild.log. – seva titov Aug 10 '16 at 19:28
  • Another common problem, besides incorrectly written custom targets, is having two or more project use the same output files or same obj folder. Make sure the output of projects are separated. MSBuild tracks dependencies by file timestamps, which means that if two projects share the same output, only one will be built, the other will be skipped. – seva titov Aug 10 '16 at 19:31
  • @Neutrino >>Each project first has its CoreClean MsBuild target executed followed by CoreCompile How do you do that? Change DefaultTargets or Specify before build target? – starian chen-MSFT Aug 11 '16 at 09:29
  • That's the point. I'm not even doing it. MsBuild is doing that differently by itself despite me using the Rebuild All command in Visual Studio and passing the RebuildAll target to MsBuild. I've no idea why it behaves so completely differently. – Neutrino Aug 11 '16 at 14:05
  • @Neutrino, how did you run your solution using MSBuild? Could you share a screen shot about the MSbuild error? Like this case I meet here: http://stackoverflow.com/questions/38736860/msbuild-does-not-respect-sln-file-settings, do you add all solution platforms? – Jack Zhai Aug 12 '16 at 12:49
  • @Neutrino rebuild target will clean projects before build projects. Based on my test, it works fine. Could you reproduce that issue with new solution and projects? You can share a sample project on OneDrive. Which MSBuild tool you used? In C:\Program Files (x86)\MSBuild\14.0\Bin, other or use MSBuild Command Prompt for VS 2015? What detail command you called? – starian chen-MSFT Aug 15 '16 at 05:57
  • @Jack I'm not building the solution I'm building the project using msbuild.exe TestProject.csproj /t:Rebuild /p:Configuration=Debug,Platform=x86 /m:1 > build.log – Neutrino Aug 15 '16 at 12:25
  • I noticed that the UiCommon reference in Ui was a binary reference instead of a project reference. I think this is at the root of the issue. Our build system builds each project in the codebase and in some cases we have references to other project's binaries because otherwise a RebuildAll will rebuild every shared project each time it is referenced. – Neutrino Aug 15 '16 at 12:30
  • I had to task switch on Friday and shelf a load of outstanding code in SVN, which because it was a mixed version working copy caused a load of mess that I'm still sorting out. – Neutrino Aug 15 '16 at 12:31

1 Answers1

0

I noticed that the UiCommon reference in Ui was a binary reference instead of a project reference.

Yes, this is the issue, for binary reference, it won’t build related project before build current project. As you said that other projects have project reference to UiCommon, so UiCommon will be clean and combine during TestProject rebuild. So change that project reference type to project reference.

starian chen-MSFT
  • 33,174
  • 2
  • 29
  • 53