使用Directory.Build.props将不同项目中的文件复制到输出目录

问题描述 投票:0回答:1

我有一个包含一些类库和一个控制台项目的解决方案。每个库在

Inputs
文件旁边都有一个
.csproj
目录,其中包含一堆文件。

我目前正在每个库项目中执行此操作,以便不同的文件最终被复制到控制台项目输出目录。它按预期工作:

  <ItemGroup>
    <None Update="Inputs\*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

现在我尝试通过执行以下操作将该功能提取到

Directory.Build.props

  <ItemGroup Condition="$(MSBuildProjectName.StartsWith('AoC')) AND !$(MSBuildProjectName.EndsWith('Test'))" >
    <None Update="$(MSBuildProjectDirectory)\Inputs\*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

最终没有文件被复制到输出目录(无论是库文件还是运行程序)。

有趣的是:

  • 如果我在
    Inputs
    中有一个
    \bin\Debug\net8.0
    目录,其中包含从项目中的原始
    ItemGroup
    创建的文件,那么如果我只保留
    ItemGroup
    文件中的“通用”
    Directory.Build.props
    ,这些文件就会被删除。
  • 没有其他文件被修改(即删除)。
  • 如果没有
    Inputs
    目录,则根本就没有创建。

此外,

Directory.Build.props
中的此目标显示了
Input
文件夹所在的预期项目路径:

  <Target Name="PrintDirs" BeforeTargets="Build" Condition="$(MSBuildProjectName.StartsWith('AoC')) AND !$(MSBuildProjectName.EndsWith('Test'))">
    <Message Importance="High" Text="||---> $(MSBuildProjectDirectory)" />
  </Target>
<..>\AoCMultiYear> dotnet build

Versión de MSBuild 17.8.3+195e7f5a3 para .NET
  Determinando los proyectos que se van a restaurar...
  Todos los proyectos están actualizados para la restauración.
  Common -> <..>\AoCMultiYear\src\Common\bin\Debug\net8.0\Common.dll
  AoC2020 -> <..>\AoCMultiYear\src\AoC2020\bin\Debug\net8.0\AoC2020.dll
  AoC2021 -> <..>\AoCMultiYear\src\AoC2021\bin\Debug\net8.0\AoC2021.dll
  ||---> <..>\AoCMultiYear\src\AoC2020
  ||---> <..>\AoCMultiYear\src\AoC2021
  AoC2020.Test -> <..>\AoCMultiYear\tests\AoC2020.Test\bin\Debug\net8.0\AoC2020.Test.dll
  AoC2022 -> <..>\AoCMultiYear\src\AoC2022\bin\Debug\net8.0\AoC2022.dll
  ||---> <..>\AoCMultiYear\src\AoC2022
  Runner -> <..>\AoCMultiYear\src\Runner\bin\Debug\net8.0\Runner.dll

我在这里遗漏了

msbuild
拼图的哪一块? :)

.net-core msbuild msbuild-task
1个回答
0
投票

旧版和SDK 项目

MSBuild 项目文件有两种类型:遗留样式和SDK 样式。旧项目用于仅适用于旧版 Windows 的 .NET Framework。 SDK 项目是针对 .NET(又名 .NET Core)开发的,可以同时支持 .NET 和 .NET Framework。

MSBuild 项目文件是 XML。如果

Project
元素具有
SDK
属性,则它是 SDK 样式项目。

例如

<Project Sdk="Microsoft.NET.Sdk">
  ...
</Project>

SDK 风格的项目将大量内容从实际项目文件中移出,并实现了一些新功能。但随之而来的是一些行为改变。

SDK - 默认包含和排除

遗留项目通常会明确指定属于项目一部分的文件。 SDK 项目有一组默认的文件包含。与问题相关,项目文件夹和子文件夹中不是

Compile
或资源项或其他一些特殊类型的文件都包含在
None
项集合中。

Directory.Build.props 和 .targets

