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?