|
| 1 | +# Build Scenarios and Major Users |
| 2 | + |
| 3 | +## Scenarios |
| 4 | + |
| 5 | +MSBuild is used in a huge variety of ways, each with its own behavioral and performance characteristics. |
| 6 | + |
| 7 | +### Batch builds |
| 8 | + |
| 9 | +The most straightforward invocation of MSBuild is a batch build--a direct invocation of `dotnet build` or `MSBuild.exe` on a project or set of projects. This can run from a clean state, requiring all tools to run as well as all of MSBuild's overhead computation. |
| 10 | + |
| 11 | +Depending on the size of the codebase, these builds are usually dominated by tool execution, such as the C# compiler. Other build tasks like `Copy` and ASP.NET static-asset handling are also often contributors. |
| 12 | + |
| 13 | +This scenario is critical for: |
| 14 | + |
| 15 | +* Clean repo checkout |
| 16 | +* CI/PR/Official builds (usually from clean though not always) |
| 17 | + |
| 18 | +### Incremental batch builds |
| 19 | + |
| 20 | +MSBuild tries to avoid doing unnecessary work when projects have already been built. It uses file input and output lists to avoid executing targets when possible. Unfortunately, checking whether a target is up to date still has costs, and the overhead of MSBuild evaluation can also be a major factor in incremental build performance. |
| 21 | + |
| 22 | +In the limit, a fully-up-to-date build is instructive for the MSBuild team, because an *ideal* fully up-to-date build would take no time to run. If you do `dotnet build && dotnet build`, any time spent in the second one should be overhead (barring an incrementality bug in the projects). |
| 23 | + |
| 24 | +This scenario is critical for: |
| 25 | + |
| 26 | +* Dev inner loop |
| 27 | +* Optimizing constant overhead |
| 28 | + |
| 29 | +### IDE load |
| 30 | + |
| 31 | +IDEs like Visual Studio and C# Dev Kit need to understand |
| 32 | + |
| 33 | +* What sources to parse and analyze |
| 34 | +* What build configurations exist |
| 35 | +* What compiler flags each configuration will set. |
| 36 | + |
| 37 | +Ideally, this would result in a model (to power IntelliSense completion, go-to-definition, and other editor tools) that *exactly* matches the way compilation will be executed in a batch build (and ideally a batch build that produces deployable bits). However, the IDE load scenario is extremely performance sensitive, since a repo or solution may contain hundreds of projects that need to be understood before the load (and editor functionality) is complete. |
| 38 | + |
| 39 | +Because MSBuild is so dynamic, the required information is generally extracted via a [design-time build](), which runs a subset of the build: ideally enough to generate the information required to run a compiler, but no more. Differences between design-time build and batch build can result in errors that are extremely confusing to the users (editor squiggles that don't show up in builds, or vice versa). |
| 40 | + |
| 41 | +### IDE build |
| 42 | + |
| 43 | +After projects are loaded into an IDE, the user may invoke a build directly or indirectly (for instance with a start-debugging command). These builds can differ from batch builds dramatically, since IDEs like Visual Studio may choose to build projects in isolation. This can be motivated by supporting non-MSBuild project types (as Visual Studio does), or by a desire to reduce IDE incremental build time by avoiding MSBuild overhead using [fast up-to-date checks]() that decide whether to invoke a project build based on a higher-order model of the project-level inputs and outputs. |
| 44 | + |
| 45 | +### Project-level caching |
| 46 | + |
| 47 | +Repos using MSBuild's project caching plugin system are [graph-based]() builds that consult the cache plugin before starting to build each project. The cache plugin can provide cached results for a project based on the state of the system or allow the build to continue (and possibly add results to a cache). |
| 48 | + |
| 49 | +Because the build is graph-based, graph-construction time (dominated by evaluation time) is a major factor for these builds when up to date or mostly cached. |
| 50 | + |
| 51 | +### Higher-order build systems |
| 52 | + |
| 53 | +MSBuild can be invoked as part of a higher-order build system like [CloudBuild]() or [BuildXL](). Generally in these cases the higher-order build system often constructs and walks the graph, making MSBuild evaluation and execution time (of only out-of-date projects) the critical path. |
| 54 | + |
| 55 | +## Major Users/Use Cases |
| 56 | + |
| 57 | +| User Scenario | Specific actions tied to this scenario | |
| 58 | +| - | - | |
| 59 | +| VS Evaluation | Initial load, solution switch, branch switch. Used to populate IDE data. Often a blocker to light up other IDE functionality. | |
| 60 | +| VS Solution Build | F5 debugging, running tests | |
| 61 | +| VS Design-time Build | Used to populate IDE functionality (right-click commands, views like the Dependencies node, etc) | |
| 62 | +| CLI Evaluation | Used by many core CLI Commands: build, publish, restore, clean, test, workload restore, run, package management, watch. Has large impact on dev inner loop at the CLI. Clients of these commands: aspire, azure dev CLI, VS Code | |
| 63 | +| MSBuild API-based Evaluation | dotnet run and other commands do multiple evaluations to get data to use. this increases cycle times. dotnet new console currently spends 2.8s doing the build: 2 evaluations, 440ms. 1 restore: 220ms. 1 build: 2.1 s. and then another 310ms evaluating the required data to run. | |
| 64 | +| CLI Run | used by: single-file feature in .NET 10, Aspire - once for the apphost, once for each referenced app project | |
| 65 | +| CLI Publish | used by: ci/cd pipelines, Aspire publishing, azd publishing | |
0 commit comments