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