Skip to content

Instantly share code, notes, and snippets.

@KirillOsenkov
Last active July 26, 2024 19:34
Show Gist options
  • Save KirillOsenkov/f20cb84d37a89b01db63f8aafe03f19b to your computer and use it in GitHub Desktop.
Save KirillOsenkov/f20cb84d37a89b01db63f8aafe03f19b to your computer and use it in GitHub Desktop.
Sample of generating a .cs file during build and adding it to the compilation
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<GeneratedText><![CDATA[
using System%3B
public class Hello$(TargetFramework)
{
public void Print()
{
Console.WriteLine("Hello $(TargetFramework)!")%3B
}
}
]]></GeneratedText>
</PropertyGroup>
<Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.cs">
<PropertyGroup>
<GeneratedFilePath>$(IntermediateOutputPath)GeneratedFile.cs</GeneratedFilePath>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(GeneratedFilePath)" />
<FileWrites Include="$(GeneratedFilePath)" />
</ItemGroup>
<WriteLinesToFile Lines="$(GeneratedText)" File="$(GeneratedFilePath)" WriteOnlyWhenDifferent="true" Overwrite="true" />
</Target>
</Project>
@jcansdale
Copy link

@rainersigwald,

possibly skipping them at the target level based on target inputs and outputs.

Would this explain why the following generates GeneratedFile.cs the first time, but never regenerates it, even after a Rebuild?

<Target ... Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.cs">

Does Rebuild force the up-to-date check to return false, but MSBuild decides the target still doesn't need to execute because GeneratedFile.cs was updated more recently than $(MSBuildAllProjects)?

@rainersigwald
Copy link

Rebuild does Clean;Build. I think in that case, because the generated file isn't added to @(FileWrites), it's not getting deleted/cleaned up on Clean, so Rebuild doesn't reset its state.

Incremental build for targets is unconfigurable: it's always on.

A log at detailed or diagnostic level should show the target being skipped as up to date.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment