dotnet / dotnet/msbuild

[Bug]: Evaluation of a project with an `ProjectCachePlugin` item impacts the next build, regardless of its involvement in the build.

Open
#10,615 2 comments 0 reactions 0 assignees View on GitHub
Area: Engine Area: Project Cache bug triaged
Dominant language
C#
Stars
5.5k
Forks
1.5k
Avg merge
1d 8h
Merged PRs (30d)
141

Description

### Issue Description

Merely evaluating a Project (even in a private `ProjectCollection`) that produces an `ProjectCachePlugin` item has the nasty side-effect of impacting the next build, even though that project is never built.
And in particular, it breaks attempts to programmatically enable [the MSBuildCache plugin](https://github.com/microsoft/MSBuildCache) because it is very particular about only being initialized once, yet it is loaded twice in my testing because MSBuild allowed a single evaluation of an isolated project to also impact the build.

### Steps to Reproduce

This code breaks the next build, yet is a natural way to reuse the plugin's defaults as defined in the plugin's nuget package:

```cs
buildParameters.ProjectCacheDescriptor = CreateCacheDescriptor();

private static ProjectCacheDescriptor? CreateCacheDescriptor()
{
const string nugetPackageCache = @"C:\.tools\.nuget\packages";
const string pluginPackageId = "microsoft.msbuildcache.local";
const string pluginPackageVersion = "0.1.287-preview";
ProjectCollection projectCollection = new();
ProjectRootElement pre = ProjectRootElement.Create(projectCollection);
pre.AddImport(Path.Combine(nugetPackageCache, pluginPackageId, pluginPackageVersion, "build", $"{pluginPackageId}.props"));
pre.AddImport(Path.Combine(nugetPackageCache, pluginPackageId, pluginPackageVersion, "build", $"{pluginPackageId}.targets"));
var project = Microsoft.Build.Evaluation.Project.FromProjectRootElement(pre, new ProjectOptions { });

ProjectItem? pluginItem = project.GetItems("ProjectCachePlugin").FirstOrDefault();
if (pluginItem is null)
{
return null;
}

string pluginPath = pluginItem.GetMetadataValue("FullPath");
Dictionary settings = new(StringComparer.OrdinalIgnoreCase);
foreach(ProjectMetadata metadatum in pluginItem.DirectMetadata)
{
settings[metadatum.Name] = metadatum.EvaluatedValue;
}

settings["IdenticalDuplicateOutputPatterns"] = "**";

return ProjectCacheDescriptor.FromAssemblyPath(pluginPath, settings);
}
```

### Expected Behavior

A successful build.

### Actual Behavior

The build fails with this message:

> Another instance of MSBuildCache is already running in this build. This is typically due to a misconfiguration of the plugin settings, in particular different plugin settings across projects.

### Analysis

@dfederm says msbuild stores the plugin in a mutable static (evil) just from seeing an `ProjectCachePlugin` item in _any_ project evaluation.

### Versions & Configurations

Dev17.12 (35228.240.main)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.