Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
747 views
in Technique[技术] by (71.8m points)

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

The question

I assume when msbuild is about to compile source code files, it produces a list of files to build, based on Include and Exclude rules of the project.

Is there a way to execute a task before the list of files to compile is evaluated ?

This is to be able to generate a source code file and get it to be taken in the build.

Current research and trials

I'm making a .NET Core CLI tool that has to be run before the build of the project that is using it, because it (the CLI tool) generates a file that has to be included in the build.

The project is created with the new .csproj system, not the old project.json one.

Along with my .NET Core CLI tool project, I created a library project for testing purpose.

If I add this in the .csproj of the testing library:

<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>

then the file generated by the CLI tool is not taken into account in the compilation if it didn't exist before. That means when the file exists, it is OK but it also means the very first build (after a clone, cleanup or what) will always fail.

I tried several different targets for BeforeTargets but I couldn't find a way to make it work. I tried to set my target in the InitialTargets of the Project node, but it didn't work either. I tried to set the Outputs property of the Target node to the filename generated by the CLI tool, but same, it fails.

The only solution I found that worked is to manually add a Compile directive, as follow:

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

This solution is fine for the moment, but the filename may change based on the CLI tool options, and this would make two places where a filename would have to be updated on change, like the following:

<ItemGroup>
    <Compile Include="PATHTOCUSTOM_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 PATHTOCUSTOM_FILENAME_HERE.CS" />
</Target>

(see CUSTOM_FILENAME_HERE.CS appears twice)

I know I could use a constant, as follow:

<PropertyGroup>
    <MyFilename>PATHTOCUSTOM_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>

but I'm not satisfied with this approach, it makes things way too complicated for a lambda user to integrate, assuming that this is still a simplified version, because the CLI tool can take several other options, meaning having other variables, bla bla bla.

I'm using .NET Core SDK 1.0.1.

Sorry for the lengthy question and my noobness with msbuild.

Thanks in advance for your time and help.




Side note: calling dotnet my-cli-tool in pre-build event, as in:

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

doesn't work at all, I get the following error:

Code: MSB3073 Description: The command "dotnet my-cli-tool" exited with code 1. Project: the testing library project, not the tool one File: C:Program Files (x86)Microsoft Visual Studio2017CommunityMSBuild15.0BinMicrosoft.Common.CurrentVersion.targets Line: 4935

Though, the following works fine:

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

so this is not a bug with the pre build events.

Anyway this is another story which I don't care much about for the moment.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The "default items" as the .NET SDK calls it are part of the static evaluation of the project file - before any target is run. So you'll need a target that is run before the @(Compile) items are needed.

The trick is to include files added to the filesystem after the custom tool is run. This can be done by re-scanning all files and excluding those already part of the project inside a target that is run before the build:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...