Friday 8 July 2016

Realtime Editing of C++ via Runtime Compiling and HotLoading


Once upon a time, I was introduced to a scripting language called Lua, which promised to improve my productivity by reducing my edit-iteration times in return for a small share of my cpu time.
While trying not to sound like a fanatic, this did sound appealing, and in time I discovered that the promise was true - I could indeed expose my C/C++ code to the scripting environment, move some part of my code operations into the script world, and take advantage of the fact that we can edit scripts, save them, and reload them, without ever needing to close and restart our game application.
 Given my background as an Assembly language programmer, I had always known that it was possible to compile new code, import it into a living application, and execute it - essentially, the same promises can be made for C/C++ or any other compiled languages, there is basically always a way to introduce hot code into any environment, within user permissions - while this sounds 'hacky', and it is, dynamically-loaded libraries are certainly not new, and represent perhaps the most legitimate way to achieve the 'impossible dream' for C/C++ programmers: hit save, and see the changes appear in the still-running host application.

Sounds like fantasy? Not at all - runtime compilation of code is the happening thing as far as I am concerned - basically there are three required pieces to this puzzle.
1 - our application needs to be able to monitor a set of (sourcecode) files for changes
2 - when changed files are detected, our application needs to be able to trigger a recompile/relink of any code modules which depend on the affected files
3 - our application should be able to detect when compilation completes, whether it was successful, and if so, be able to dynamically reload the newly-compiled code module.

There's nothing in there which is particularly difficult,  however the Devil is in the Details.
I've got all the pieces working, and should soon have them integrated - and I have several contributing authors to individually thank for that, in addition to my own work, thanks guys, your names have been added to the credits. I am humbled by those who choose to do the impossible things, as much now as I was back when the hardware limits of the commodore 64 were overcome via timing glitches by a rank amateur. Game the system!

1 comment:

  1. I hate to sound like a pessimist but I think I'm missing the point here. Don't get me wrong, I understand that you're wanting to configure a method to update dynamically shared objects. I just think a better method would be to write a configuration utility that uses IPC to issue load/unload commands to the host application. Once you tested and got the object working, you could then finalize/commit the DSO to a startup script for the host application in case it's ever restarted. This methodology is very common on Linux (even the kernel uses this scheme through LKM's).

    Second thing I question is the actual usefulness of this for your intended purpose. The reason for things like LUA (in my case Guile/Scheme) is to allow you to test and develop new features on the fly in a sandbox so you don't bring the host application to its knees. This sandbox won't exist if you're just loading/unloading DSO's and I think you will find you're going to extend your debugging time if you are constantly having to restart a host application, especially if it has a lot of resources to load on initialization.

    On a more positive note, love the blog man. It's on my regular reading list. :D

    Best Regards,
    Bryant

    ReplyDelete