构建任务之前是否有 .NET Core CLI?
Is there a .NET Core CLI pre before build task?
问题
我假设当 msbuild
即将编译源代码文件时,它会根据项目的 Include
和 Exclude
规则生成要构建的文件列表。
有没有办法在评估要编译的文件列表之前执行任务?
这是为了能够生成源代码文件并将其用于构建。
当前的研究和试验
我正在制作一个 .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>
问题
我假设当 msbuild
即将编译源代码文件时,它会根据项目的 Include
和 Exclude
规则生成要构建的文件列表。
有没有办法在评估要编译的文件列表之前执行任务?
这是为了能够生成源代码文件并将其用于构建。
当前的研究和试验
我正在制作一个 .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>