Directory.Build.props
文件和
Directory.Build.targets
文件之间的区别在于文件导入的时间。这两个文件都可以包含任何有效的 MSBuild 内容。 (
.props
文件不限于属性,
.targets
文件不限于目标。)

Directory.Build.props
文件很早就导入了,在项目文件本身的内容之前以及在定义许多标准属性之前。

Directory.Build.targets
文件是在项目文件内容之后导入的。

根据经验,将内容放入

Directory.Build.targets
文件中。当需要更改标准属性和项目的定义行为时,请使用
Directory.Build.props
文件。例如,有一组用于更改默认项目包含的属性。设置这些属性应在
Directory.Build.props
文件中完成。项目文件本身(和
Directory.Build.targets
文件)太晚了。

分解通用功能

当从一组项目文件中分解通用功能(其中该功能当前位于项目文件中并且正常工作)时,请将通用代码移至

Directory.Build.targets
文件。本质上,这就像将代码移动到项目文件的末尾。由于
Directory.Build.props
文件的特殊早期导入,您不会破坏代码。

Inputs
文件夹的方法

假设是一个 SDK 风格的项目,创建一个包含以下内容的

Directory.Build.targets
文件:

<Project>
  <PropertyGroup>
    <InputsDirectoryName Condition="'$(InputsDirectoryName)' == ''">Inputs</InputsDirectoryName>
    <!-- EnableCopyInputs: default if not set; normalize to always be either 'true' or 'false' -->
    <EnableCopyInputs Condition="'$(EnableCopyInputs)' == ''">true</EnableCopyInputs>
    <EnableCopyInputs Condition="'$(EnableCopyInputs)' != 'true' and '$(EnableCopyInputs)' != 'false'">false</EnableCopyInputs>
  </PropertyGroup>

  <ItemGroup Condition="$(EnableCopyInputs) and Exists('$(InputsDirectoryName)')">
    <None Update="$(InputsDirectoryName)\*" >
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <Target Name="DisplayCopyInputsSettings">
    <Message Text="EnableCopyInputs: $(EnableCopyInputs)" />
    <Message Text="InputsDirectoryName: $(InputsDirectoryName)" />
    <PropertyGroup>
      <InputsDirectoryNameExists>false</InputsDirectoryNameExists>
      <InputsDirectoryNameExists Condition="Exists('$(InputsDirectoryName)')">false</InputsDirectoryNameExists>
    </PropertyGroup>
    <Message Text="Directory '$(InputsDirectoryName)' Exists: $(InputsDirectoryNameExists)" />
    <Message Text="@(None->'%(Identity), %(CopyToOutputDirectory)', '%0d%0a')" />
  </Target>
</Project>

注释

  • 每个项目都会导入
    Directory.Build.targets
    文件。通用逻辑在每个单独项目的上下文中运行。
  • 文件夹的名称位于属性 (
    InputsDirectoryName
    ) 中,并且可以被覆盖。 (这可以在每个项目的基础上完成。)
  • 可以通过属性启用或禁用复制输入功能 (
    EnableCopyInputs
    )。
    • 此属性可以在项目文件中设置为
      false
      和/或可以根据
      Directory.Build.targets
      文件中的项目名称进行设置。
  • ItemGroup
    条件要求启用复制功能并且目录存在。如果项目没有适当的现有目录,则不会进行任何更改。
  • 因为这是一个SDK风格的项目,所以
    Upgrade
    用于修改现有项目的元数据。它们是现有项目,因为 SDK 逻辑将自动包含它们。
    • Upgrade
      无法在
      Directory.Build.props
      文件中使用,因为尚未执行 SDK 的自动包含。
  • 对于测试和诊断,
    DisplayCopyInputsSettings
    目标会报告相关属性和项目。它可以用于项目,例如
    dotnet msbuild -t:DisplayCopyInputsSettings myproject.csproj
© www.soinside.com 2019 - 2024. All rights reserved.