Including the file unconditionally should work. For example with these lines in a default C# project template right after the Microsoft.CSharp.targets Import:
<ItemGroup>
<MyInput Include="in.txt" />
</ItemGroup>
<PropertyGroup>
<MyOutput>Generated.cs</MyOutput>
</PropertyGroup>
<Target Name="MyCodeGen" BeforeTargets="PreBuildEvent" DependsOnTargets="ResolveReferences"
Inputs="@(MyInput);$(MSBuildThisFileFullPath)"
Outputs="$(MyOutput)">
<ReadLinesFromFile File="@(MyInput)">
<Output TaskParameter="Lines" ItemName="MyInputlines"/>
</ReadLinesFromFile>
<Message Text="CODEGEN lines @(MyInputlines)" />
<WriteLinesToFile File="$(MyOutput)" Lines="@(MyInputlines)" Overwrite="True" />
</Target>
<ItemGroup>
<Compile Include="$(MyOutput)"/>
</ItemGroup>
The results of running msbuild /v:d on the commandline are (showing only output for MyCodeGen Target):
Output of first run (Generated.cs does not exist yet):
Target "MyCodeGen" in project "my.csproj" (target "PreBuildEvent" depends on it):
Building target "MyCodeGen" completely.
Output file "Generated.cs" does not exist.
Using "ReadLinesFromFile" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "ReadLinesFromFile"
Done executing task "ReadLinesFromFile".
Task "Message"
CODEGEN lines using System;
Done executing task "Message".
Using "WriteLinesToFile" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "WriteLinesToFile"
Done executing task "WriteLinesToFile".
Done building target "MyCodeGen" in project "my.csproj".
Output of second/third/... run:
Target "MyCodeGen" in project "my.csproj" (target "PreBuildEvent" depends on it):
Skipping target "MyCodeGen" because all output files are up-to-date with respect to the input files.
Input files: in.txt;my.csproj
Output files: Generated.cs
Done building target "MyCodeGen" in project "my.csproj".
Output of build after modifying in.txt:
Target "MyCodeGen" in project "my.csproj" (target "PreBuildEvent" depends on it):
Building target "MyCodeGen" completely.
Input file "in.txt" is newer than output file "Generated.cs".
Using "ReadLinesFromFile" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "ReadLinesFromFile"
Done executing task "ReadLinesFromFile".
Task "Message"
CODEGEN lines using System.Linq;
Done executing task "Message".
Using "WriteLinesToFile" task from assembly "Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "WriteLinesToFile"
Done executing task "WriteLinesToFile".
Done building target "MyCodeGen" in project "my.csproj".
Output of runs after this:
Target "MyCodeGen" in project "my.csproj" (target "PreBuildEvent" depends on it):
Skipping target "MyCodeGen" because all output files are up-to-date with respect to the input files.
Input files: in.txt;my.csproj
Output files: Generated.cs
Done building target "MyCodeGen" in project "my.csproj".
If this doesn't work for you, it could be for instance that the process you use to generate the file doesn't play well with msbuild in that it doesn't update the timestamp correctly. E.g. just copying an existing file which is older than the project file would lead to Generated.cs having a timestamp older than the $(MSBuildThisFileFullPath) input so the target would just always run.
$(IntermediateOutputDirectory)
or somewhere where the glob patterns would pick the .cs file up (and show them in VS solution explorer)? If so, there's little that can be done (there is a_GenerateCompileDependencyCache
private target that captures all Compile items in the project, this will change during first and second build) – Toon1 succeeded, 0 up-to-date
instead of0 succeeded, 1 up-to-date
. Maybe it’s a potential issue, I’m not sure. What about also reporting/asking this issue in Microsoft Developer Community? – ChavezProj and Solution > SDK-Style Proj >Loging Level = Minimal
– Thema