经过几天的调试和调查,我确信问题是由在构建解决方案 (.sln) 文件时使用 MSBuild 多核操作 (-m:) 引起的。
如果我删除 -m MSBuild 命令行参数,所有奇怪的“文件正在被另一个进程使用”错误立即消失。如果我启用 -m:2 参数(或更高,或无界 -m),错误会立即返回。
我失败的 .sln 文件通常包含三个 .csproj 项目 - 一个库 DLL 项目、一个 LibraryXxxTests 项目和一个到库的瘦控制台程序接口。测试和控制台项目通常使用对库项目的项目引用。
也许(但我无法想象为什么)指向库项目的项目引用为 MSBuild 并行性错误打开了大门。 (但是 MSBuild -m 应该足够聪明,可以在控制台和引用库 DLL 的测试项目之前首先查看项目引用并构建库项目,是吗?)
另一种有时会失败的项目只有两个项目(lib 和测试项目)。
我的解决方案文件和项目文件没有做任何特殊或棘手的事情 - 据我所知,它们是具有 20 - 50 个 C# 文件的典型 C# 项目。当某些进程尝试写入该 .DLL 文件但由于锁定而无法执行时,构建生成的主 DLL 文件 (Library.DLL) 上会出现错误。我不知道为什么。
但我确实知道,如果删除 MSBuild -m 命令行参数,错误就会消失。回到我的解决方案级别的串行构建......
更新:我想相信 MSBuild 可以找出解决方案文件中项目之间的构建顺序,因此我在网上进行了更多搜索。我在中找到了此信息有关如何计算构建的 MSBuild 文档 https://learn.microsoft.com/en-us/visualstudio/msbuild/build-process-overview?view=vs-2022.
图表选项
如果指定图形构建开关(-graphBuild 或 -graph),
ProjectReference 成为 MSBuild 使用的一流概念。
MSBuild 将解析所有项目并构建构建顺序
graph,项目的实际依赖图,然后遍历
以确定构建顺序。与各个项目的目标一样,
MSBuild 确保引用的项目是在项目之后构建的
他们依赖。
将 -graph 选项与 -m 选项一起使用似乎适用于解决方案级构建(将 .sln 文件传递到 MSBuild)。 graph 选项告诉它计算每个解决方案文件中项目之间的构建顺序图。 -m -graph 组合似乎让我可以使用多个核心在更短的时间内进行构建,而 MSBuild 不会在解决方案中的项目之间出现访问错误。
请记住,此方法要求您在项目 XML 文件中使用 ProjectReferences。如果您使用对存储在其他位置的project.DLL 的直接程序集引用,则-graph 选项无法计算解决方案中正确的构建顺序。
更新2:
上面有关使用 -graph 的信息似乎有帮助,但并没有解决所有问题。我很幸运地找到了以下内容GitHub 上的信息 https://github.com/dotnet/sdk/issues/9964:
我很想将其称为 #9585 的重复项,它本身并不是
第一次发现这个问题,但找不到原文。
每当您显式传递 --framework (CLI) 或
/p:TargetFramework=(直接 MSBuild)来构建解决方案。这
问题是全局属性(例如 TF 设置)
大多数情况下都会遗传,但不是全部。这里是 ClassLibrary1 项目
使用显式 TF 构建一次(从解决方案构建继承)
一次没有 TF(因为它只有一个,来自的 ProjectReference
WebApplication1 不会向下传递其 TF)。
解决这个问题的最佳方法是仅将 --framework 传递给构建
个别项目,而不是解决方案。项目到项目的参考是
小心不要陷入这种情况。
到目前为止,在构建 .SLN 文件时从 msbuild 命令行中删除 /p:TargetFramework=win-x64 似乎对我有用。