Zane's Blog
C++ Eval? Hell yes.
Tagged as hack, c++, and livecoding
Recently I’ve been getting back into live coding, and as part of that I have been experimenting with a simple livecoding framework in C++.
One of my experiments involves using C++ as a scripting language, by compiling code on the fly (using g++, but any compiler should work) into a shared object, and then dlopen-ing the resultant file and hooking up the necessary functions.
By doing this I can have full access to the engine/framework and speed is never a concern. It also means I can modify it later to load any arbitrary shared object (ie. generated via C or any other language, perhaps Chicken?).
The workflow I desired to achieve was to have an OpenGL context open, blank at first. From there I could open the editor of my choice, hack on some high level C++/OpenGL, and when I saved the file, the engine would recompile the file and load it, causing its rendering function to be overridden with the new one.
I’m happy to say I’ve achieved what I was after!
I will be posting the relevant source to do this in the next post, but for now I will say that it involves a very simple class called FileTools that wraps inotify on the Linux operating system (so it will need to be ported for other OS’s, or a generic polling solution could be used very easily, by simply resorting to stat)), which allows one to watch a file with some simple code that looks like this:
int fd = FileTools::addWatch("test.cpp");
while (mainloop) {
if (FileTools::hasChanged(fd)) { // Uses select internally
// Cool!
}
}
FileTools::removeWatch(fd);
For my engine to extend this to include recompilation, I have another class called CodeTools, which wraps system and dlopen. This is also very easy to use, it looks like this:
if (FileTools::hasChanged(fd)) {
CodeTools::compileFile("test.cpp", [](void* handle) {
Renderer::renderp render = (Renderer::renderp)dlsym(handle, "render");
if (render) // Hook 'er up
::engine.renderer->userRender = render;
});
}
Here we are passing a path to a file to compile, and a function (I’m using C++0x lambdas here) that takes a valid handle from dlopen.
Using this class it is also possible to using compileString to compile a string via temp files.
Oh and a screenshot for those wanting to see it in action!
