Description
I have been unable to get C# code generation to work reliably in my .NET project. I can get it to build EITHER (a) when the source files exist beforehand OR (b) when the source files do NOT exist beforehand. I can't get the same settings to work in both scenarios.
Why this matters: If I'm building on my development machine, I've probably built the code before, so I need it to regenerate the source that exists. However, when building on the build machine, those files do NOT exist, so I need it to generate the code from scratch in that case.
Setup
A csproj and a single source file are all that's needed to duplicate this.
Here's a trivial program that references a sample GeneratedClass
:
class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine(GeneratedClass.MESSAGE);
}
}
Here's the simplest csproj file I could come up with.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Target Name="GenerateCode" BeforeTargets="CoreCompile">
<!-- Removing the source code beforehand makes no difference
<Exec Command="rm $(ProjectDir)Generated/*.cs" IgnoreExitCode="true" />
-->
<Exec Command="echo 'class GeneratedClass { public static int MESSAGE = 1; }' > Generated/GeneratedClass.cs" />
<!-- Toggling this setting will cause failures in some scenarios and success in others
<ItemGroup>
<Compile Include="Generated/*$(DefaultLanguageSourceExtension)" />
</ItemGroup> -->
</Target>
</Project>
Create an empty directory called "Generated".
To build, run dotnet build
from the directory where the csproj and Program.cs file are located.
I'm running .NET Core 2.0.3 on Linux. My Docker build containers use the microsoft/dotnet:2.0-sdk
image; I can replicate the issue both inside and outside of Docker.
Symptoms
Note that in the csproj file above there's a <Compile Include
setting that's commented out. Note also that running the build multiple times will generate the code. (The code can be manually deleted to replicate the situation where the code does not exist at the beginning of the build.)
Here's the matrix of where I see errors and where I don't:
+----------------------+----------------------+-----------------------------------+ | Compile Include=...? | Code Already Exists? | Result | +----------------------+----------------------+-----------------------------------+ | Present | YES | ERROR! "specified more than once" | | Present | NO | SUCCESS! | | Commented Out | YES | SUCCESS! | | Commented Out | NO | ERROR! "does not exist" | +----------------------+----------------------+-----------------------------------+
The full error text of the "specified more than once" error: /usr/share/dotnet/sdk/2.0.3/Roslyn/Microsoft.CSharp.Core.targets(84,5): error MSB3105: The item "Generated/GeneratedClass.cs" was specified more than once in the "Sources" parameter. Duplicate items are not supported by the "Sources" parameter. [/home/user/tmp/CodeGenExample.csproj]
The full error text of the "does not exist" error: Program.cs(5,34): error CS0103: The name 'GeneratedClass' does not exist in the current context [/home/user/tmp/CodeGenExample.csproj]
Plea for Help
My best guess is that my BeforeTargets="CoreCompile"
is wrong. I've tried lots of different values there (sorry don't remember which ones) and I always ran into some issue like this or another one. That's just a guess.
What am I doing wrong?