MSBuild 错误 MSB4018 无法在 NET 5 构建中访问 project.assets.json

MSBuild error MSB4018 cannot access project.assets.json in NET 5 build

MSBuild 错误 MSB4018 无法在 NET 5 构建操作中访问 project.assets.json MSBuild 错误 MSB4018

我在并行组中构建 70 个 C# NET 5 项目,有时在构建中的随机项目中出现以下错误

error MSB4018: The "GenerateDepsFile" task failed unexpectedly. [c:\dev\highspeed\HsCore\hscore\HsCore.csproj] C:..\sdk.0.202\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(172,5): error MSB4018: System.IO.IOException: The process cannot access the file 'c:\dev\highspeed\HsCore\hscore\bin\Debug\net5.0-windows7.0\win-x64\HsCore.deps.json' because it is being used by another process. [c:\dev\highspeed\HsCore\hscore\HsCore.csproj]

Microsoft 文档说:当任务因未处理的异常而失败时会发出此错误。这通常是任务中存在错误的迹象。错误 MSB4018 可能是 运行 在未准备好的环境中执行任务时引起的,例如,当任务具有 x86 依赖项但 运行 在 64 位 MSBuild 环境中执行任务时。这可以表现为 System.DllNotFoundException.

就我而言,我完全处于 windows x64 环境中,构建和使用 AnyCPU 库(并发布到 win-x64,但这在构建 运行s 之前并不重要). 我使用以下参数调用 xxx.sln 文件的构建:

Exit Code 1: /t:Clean;Restore;Publish /p:Platform="Any CPU" /p:Configuration=Debug /p:TargetFramework=net5.0-windows7.0 /p:RuntimeIdentifier=win-x64 "c:\path\MySolution.sln"

代码正常生成并且 运行 没问题,除非发生这种错误。通常,当我 运行 第二次构建时,构建会成功。

我不明白为什么 MSBuild 进程(或其进程之一)无法访问 project.assets.json 文件,因为 MSBuild 是唯一访问过该文件的进程该项目中的文件。 None 我的工具曾经引用过该文件; Visual Studio 没有打开文件或项目;并行构建组中的其他项目无论如何都不会访问 projects.assets.json 文件;所以 MSBuild 是唯一一个可以处理整个项目树的工具。

我能想到的最好的办法是 Clean;Restore;Publish 链中的 Restore 目标可能正在锁定文件并且没有足够快地释放它以供 Publish(构建包括)操作。但是 MSBuild 不会足够聪明来管理这种事情吗?

有人知道会发生什么吗?还有什么其他进程可能正在查看(并锁定)该文件?谢谢

经过几天的调试和调查,我确信问题是由在构建我的解决方案 (.sln) 文件时使用 MSBuild multi-core 操作 (-m:) 引起的。

如果我删除 -m MSBuild 命令行参数,所有奇怪的“文件正在被另一个进程使用”错误都会立即消失。如果我启用 -m:2 参数(或更高,或无限制的 -m),错误会立即返回。

我失败的 .sln 文件通常有三个 .csproj 项目 - 库 DLL 项目、LibraryXxxTests 项目和库的瘦控制台程序接口。测试和控制台项目通常使用对库项目的项目引用。

也许(但我无法想象为什么)指向库项目的项目引用打开了 MSBuild 并行错误的大门。 (但是 MSBuild -m 应该足够聪明,可以看到项目引用并在引用库 DLL 的控制台和测试项目之前首先构建库项目,是吗?)

另一种有时失败的项目只有两个项目(lib和tests项目)。

我的解决方案文件和项目文件没有做任何特别或棘手的事情 - 据我所知,它们是典型的 C# 项目,包含 20 - 50 个 C# 文件。错误发生在构建生成的主 DLL 文件 (Library.DLL) 上,当某些进程试图写入该 .DLL 文件但由于锁定而无法执行时。不知道为什么。

但我知道如果删除 MSBuild -m 命令行参数,错误就会消失。回到我的解决方案级别的串行构建 ...

更新:我想相信 MSBuild 可以找出解决方案文件中项目之间的构建顺序,所以我在网上进行了更多搜索。我在 the MSBuild documentation on how it calculates builds.

中找到了此信息

Graph option

If you specify the graph build switch (-graphBuild or -graph), the ProjectReference becomes a first-class concept used by MSBuild. MSBuild will parse all the projects and construct the build order graph, an actual dependency graph of projects, which is then traversed to determine the build order. As with targets in individual projects, MSBuild ensures that referenced projects are built after the projects they depend on.

将 -graph 选项与 -m 选项一起使用似乎适用于 solution-level 构建(将 .sln 文件传递​​给 MSBuild)。 graph 选项告诉它计算每个解决方案文件中项目之间的构建顺序图。 -m -graph 组合似乎让我可以使用多个内核在更短的时间内完成构建,而 MSBuild 不会在解决方案中的项目之间出现访问错误。

请记住,此方法要求您在项目 XML 文件中使用 ProjectReferences。如果您使用对存储在其他位置的 project.DLLs 的直接程序集引用,则 -graph 选项无法在解决方案中计算正确的构建顺序。

更新 2:

上面关于使用-graph 的信息似乎有所帮助,但并没有解决所有问题。我很幸运地找到了以下 information on GitHub:

I'm tempted to call this a duplicate of #9585, which is itself not the first time the problem has been found but I can't find the original.

Problems arise whenever you explicitly pass a --framework (CLI) or /p:TargetFramework= (direct MSBuild) to the build of a solution. The issue is that global properties (such as that TF setting) are inherited in most cases, but not all. Here, the ClassLibrary1 project is built once with an explicit TF (inherited from the solution build) and once with no TF (since it only has one, the ProjectReference from WebApplication1 does not pass its TF down).

The best way out of this is to only pass --framework to builds of individual projects, not solutions. Project-to-project references are careful not to get into this situation.

到目前为止,在构建 .SLN 文件时从 msbuild 命令行中删除 /p:TargetFramework=win-x64 似乎对我有用。