scudo's junkie site

Ryujinx can't (couldn't?) be compiled

Jul 29th, 2025 - scudo

After Nintendo successfully managed to close down the Ryujinx project, out of curiosity I tried to compile its source code, as the repo had been backed up and reuploaded both on GitHub and the Internet Archive.
There still were (and are) builds for Windows and Linux, and my notes from back then say the Flatpak version was still available on Flathub.

Also, back then I was experimenting with C#/.NET and Ryujinx is written in C#, so I figured I could give it a try.

What I found is that the project did not build, and for quite complicated reasons.

Analyzing the build logs, I found there were a lot of errors saying things like:

error CS0535: 'UnregistrationNotifier' does not implement interface method 'IServiceObject.GetCommandHandlers()'

Generally speaking, all of these errors referred to classes and project related to managing HorizonOS system calls.

I took a look into it; I loaded the repo into VSCodium and I let it crunch through all the files until it started giving out errors; I then grabbed a random class that errored out, that referenced an interface.

I was then welcomed with the sight of a completely empty interface:

interface IReceiverService : IServiceObject
    {
    }

Great. An empty interface that extends another interface. What an amazing start.

But what does IServiceObjectcontain? Not much, actually:

interface IServiceObject
    {
        IReadOnlyDictionary<int, CommandHandler> GetCommandHandlers();
    }

Great. Another (almost) empty interface. But see that GetCommandHandlers()? That is the method that gave all those build errors before!

So I searched all references to that method; it was called only once in the whole project, inside ServiceDispatchTables, a class that should deal with command handlers relative to HorizonOS syscalls:

public static ServiceDispatchTableBase Create(IServiceObject instance)
    {
        if (instance is DomainServiceObject)
        {
            return new DomainServiceObjectDispatchTable();
        }
        return new ServiceDispatchTable(instance.GetType().Name, instance.GetCommandHandlers());
    }

Wow, we even land on a constructor! And we have our GetCommandHandlers call, invoked on the instance object, which is... (drum roll)... an instance of IServiceObject! Yay! We closed the circle!

Or did we?

Let's concentrate on that call to GetCommandHandlers. Since that call is invoked on a IServiceObject object, we need to look into IServiceObject to see if there are any methods called GetCommandHandlers.

There is indeed a method with that name, which is the only thing inside of that interface. What does that method do?

GetCommandHandlers returns a IReadOnlyDictionary collection; that is, a key-value pair where the key is an integer and the value is a CommandHandler object, which is what we want to have. The problem is that this definition of GetCommandHandlers is defined inside of an interface, so it is the job of any class that implements that interface to also implement its methods; this means all the classes that implement all the HorizonOS syscalls have to implement GetCommandHandlers.

The problem is that no class in the whole project ever implements GetCommandHandlers. Oopsie. No wonder it didn't compile!