How to force a Roslyn SourceGenerator to run?

I’m following the manual on how to get roslyn source generators to work, but i’d like to trigger the source generator to run based on a user action. How do i go about this? I’ve tried CompilationPipeline.RequestScriptCompilation to make a general recompile happen, but that doesnt trigger the source gen.

Eventually i want the source generator to run when a user changes an asset.

1 Like

I figured out a way, by calling AssetDatabase.ImportAsset on the current script file path. Works, but a bit icky.

1 Like

Hi :slight_smile:
So theres a couple of things in play with Compilation and Source Generators:

Unity tracks how much we need to compile. This is based on files changed, so we only invoke Roslyn on things we know needs to get recompiled. When you CompilationPipeline.RequestScriptCompilation that could result in nothing or not all getting recompiled, as input’s to the compilation has not changed. (File hashes, arguments to Roslyn, other interesting things)

Roslyn is run as shared, this allowed Roslyn to cache so next compilation will be faster, even when that compilation has changed as fx SyntaxTree’s could be the same.

Since Roslyn caches data, you should not Read files from it directly. Since the compilation might invoke Roslyn again, Roslyn could end up in reusing a Cached result as the input to that compilation for the source generator hasnt changed.

Theres a thing called additionalFiles

That fixes the Roslyn Cache, so what your SourceGenerator depends on needs to come from that.
in 2022.2 we added support for AdditionalFiles (but not our yet).

Since Unity does things in steps:

  • Compile
  • Domain Reload
  • Import Assets

The Compilation Specific files has to be with knows extensions, additional files is postfixed with .additionalfile so we know to pick it up.

You can use additionalfile today using csc.rsp file.

1 Like

Small update, the Additional files feature is going to be backported to 2021.2

2 Likes

Awesome, thanks for the in depth response!

1 Like

Hi @HaraldNielsen ,

Has the Additional Files feature been backported to 2021 LTS? If not, would it be possible to get it done soon?
We could really benefit from it in our project. Thanks!

@cpatrascu I just checked the code there, it should be part of 2021 LTS. Should be in since 2021.3.3f1

1 Like

@HaraldNielsen It’s more complex compared to what you wrote above if this document is to be trusted. And given that the documentation on Source Generators is lacking any information and there is some here, I am kind of inclined to think this is probably how it works.

Let me phrase this as nicely as I can: It also matches the level of understanding of the tech/use cases and the unwieldiness one has come to expect from Unity in terms of supporting regular dotnet stuff. Quelle surprise!

This is IMHO not the way to solve this. It excludes pretty much every source generator that uses additional files and is written for regular projects. One would normally filter by file extensions of additional files etc. and that is out of the window with having to use the .additionalfile extension. Not having “.” in the file names excludes hierarchical and namespace-relevant stuff in generation - which again, is a common use case with those. Which people would know, if they had worked on source generators outside of the context of Unity. You also lose any editor support because guess what: they usually recognize which specific language editor to pick based on file extensions - but those all need to be the same.

Having to specify all the files in the csc.rsp is unwieldy as f*** so please don’t pretend like it’s a viable workaround. It’s probably what one should go for, given the situation, but it’s not how this should have been implemented.

Multiple ways to improve this, IMHO. Best one, given the limitations of the current project system: Add a project setting for specifying globs to match additional files. This could be just a text field. You can even have the whole thing where you can choose which generator gets which files, if you really want this (although the doc ALREADY specifies it doesn’t have an impact). But it shouldn’t be needed, because that’s also not how it works in dotnet land. Every generator gets everything there and it’s fine.

MyAwesomeGenerator:**/*.lang;OtherGenerator:Assets/Sounds/**/*.wav

Either way: I can’t wait for 2025 or whenever the .NET project system work lands in Unity and these things just work out of the box.

1 Like

Here’s another workaround if someone else runs into this…

public class AdditionalFilesPatcher : AssetPostprocessor
{
    public static string OnGeneratedCSProject(string path, string content)
    {
        if (!path.EndsWith("Assembly-CSharp.csproj")) return content;
       
        var myFiles = AssetDatabase.GetAllAssetPaths().Where(file => file.EndsWith(".some-extension"));
       
        var xDoc = XDocument.Parse(content);
        var nsMsbuild = (XNamespace)"http://schemas.microsoft.com/developer/msbuild/2003";
        var project = xDoc.Element(nsMsbuild + "Project");

        if (project == null) return content;
       
        var itemGroup = new XElement(nsMsbuild + "ItemGroup");
        project.Add(itemGroup);
       
        foreach (var myFile in myFiles)
        {
            var include = new XAttribute("Include", myFile);
            var item = new XElement(nsMsbuild + "AdditionalFiles", include);
           
            itemGroup.Add(item);
        }
       
        content = xDoc.ToString();
       
        return content;
    }
}

Further addition: This is not enough because the editor doesn’t build using the project file, it seems…

2021.3.13f1 also doesn’t seem to do anything given my scenario, if I want to go with the route described in the docs.

