I am writing an incremental C# source generator which I would like to use in .NET (net9.0) and Unity (6.0) projects. The generator should have slightly different behaviour in each (generate Task in .NET or Awaitable in Unity). So; I would like it to read the preprocessor symbols and look for UNITY or UNITY_WEBGL etc. I have written the following to do this;
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Add the marker attribute to the compilation
context.RegisterPostInitializationOutput(ctx =>
{
...
});
// Extract defined preprocessor symbols
var compileForUnityCheck = context.CompilationProvider.Select((compilation, _) =>
{
if (compilation is CSharpCompilation cSharpCompilation)
{
var parseOptions = cSharpCompilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
if (parseOptions != null)
{
var preprocessorSymbols = parseOptions.PreprocessorSymbolNames;
return preprocessorSymbols.Any(s => s is "UNITY_WEBGL" or "UNITY");
}
}
return false;
});
var thingsToGenerate = context.SyntaxProvider
.ForAttributeWithMetadataName(
...
var combinedProvider = thingsToGenerate.Combine(compileForUnityCheck);
// Generate source code for each interface found
context.RegisterSourceOutput(combinedProvider,
static (spc, combined) => Execute(combined, spc));
}
However, a breakpoint on the return of the preprocessor symbols shows they are empty. The rest of the generator works well.
Is there a way to find these?
(FWIW: Rider, MacOS)
I am writing an incremental C# source generator which I would like to use in .NET (net9.0) and Unity (6.0) projects. The generator should have slightly different behaviour in each (generate Task in .NET or Awaitable in Unity). So; I would like it to read the preprocessor symbols and look for UNITY or UNITY_WEBGL etc. I have written the following to do this;
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Add the marker attribute to the compilation
context.RegisterPostInitializationOutput(ctx =>
{
...
});
// Extract defined preprocessor symbols
var compileForUnityCheck = context.CompilationProvider.Select((compilation, _) =>
{
if (compilation is CSharpCompilation cSharpCompilation)
{
var parseOptions = cSharpCompilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions;
if (parseOptions != null)
{
var preprocessorSymbols = parseOptions.PreprocessorSymbolNames;
return preprocessorSymbols.Any(s => s is "UNITY_WEBGL" or "UNITY");
}
}
return false;
});
var thingsToGenerate = context.SyntaxProvider
.ForAttributeWithMetadataName(
...
var combinedProvider = thingsToGenerate.Combine(compileForUnityCheck);
// Generate source code for each interface found
context.RegisterSourceOutput(combinedProvider,
static (spc, combined) => Execute(combined, spc));
}
However, a breakpoint on the return of the preprocessor symbols shows they are empty. The rest of the generator works well.
Is there a way to find these?
(FWIW: Rider, MacOS)
Share Improve this question edited Mar 20 at 10:14 DarkBee 15.5k8 gold badges72 silver badges117 bronze badges asked Mar 19 at 12:04 Stephen StarkieStephen Starkie 731 silver badge10 bronze badges 3 |1 Answer
Reset to default 0So in the hope that this might help others - it turns out the first problem was that I was unit testing my source generator and didn't add the expected preprocessor symbols (If I had read the code I copied from better I would have understood that);
var syntaxTree = CSharpSyntaxTree.ParseText(source);
I added the symbols in the unit test like this;
syntaxTree = syntaxTree.WithRootAndOptions(syntaxTree.GetRoot(), (new CSharpParseOptions(LanguageVersion.Latest)).WithPreprocessorSymbols("UNITY_WEBGL"));
Then I could at least debug the source generator properly and understand what was going on. Some wrangling later and my code to find the preprocessor symbols that works is;
var generateForUnityCheck = context.CompilationProvider.Select((compilation, _) =>
{
if (compilation is CSharpCompilation cSharpCompilation)
{
var preprocessorSymbols = cSharpCompilation.SyntaxTrees
.Select(st => st.Options)
.OfType<CSharpParseOptions>()
.SelectMany(po => po.PreprocessorSymbolNames)
.Distinct()
.ToList();
return preprocessorSymbols.Any(s => s is "UNITY_WEBGL" or "UNITY_6");
}
return false;
});
Thanks @BugFinder - I didn't find anything quite helpful in that issue or the referenced PRs - but it did lead me down paths that helped to get output to debug what was going on
Thanks @derHugo - you are right about the lack of UNITY
define (it was really just an example; mangled a bit to put in SO); for my use case (I'm not building a public library!) I only really needed UNITY_WEBGL but I have extended a bit to at least work in the editor. (still messing with the right thing to do here). As to UniTask
and Awaitable
s - I had heard of UniTask
and have seen the plethora of negativity towards Awaitable
in the forums but want to take as few dependencies as possible until I have to; Awaitable
s are working well enough for me at the moment
Awaitables
catches up .. which might be in a while or never ^^ – derHugo Commented Mar 19 at 17:23UNITY
preprocessor ... See docs.unity3d/6000.0/Documentation/Manual/… you could use e.g.UNITY_2019_4_OR_NEWER
to support any Units version after that one – derHugo Commented Mar 19 at 17:27