Skip to content

Speed up builds with solution-level compile and output reuse - #1

Draft
Antaris wants to merge 1 commit into
mainfrom
cursor/faster-solution-builds-4458
Draft

Speed up builds with solution-level compile and output reuse#1
Antaris wants to merge 1 commit into
mainfrom
cursor/faster-solution-builds-4458

Conversation

@Antaris

@Antaris Antaris commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Builds were sequential and per-project. Each dotnet build on an app or test walked ProjectReferences, so a shared library was compiled again for every consumer. App publish had the same problem because it never passed --no-build.

This change keeps the Cake task, hook, and extension architecture, and makes the compile step a single parallel solution build.

  • Solution-level compile: dotnet build on the resolved consumer .sln with /m so independent projects compile concurrently and each project is built once.
  • Hooks still run: all BeforeBuild / BeforeBuildAsync callbacks run first (code generation still happens before compile), then the solution builds, then leftover projects not in the solution are built with --no-dependencies, then AfterBuild hooks run.
  • Output reuse: test, pack, and publish pass --no-build / --no-restore after a successful compile. SDK tests in the solution use dotnet test <sln> --no-build.
  • Per-project fallback: if no solution is resolved, projects still build individually, but in one invocation per project (all TFMs together) with parallel MSBuild.
  • Hooks actually resolve: BuildServices.GetHooks<T>() now returns ITaskHook implementations discovered from extension assemblies, instead of always yielding nothing.

main is unchanged. This stays on cursor/faster-solution-builds-4458.

How it works

BeforeBuild hooks (per project, existing order)
        ↓
dotnet build Solution.sln  (parallel, all TFMs)
        ↓
leftover projects not in the sln (no-restore, no-dependencies)
        ↓
AfterBuild hooks
        ↓
Test / Pack / Publish reuse bin outputs

Extensions that generate sources in BeforeBuild still run before compile. Extensions that consume outputs in AfterBuild still run after compile. App publish should call BuildProject(..., publish: true) after Build so HasBuilt is true and publish does not rebuild references.

Test plan

  • dotnet build Build.sln -c Release succeeds
  • In a consumer repo with libs + apps that reference those libs, run --target Build and confirm a single solution compile (libs not rebuilt per app)
  • Confirm build-extensions IBuildHook / IAsyncBuildHook implementations still run (BeforeBuild before compile, AfterBuild after)
  • Run --target Test and --target Pack after Build and confirm --no-build is used
  • Publish an app after Build and confirm it does not rebuild project references
  • Repo with projects outside the .sln still builds those leftovers individually
Open in Web Open in Cursor 

Compile the resolved solution once with parallel MSBuild so shared
libraries are not rebuilt for every app and test. Keep the existing
extension model: BeforeBuild hooks still run first, AfterBuild hooks
run after outputs exist, and projects outside the solution are built
individually without project-reference rebuilds.

Reuse those outputs for test, pack, and publish via --no-build, and
resolve ITaskHook implementations from DI so extension hooks fire.

Co-authored-by: Matthew Abbott <matt@ingeniumsoftware.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants