Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / src/systems/compiler_system.cpp

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz
src/systems/compiler_system.cpp 2.4 KB · 108 lines raw
#include <SDL3/SDL.h>

#include "systems/compiler_system.hpp"
#include "text/text.hpp"

namespace
Nimbin
{

CompilerSystem::~CompilerSystem()
{
    if (_worker.joinable()) _worker.join();
}


void
CompilerSystem::compile(Text::Handler& out, const std::string& src)
{
    if (_running.load()) return;
    if (_worker.joinable()) _worker.join();

    last_compile_ok = false;

    out.clear();
    _count = 0;

    {
        std::lock_guard<std::mutex> lock(_mtx);
        _pending.clear();
    }

    _running.store(true);
    _worker = std::thread(&CompilerSystem::run_Compile, this, src);
}


void
CompilerSystem::run_Compile(CompilerSystem* self, std::string src)
{
    FILE* f = fopen("/tmp/game_prog.cpp", "w");
    if (!f) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
                     "CompilerSystem: could not write temp file");
        self->_running.store(false);
        return;
    }

    fputs(src.c_str(), f);
    fclose(f);

    FILE* pipe = popen("LC_ALL=C c++ /tmp/game_prog.cpp -o /tmp/game_prog 2>&1", "r");
    if (!pipe) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "CompilerSystem: popen failed");
        self->_running.store(false);
        return;
    }

    int  n = 0;
    char buf[512];
    while (fgets(buf, sizeof(buf), pipe)) {
        std::string line(buf);
        if (!line.empty() && line.back() == '\n') line.pop_back();
        if (line.empty()) continue;

        std::lock_guard<std::mutex> lock(self->_mtx);
        self->_pending.push_back(line);
        ++n;
    }
    pclose(pipe);

    if (n == 0) { // no diagnostics → success
        std::lock_guard<std::mutex> lock(self->_mtx);
        self->_pending.push_back("OK");
    }

    self->_running.store(false);
}


void
CompilerSystem::update(Text::Handler& out)
{
    constexpr size_t LINES_PER_FRAME = 2;

    DynArray<std::string> batch;
    {
        std::lock_guard<std::mutex> lock(_mtx);
        if (_pending.empty()) return;
        const size_t n = SDL_min(LINES_PER_FRAME, _pending.size());
        for (size_t i = 0; i < n; i++) batch.push_back(std::move(_pending[i]));
        _pending.erase(_pending.begin(),
                       _pending.begin() + static_cast<std::ptrdiff_t>(n));
    }

    for (const std::string& line : batch)
        push_Line(out, line);
}


void
CompilerSystem::push_Line(Text::Handler& out, const std::string& line)
{
    if (line == "OK") last_compile_ok = true;
    out.append_Line(Text::ascii_Sanitize(line));
    _count++;
}

} // namespace Nimbin