MSBuild build order

2019-02-07 22:49发布

问题:

I have a large solution with more than 100 projects (C++, Managed C++, C#) and many of them depends on each others.

I have a TeamCity server and I want build this solution there.

When I build solution in VisualStudio everything goes fine, but with TeamCity I have a CS0006 error. I know why that so - TeamCity uses MSBuild 4 to build solutions, but there is a known bug in MSBuild 4 - it ignores build order and build projects from solutions in order it wants. Because of this behavior if you have:

Project A
Project B which has reference to A

MSBuild can build these project in such order:

1. B
2. A

The easiest solution is to set BuildProjectReferences=true (which is default) and all referenced project will be builded automatically. But I can't use this approach because not all referenced project in this solution, and I can't build projects from another solution.

Here is another fix for this problem - use ConfigurationManager and disable all projects, which shouldn't build, but it works only in VisualStudio - MSBuild ignores that and builds all referenced projects.

The problem is to restore build order which I can see in VisualStudio in window ProjectBuildOrder which is not true if I use MSBuild directly from Console.

回答1:

See Incorrect solution build ordering when using MSBuild.exe at The Visual Studio Blog:

Follow this principle: do not use dependencies expressed in the solution file at all! Better to express dependencies in the file that has the dependency: put a project reference in the project, instead. In our example, that would be a project reference from B to C.

You may not have done that before because you didn’t want to reference the target of the project reference, but merely order the build. However, in 4.0 you can create a project reference that only orders the build without adding a reference. It would look like this – note the metadata element, and all this is inside an <ItemGroup> tag of course:

<ProjectReference Include="foo.csproj">
    <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>

Note that you have to add the child element with a text editor — Visual Studio can add a project reference, but doesn’t expose UI for this metadata.

I can tidy up by removing the dependency in the solution file as well – removing now-unnecessary lines like this — your GUID will be different, but use the VS dialog and it will do the job...



回答2:

I had a problem much like this. It manifested itself in the solution, by requiring two builds before successfully building the entire solution.

As it turns out, I had accidentally added a Reference and not a ProjectReference (look for this in the .sln file), meaning VS/MSBuild would require and look for the referenced library file, but be completely unaware of how to build it if it was missing. Eventually the build process would come around to the project with the referenced library, building it and making it available for the next build attempt.

Depending on your dependency tree and the particular mood of the MS toolchain, this could turn up as a sporadic error, and thus be a bitch to debug.

Short version: Make sure references to projects inside the solution are listed as ProjectReference and not just Reference. Do this by adding the reference on the Solution tab instead of browsing and picking the DLL file.