NET 5 核心项目上的 MSBuild 生成不同的 bin/x64 和 bin/Debug 文件夹结构
MSBuild on NET 5 Core projects produces different bin/x64 and bin/Debug folder structures
我很难理解 MSBuild 如何与 Windows 上的 NET Core 项目文件 (csproj) 一起工作。我有 71 个 NET Core C# 项目文件(可执行文件、库、测试项目)。它们都在 Visual Studio 下或使用在命令行上构建并发布到发布文件夹的 msbuild 批处理作业正确编译和 运行。
在本地构建会生成不同的 BIN/* 文件夹
但是当我 运行 MSBuild(使用相同的命令行参数)在 71 个项目上进行本地构建(不在本地发布)时,一些项目会产生不同的输出文件夹。
其中一些创建 bin/Debug/* 文件夹,一些创建 bin/x64/Debug/ 文件夹,一些项目同时生成这两种类型的文件夹。 “*”部分是framework/runtime,在我的系统上是net5.0-windows/win-x64。
这是我的典型 NET 5.0 项目文件的样子:
<PropertyGroup>
<Platforms>AnyCPU</Platforms>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>net5.0-windows7.0</TargetFramework>
<SelfContained>false</SelfContained>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
// The IsPublishable setting makes no difference.
// The build operation is not a publishable operation.
</PropertyGroup>
这是我的 MSBuild 命令对于所有 71 个项目的样子
MSBuild /t:Restore;Build /p:Configuration=Debug /p:Platform=x64 /p:RuntimeIdentifier=win-x64 csproj-file-pathname
我做了很多实验,包括在 运行 启用 MSBuild 命令行之前完全删除 obj 和 bin 树,但没有任何效果。我看不到项目文件、项目类型(lib 或 exe 或应用程序)和 MSBuild 命令行参数之间的任何可辨别的关系,这些参数可以解释不同的本地生成输出文件夹。
如果项目文件相同且 MSBuild 参数相同,有谁知道什么会使某些项目创建不同的输出文件夹结构(和内容)?
有谁确切确切地知道上面显示的 msbuild 参数应该生成哪些 bin/* 输出文件夹?我花了几个小时来解决这个问题,但没有成功。谢谢。
MSBuild Structured Log Viewer 将成为您的朋友。每当我需要 确切地 了解 MSBuild 正在做什么时,我都会打开这个工具。
我做了几个图书馆项目来向你展示发生了什么
这是 x64 的解决方案配置
我使用您正在使用的相同属性构建解决方案。
我非常熟悉 MSBuild,而且我知道 属性 要查找最终副本的内容。所以我搜索 $property OutDir
。这意味着我正在寻找名称包含 OutDir.
的 MSBuild 属性
如您所见,我们遇到的情况与您描述的情况几乎相同。有些有 bin\x64\Debug 而有些只有 bin\Debug。它们都附加了目标框架,但也附加了运行时标识符。
如果我们想要完全按照 MSBuild 的方式查看项目。我们可以展开评估文件夹并从上下文菜单中单击“预处理”。这将是一个怪物xml。在从 .NET SDK 和您的存储库导入所有 .props 和 .targets 之后,这实际上是您的 csproj 的完全扩展荣耀。
您也可以使用 MSBuild -preprocess[:file]
选项从 cli 获取此文件。
有很多事情正在进行,但实际上我们只是在寻找指导输出的东西。我知道 OutDir 中使用了 OutputPath,所以我搜索 OutputPath 并跳转。我发现控制默认输出的特殊 .targets 文件称为 Microsoft.NET.DefaultOutputPaths.targets
。这是相关部分:
<Configuration Condition="'$(Configuration)'==''">Debug</Configuration>
<Platform Condition="'$(Platform)'==''">AnyCPU</Platform>
<PlatformName Condition="'$(PlatformName)' == ''">$(Platform)</PlatformName>
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">bin\</BaseOutputPath>
<BaseOutputPath Condition="!HasTrailingSlash('$(BaseOutputPath)')">$(BaseOutputPath)\</BaseOutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' == 'AnyCPU'">$(BaseOutputPath)$(Configuration)\</OutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' != 'AnyCPU'">$(BaseOutputPath)$(PlatformName)$(Configuration)\</OutputPath>
<OutputPath Condition="!HasTrailingSlash('$(OutputPath)')">$(OutputPath)\</OutputPath>
你的第一部分终于可以回答了。对于在 AnyCPU 解决方案下构建的项目(即使您指定 x64),您不会在输出中获得 $(Platform)
。你可以在我的例子中看到:只有 net6lib
在 OutDir
.
中有 x64
那么运行时标识符呢,我在这个 .targets 文件中没有看到它。它实际上稍后在另一个文件中进行了扩展:Microsoft.NET.RuntimeIdentifierInference.targets
.
相关部分加评论
<!--
Append $(RuntimeIdentifier) directory to output and intermediate paths to prevent bin clashes between
targets.
But do not append the implicit default runtime identifier for .NET Framework apps as that would
append a RID the user never mentioned in the path and do so even in the AnyCPU case.
-->
<PropertyGroup Condition="'$(AppendRuntimeIdentifierToOutputPath)' == 'true' and '$(RuntimeIdentifier)' != '' and '$(_UsingDefaultRuntimeIdentifier)' != 'true'">
<IntermediateOutputPath>$(IntermediateOutputPath)$(RuntimeIdentifier)\</IntermediateOutputPath>
<OutputPath>$(OutputPath)$(RuntimeIdentifier)\</OutputPath>
</PropertyGroup>
这是输出部分的最后一部分。 $(TargetFramework)
也被插入到我提到的前一个目标和这个目标之间,但你已经知道了。
这里一点也不疯狂。 MSBuild 完全按照指令执行。
希望这对一些人有所帮助!
我很难理解 MSBuild 如何与 Windows 上的 NET Core 项目文件 (csproj) 一起工作。我有 71 个 NET Core C# 项目文件(可执行文件、库、测试项目)。它们都在 Visual Studio 下或使用在命令行上构建并发布到发布文件夹的 msbuild 批处理作业正确编译和 运行。
在本地构建会生成不同的 BIN/* 文件夹
但是当我 运行 MSBuild(使用相同的命令行参数)在 71 个项目上进行本地构建(不在本地发布)时,一些项目会产生不同的输出文件夹。
其中一些创建 bin/Debug/* 文件夹,一些创建 bin/x64/Debug/ 文件夹,一些项目同时生成这两种类型的文件夹。 “*”部分是framework/runtime,在我的系统上是net5.0-windows/win-x64。
这是我的典型 NET 5.0 项目文件的样子:
<PropertyGroup>
<Platforms>AnyCPU</Platforms>
<PlatformTarget>AnyCPU</PlatformTarget>
<TargetFramework>net5.0-windows7.0</TargetFramework>
<SelfContained>false</SelfContained>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
// The IsPublishable setting makes no difference.
// The build operation is not a publishable operation.
</PropertyGroup>
这是我的 MSBuild 命令对于所有 71 个项目的样子
MSBuild /t:Restore;Build /p:Configuration=Debug /p:Platform=x64 /p:RuntimeIdentifier=win-x64 csproj-file-pathname
我做了很多实验,包括在 运行 启用 MSBuild 命令行之前完全删除 obj 和 bin 树,但没有任何效果。我看不到项目文件、项目类型(lib 或 exe 或应用程序)和 MSBuild 命令行参数之间的任何可辨别的关系,这些参数可以解释不同的本地生成输出文件夹。
如果项目文件相同且 MSBuild 参数相同,有谁知道什么会使某些项目创建不同的输出文件夹结构(和内容)?
有谁确切确切地知道上面显示的 msbuild 参数应该生成哪些 bin/* 输出文件夹?我花了几个小时来解决这个问题,但没有成功。谢谢。
MSBuild Structured Log Viewer 将成为您的朋友。每当我需要 确切地 了解 MSBuild 正在做什么时,我都会打开这个工具。
我做了几个图书馆项目来向你展示发生了什么
这是 x64 的解决方案配置
我使用您正在使用的相同属性构建解决方案。
我非常熟悉 MSBuild,而且我知道 属性 要查找最终副本的内容。所以我搜索 $property OutDir
。这意味着我正在寻找名称包含 OutDir.
如您所见,我们遇到的情况与您描述的情况几乎相同。有些有 bin\x64\Debug 而有些只有 bin\Debug。它们都附加了目标框架,但也附加了运行时标识符。
如果我们想要完全按照 MSBuild 的方式查看项目。我们可以展开评估文件夹并从上下文菜单中单击“预处理”。这将是一个怪物xml。在从 .NET SDK 和您的存储库导入所有 .props 和 .targets 之后,这实际上是您的 csproj 的完全扩展荣耀。
您也可以使用 MSBuild -preprocess[:file]
选项从 cli 获取此文件。
有很多事情正在进行,但实际上我们只是在寻找指导输出的东西。我知道 OutDir 中使用了 OutputPath,所以我搜索 OutputPath 并跳转。我发现控制默认输出的特殊 .targets 文件称为 Microsoft.NET.DefaultOutputPaths.targets
。这是相关部分:
<Configuration Condition="'$(Configuration)'==''">Debug</Configuration>
<Platform Condition="'$(Platform)'==''">AnyCPU</Platform>
<PlatformName Condition="'$(PlatformName)' == ''">$(Platform)</PlatformName>
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">bin\</BaseOutputPath>
<BaseOutputPath Condition="!HasTrailingSlash('$(BaseOutputPath)')">$(BaseOutputPath)\</BaseOutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' == 'AnyCPU'">$(BaseOutputPath)$(Configuration)\</OutputPath>
<OutputPath Condition="'$(OutputPath)' == '' and '$(PlatformName)' != 'AnyCPU'">$(BaseOutputPath)$(PlatformName)$(Configuration)\</OutputPath>
<OutputPath Condition="!HasTrailingSlash('$(OutputPath)')">$(OutputPath)\</OutputPath>
你的第一部分终于可以回答了。对于在 AnyCPU 解决方案下构建的项目(即使您指定 x64),您不会在输出中获得 $(Platform)
。你可以在我的例子中看到:只有 net6lib
在 OutDir
.
x64
那么运行时标识符呢,我在这个 .targets 文件中没有看到它。它实际上稍后在另一个文件中进行了扩展:Microsoft.NET.RuntimeIdentifierInference.targets
.
相关部分加评论
<!--
Append $(RuntimeIdentifier) directory to output and intermediate paths to prevent bin clashes between
targets.
But do not append the implicit default runtime identifier for .NET Framework apps as that would
append a RID the user never mentioned in the path and do so even in the AnyCPU case.
-->
<PropertyGroup Condition="'$(AppendRuntimeIdentifierToOutputPath)' == 'true' and '$(RuntimeIdentifier)' != '' and '$(_UsingDefaultRuntimeIdentifier)' != 'true'">
<IntermediateOutputPath>$(IntermediateOutputPath)$(RuntimeIdentifier)\</IntermediateOutputPath>
<OutputPath>$(OutputPath)$(RuntimeIdentifier)\</OutputPath>
</PropertyGroup>
这是输出部分的最后一部分。 $(TargetFramework)
也被插入到我提到的前一个目标和这个目标之间,但你已经知道了。
这里一点也不疯狂。 MSBuild 完全按照指令执行。
希望这对一些人有所帮助!