构建任务之前是否有 .NET Core CLI?

Is there a .NET Core CLI pre before build task?

问题

我假设当 msbuild 即将编译源代码文件时,它会根据项目的 IncludeExclude 规则生成要构建的文件列表。

有没有办法在评估要编译的文件列表之前执行任务?

这是为了能够生成源代码文件并将其用于构建。

当前的研究和试验

我正在制作一个 .NET Core CLI 工具,它必须 运行 在构建使用它的项目之前,因为它(CLI 工具)生成一个必须包含的文件在构建中。

项目是使用新的 .csproj 系统创建的,而不是旧的 project.json 系统。

连同我的 .NET Core CLI 工具项目,我创建了一个用于测试目的的库项目。

如果我在测试库的 .csproj 中添加:

<ItemGroup>
    <DotNetCliToolReference Include="MyCliTool" Version="x.x.x" />
    <!-- here x.x.x is just a placeholder -->
</ItemGroup>

<Target Name="MyCliToolTarget" AfterTargets="Restore" BeforeTargets="BeforeBuild">
    <Exec Command="dotnet my-cli-tool" />
</Target>

那么CLI工具生成的文件如果之前不存在,编译时不会考虑。这意味着当文件存在时,它没问题,但这也意味着第一次构建(在克隆、清理或其他之后)总是会失败。

我为 BeforeTargets 尝试了几个不同的目标,但我找不到让它工作的方法。我试图在 Project 节点的 InitialTargets 中设置我的目标,但它也没有用。我试图将 Target 节点的 Outputs 属性 设置为 CLI 工具生成的文件名,但同样,它失败了。

我发现唯一可行的解​​决方案是手动添加 Compile 指令,如下所示:

<ItemGroup>
    <Compile Include="MyGeneratedFile.cs" />
</ItemGroup>

这个解决方案目前没问题,但文件名可能会根据 CLI 工具选项而改变,这将导致两个地方的文件名必须在更改时更新,如下所示:

<ItemGroup>
    <Compile Include="PATH\TO\CUSTOM_FILENAME_HERE.CS" />
    <DotNetCliToolReference Include="MyCliTool" Version="x.x.x" />
</ItemGroup>

<Target Name="MyCliToolTarget" AfterTargets="Restore" BeforeTargets="BeforeBuild">
    <Exec Command="dotnet my-cli-tool --output PATH\TO\CUSTOM_FILENAME_HERE.CS" />
</Target>

(见 CUSTOM_FILENAME_HERE.CS 出现两次)

我知道我可以使用常量,如下所示:

<PropertyGroup>
    <MyFilename>PATH\TO\CUSTOM_FILENAME_HERE.CS</MyFilename>
</PropertyGroup>

<ItemGroup>
    <Compile Condition="!Exists('$(MyFilename)')" Include="$(MyFilename)" />
    <DotNetCliToolReference Include="MyCliTool" Version="x.x.x" />
</ItemGroup>

<Target Name="MyCliToolTarget" AfterTargets="Restore" BeforeTargets="BeforeBuild">
    <Exec Command="dotnet my-cli-tool --output $(MyFilename)" />
</Target>

但我对这种方法不满意,它让 lambda 用户集成起来太复杂了,假设这仍然是一个简化版本,因为 CLI 工具可以采用其他几个选项,这意味着有其他变量,bla bla bla.

我正在使用 .NET Core SDK 1.0.1。

抱歉这个冗长的问题和我对 msbuild 的笨拙。

提前感谢您的宝贵时间和帮助。




旁注: 在预构建事件中调用 dotnet my-cli-tool,如:

<PropertyGroup>
    <PreBuildEvent>dotnet my-cli-tool</PreBuildEvent>
</PropertyGroup>

根本不起作用,出现以下错误:

代码:MSB3073 描述:命令“dotnet my-cli-tool”以代码 1 退出。 项目:测试库项目,不是工具项目 文件:C:\Program Files (x86)\Microsoft Visual Studio17\Community\MSBuild.0\Bin\Microsoft.Common.CurrentVersion.targets 线路:4935

尽管如此,以下工作正常:

<PropertyGroup>
    <PreBuildEvent>echo meh</PreBuildEvent>
</PropertyGroup>

所以这不是预构建事件的错误。

反正这是另外一个故事,我暂时不太关心

.NET SDK 调用的 "default items" 是项目文件静态评估的一部分 - 在任何目标 运行 之前。因此,在需要 @(Compile) 项之前,您需要一个 运行 的目标。

诀窍是在自定义工具 运行 之后包含添加到文件系统的文件。这可以通过重新扫描所有文件并排除那些在构建之前 运行 目标中已经属于项目的文件来完成:

  <Target Name="GenerateSomeFiles" BeforeTargets="BeforeBuild">
    <Exec Command="dotnet my-tool" />
    <ItemGroup>
      <Compile Include="**/*$(DefaultLanguageSourceExtension)"
               Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(BaseIntermediateOutputPath)**;$(BaseOutputPath)**;@(Compile)" />
    </ItemGroup>
  </Target>

如果您的自定义工具只创建一个文件,您可以直接在中间输出路径中创建它并将其包含在您的编译中:

  <Target Name="GenerateSomeFiles" BeforeTargets="CoreCompile" DependsOnTargets="PrepareForBuild">
    <Exec Command="dotnet my-tool $(MSBuildProjectDirectory)$(IntermediateOutputPath)\my-output.cs" />
  </Target>

  <ItemGroup>
    <Compile Include="$(MSBuildProjectDirectory)$(IntermediateOutputPath)\my-output.cs" />
  </ItemGroup>