MSBuild SDK Packaging Best Practices
Building MSBuild SDKs with compiled tasks presents unique challenges, particularly around file locking during development. This guide documents Microsoft’s patterns and best practices for creating robust, maintainable MSBuild SDK packages.The File Lock Problem
When developing MSBuild SDKs that include compiled tasks, a common issue arises:- The SDK project compiles its task assemblies
- The same build process attempts to load those assemblies
- MSBuild locks the loaded assemblies in memory
- Subsequent builds fail because the compiler cannot overwrite locked files
Microsoft’s Solution Pattern
Microsoft addresses this challenge through architectural separation and careful build orchestration.1. Separation of Concerns Architecture
Microsoft separates SDK projects into distinct components:- Task Projects (
Microsoft.NET.Build.Tasks
) - Contains compiled MSBuild tasks - SDK Projects (
Microsoft.Build.NoTargets
) - Contains props/targets files and SDK structure - Test Projects - Separate unit test projects for each component
2. The NoTargets Pattern
Microsoft createdMicrosoft.Build.NoTargets
specifically for projects that don’t compile assemblies but need MSBuild integration:
3. Task Assembly Packaging Configuration
For SDKs with compiled tasks, Microsoft uses specific packaging properties:4. Standard Directory Structure
Microsoft’s SDK packages follow this consistent structure:5. Multi-Stage Build Process
Microsoft avoids file locks through a multi-stage approach:- Stage 1: Build task assemblies in an isolated project
- Stage 2: Package pre-built assemblies into the SDK
- Stage 3: Test the packaged SDK in a separate solution
6. Runtime-Aware Task Loading
In Sdk.targets files, Microsoft uses runtime detection for task loading:7. Development vs. Package Detection
Microsoft SDKs intelligently detect their execution context:8. Preventing Circular Dependencies
The fundamental principle: The SDK project must never load its own compiled tasks during its own build. Strategies to achieve this:Recommended Solution Architecture
For a robust MSBuild SDK with compiled tasks, use this three-project structure:Project 1: Task Library
CloudNimble.DotNetDocs.Sdk.Tasks.csproj
Project 2: SDK Package
CloudNimble.DotNetDocs.Sdk.csproj
Project 3: Integration Tests
CloudNimble.DotNetDocs.Sdk.Tests.csproj
Development Workflow
- Build Tasks First: Always build the tasks project independently
- Then Package: Build the SDK project to create the package
- Test Separately: Use a different solution to test the packaged SDK
- Use Local Feeds: Configure a local NuGet feed for development testing
Additional Best Practices
Disable Node Reuse During Development
Add toDirectory.Build.props
in your development folder: