Skip to content

Instantly share code, notes, and snippets.

@engelmarkus
Created November 27, 2017 01:09
Show Gist options
  • Save engelmarkus/11737077295196f8a86ba347f29d2190 to your computer and use it in GitHub Desktop.
Save engelmarkus/11737077295196f8a86ba347f29d2190 to your computer and use it in GitHub Desktop.
Runtime code generation and execution in C++
all: program
program: program.cpp
g++ -std=c++14 -o program program.cpp -ldl -rdynamic
run: program query.cpp
./program "`< query.cpp`"
.PHONY: clean
clean:
rm -f program
#include <chrono>
#include <iostream>
#include <memory>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
// Interface
struct Query {
virtual void run() = 0;
};
std::unique_ptr<Query> query;
int main(int argc, char* argv[], char* envp[]) {
if (argc != 2) {
exit(EXIT_FAILURE);
}
auto start = std::chrono::high_resolution_clock::now();
std::string code {argv[1]};
char filename[] = "/tmp/queryXXXXXX.so";
auto targetfile = mkostemps(filename, 3, O_RDWR | O_CREAT);
int pipe_fd[2];
pipe(pipe_fd);
auto pid = fork();
if (pid) {
close(pipe_fd[0]);
write(pipe_fd[1], code.c_str(), code.size());
close(pipe_fd[1]);
auto wstatus = 0;
do {
waitpid(pid, &wstatus, 0);
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
if (WIFSIGNALED(wstatus)) {
std::cerr << "The compiler has died.\n";
exit(EXIT_FAILURE);
}
if (WEXITSTATUS(wstatus) != 0) {
std::cerr << "The code could not be compiled.\n";
exit(EXIT_FAILURE);
}
auto handle = dlopen(filename, RTLD_NOW);
if (handle == nullptr) {
std::cerr << dlerror() << std::endl;
exit(EXIT_FAILURE);
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Duration: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " ms.\n";
query->run();
}
else {
close(pipe_fd[1]);
close(0);
dup2(pipe_fd[0], 0);
char* const nargv[] = {
"/usr/bin/g++",
"-shared", "-fPIC", "-pipe",
"-o", filename,
"-ldl", "-x", "c++", "-",
nullptr
};
execve(nargv[0], nargv, envp);
perror("execve");
exit(EXIT_FAILURE);
}
}
#include <iostream>
#include <memory>
// Interface
struct Query {
virtual void run() = 0;
};
extern std::unique_ptr<Query> query;
struct MyQuery : Query {
virtual void run() override {
std::cout << "MyQuery->run()\n";
}
};
// Automatically instantiate the query when the code is loaded.
[[gnu::constructor]]
void on_load() {
query = std::make_unique<MyQuery>();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment