最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Source Generator has empty list of Pre-Processor Symbol Names - Stack Overflow

programmeradmin4浏览0评论

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
  • this may help github/dotnet/roslyn/issues/15797 – BugFinder Commented Mar 19 at 13:56
  • Depending on what exactly you do would recommend going for UniTask for Unity .. at least until Awaitables catches up .. which might be in a while or never ^^ – derHugo Commented Mar 19 at 17:23
  • There is no general UNITY 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
Add a comment  | 

1 Answer 1

Reset to default 0

So 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 Awaitables - I had heard of UniTaskand have seen the plethora of negativity towards Awaitable in the forums but want to take as few dependencies as possible until I have to; Awaitables are working well enough for me at the moment

发布评论

评论列表(0)

  1. 暂无评论