No matter if I put in the Assembly-Name (without extension) or the actual source generator class name. The additional files passed to my generator stay empty. Not that I should have to guess what is meant by [Analyzer Name]. But of course - it is not specified in the docs. Because that would actually make sense - and we can’t have that now, can we?

Honestly: This is dog s*** - and then you guys don’t even reply here - great customer service!

@Kaligoth Its been vacation time, so that’s the reason why ive been away.

My time working in this area we have been pushing for a more standardized solutions, that takes time to do but we also want to enable you guys to use features like Source Generators, and not to wait years until we are back at where we should be. Myself as a C#/.NET developer would expect standardized solutions, so understand your frustration.

The current solution is a solution that will be easy to transition to the csproj SDK with globbing of what Analyzers that the csproj is including. Adding that information in Project Settings will not, and will also by result not trigger our recompilation if those files are change/removed/added because of how the compilation pipeline are driven, and would delay work like the Dotnet modernization initiative we are working on, fx. move to csproj/msbuild compilation and move from Mono to CoreCLR.

We cant parse all additional files to every compilation(.dll), as that would mean that all internal caches in Roslyn would be invalidated if just one of them has changed.

The suggestion to use csc.rsp is a workaround, workarounds are not meant to be great but to unblock. csc.rsp will fx. not recompile if the additional file itself changes. That would enable you to add additional files that dont use the .add file. In Csproj’s you also need to specify what AdditionalFiles to add.

Im surprised you are saying 2021.3.13f1 do not work. Ill get someone to validate that, I only checked the code and release tags if it was included or not.

To confirm, yes Unity today do not use the generated csproj’s to compile with, its driven by the ADB, a custom pipeline to calculate the graph and in the end invoke Roslyn command line. Csproj’s are only there for the IDE experience, and that’s what we want to get away from, where you can maintain your own csproj’s, so you are in control of fx. AdditionalFiles, or extra build steps.

2 Likes

Did anyone have any luck trying to get this to work? I have the exact same problem, I tried guessing what [Analyzer Name] is supposed to be, but nothing what @Kaligoth tried works. I also tried to add this to the additional compiler arguments: /additionalfile:“Assets/sdaf.json” but this completely breaks unity. All materials turn pink and running a scene gives me these errors.

Could we get some more hints how to make this work or what the [AnalyzerName] is? @HaraldNielsen

Also I tried to put the arguments into csc.rsp file in the Assets folder but that didn’t do anything at all.

Also I tried to put the arguments into csc.rsp file in the Assets folder but that didn’t do anything at all.
This sadly was a bug introduced in 2022.2, I fixed it and will be in from 2022.2.9f1 that will be out shortly, sorry for that!

[Analyzer Name] is the analyzers filename without extensions.
So if you have a analyzer named MyAswesomeAnalyzer.dll, MyAswesomeAnalyzer would be what you need to add there. I renotified the docs team about improving the docs around this here

Thank you for the quick reply. I tried again to create a file in the format abc.MyAwesomeAnalyzer.additionalfile in the Assets folder, I still get no additional files in my source generator. Is there any other step that I missed?

@Ondrej98 what Unity version are you using?

I updated to 2022.2.8f1 a couple of days ago in hopes it’d work there.

@Ondrej98 can you share a simple project with the setup?
We do have automated tests for this, so it should work as described.
As im going on vacation tomorrow, my coworker will try to help out

Here is a simple project. It contains a GeneratorTest folder with the solution for the generator. The generated code is the same as in Unity - Manual: Roslyn analyzers and source generators. But it also contains a comment with the number of additional files at the top. The generated code shows the number of additional files is 0, eventhough there is a file named test.GeneratorTest.additionalfile in the Assets folder.

8846692–1205869–CodeGenTest.zip (129 KB)

Hey!
I’m using additional files in our project (Netcode for Entities) for long time. So I can assure that both GlobalConfig and additional files works.

I tried you sample project and I modified the generator to output the file list. I used 2022.2.8f1. This is the result:

foreach (var file in myFiles)
{
   context.ReportDiagnostic(Diagnostic.Create(
      new DiagnosticDescriptor("test", "rrr", file.Path, "Debug", DiagnosticSeverity.Warning, true), Location.None));
}

var sourceBuilder = new StringBuilder(
   "//" + myFiles.Length + " -- " + " \n" + 
   @"
         using System;
         namespace ExampleSourceGenerated
         {
             public static class ExampleSourceGenerated
             {
                 public static string GetTestText() 
                 {
                     return ""This is from source generator ");

sourceBuilder.Append(System.DateTime.Now.ToString());

sourceBuilder.Append(
            @""";
      }
    }
}");

This is the output in the Editor.Log

warning test: /Users/cmarastoni/Downloads/CodeGenTest/Library/Bee/artifacts/200b0aEDbg.dag/Assembly-CSharp.AdditionalFile.txt
warning test: /Users/cmarastoni/Downloads/CodeGenTest/Assets/test.GeneratorTest.additionalfile

I tried by both moving the dll in the Plugin and Assets folder. In both cases I got the same list