As promised a couple of posts back, I will present a C++ class to compile some arbitrary code using GCC and load it into memory.

The code is pretty simple, we start off with the class header:

// CodeTools.hpp

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

typedef class CodeTools {
    static bool compileString(char*, bool (*callback)(void*));
    static bool compileFile(char*, bool (*callback)(void*));

} *pCodeTools;

And then on to the compileString method. This method actually just wraps compileFile to avoid code duplication, so it's really just taking in a string and writing it to a temporary file before calling compileFile.

Here we go:

// CodeTools.cpp

bool CodeTools::compileString(char* code, bool (*callback)(void*))
    // Generate a temporary file name
    // (There are better ways to do this!)
    char temp[256];
    sprintf(temp, "codetools_XXXXXX");
    char* tmppath = mktemp(temp);

    // Open temporary file
    FILE* fp = fopen(tmppath, "wb");

    if (!fp) {
        fprintf(stderr, "Could not open temporary path %s\n", tmppath);
        return false;

    // Write out string
    fwrite(code, strlen(code), sizeof(char), fp);

    // Call out to compileFile method
    bool ret = compileFile(tmppath, callback);

    // Remove temporary file

    return ret;

So again, just a small wrapper, which can be reimplemented to your liking.

Now for the part that does the actual work, this can be cleaned up plenty but seems pretty stable for me:

bool CodeTools::compileFile(char* path, bool (*callback)(void*))
    // Increments each time this function is called.
    // This is used for the .so path. If the .so path
    // doesn't change then our new functions won't
    // override the old ones.
    static int count = 0;

    // A buffer to hold our command line
    char buffer[256];
    memset(buffer, 0, sizeof(buffer));

    // The last path used
    char sopathLast[256];
    memset(sopathLast, 0 , sizeof(sopathLast));

    // The current path to use
    char sopath[256];
    memset(sopath, 0 , sizeof(sopath));

    sprintf(sopathLast, "./", path, count - 1);
    sprintf(sopath, "./", path, count++);

    // Please change modify these to your liking! These are what I use
    // for my livecoding playground
    sprintf(buffer, "g++ -shared -o %s -fPIC -fno-use-cxa-atexit -xc++ -include src/Global.hpp %s -Isrc -I/usr/include/freetype2", sopath, path);

    // Call it!
    int ret = system(buffer);

    if (ret != 0) {
        fprintf(stderr, "Error in compilation: g++ returned %i\n", ret);
        return false;

    // Cool, compile was successful!

    // Now, try to get a handle to the last opened .so so we can close it
    void* handle = dlopen(sopathLast, RTLD_LAZY | RTLD_NOLOAD);
    if (handle) {
        fprintf(stderr, "Found current handle %s, closing first\n", sopathLast);

    // Open the new .so, LAZY load symbols for speed
    handle = dlopen(sopath, RTLD_LAZY);

    if (!handle) {
        fprintf(stderr, "Could not load compiled file into memory: %s\n", dlerror());
        return false;

    printf("Loaded %s\n", sopath);

    // Remove temporary .so

    // Call the user supplied callback passing the .so handle to it
    // From there it can load individual functions.
    return callback(handle);

And done. This should be all the code needed to use the CodeTools sample from the C++ Eval? Hell yes. post. Have fun! I will be posting the FileTools class shortly too.

(Maybe) Related posts: