Add build.cxx/sh
This commit is contained in:
parent
4d10173f00
commit
c934cf8eb9
|
@ -36,3 +36,4 @@ font.h
|
|||
|
||||
*.swp
|
||||
*.kate-swp
|
||||
build.run
|
||||
|
|
|
@ -0,0 +1,327 @@
|
|||
// exec
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <dirent.h>
|
||||
|
||||
// dependency stuff
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#define READ_END 0
|
||||
#define WRITE_END 1
|
||||
|
||||
namespace SH {
|
||||
bool process_running(int pid) {
|
||||
return (kill(pid,0) == 0);
|
||||
}
|
||||
std::string exec(std::vector<std::string> cmd, const std::string& input) {
|
||||
std::string result;
|
||||
char buffer[2048];
|
||||
pid_t pid = 0;
|
||||
int pipefd[2][2];
|
||||
|
||||
if (pipe2(pipefd[0], O_CLOEXEC) == -1) {
|
||||
throw std::runtime_error("exec/pipe (1) failed");
|
||||
}
|
||||
|
||||
if (pipe2(pipefd[1], O_CLOEXEC) == -1) {
|
||||
throw std::runtime_error("exec/pipe (2) failed");
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
|
||||
const char* arr[cmd.size()+1];
|
||||
for (unsigned int i=0; i<cmd.size(); i++) {
|
||||
arr[i] = cmd[i].c_str();
|
||||
}
|
||||
arr[cmd.size()] = NULL;
|
||||
// Child
|
||||
dup2(pipefd[0][ READ_END], STDIN_FILENO);
|
||||
dup2(pipefd[1][WRITE_END], STDOUT_FILENO);
|
||||
dup2(pipefd[1][WRITE_END], STDERR_FILENO);
|
||||
// fucking awful code, I hate C
|
||||
execvp(arr[0], (char * const*) arr);
|
||||
std::cerr << "execl failed " << errno << std::endl;
|
||||
// Nothing below this line should be executed by child process. If so,
|
||||
// it means that the execl function wasn't successfull, so lets exit:
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
||||
close(pipefd[0][READ_END]);
|
||||
if (input.size() > 0) {
|
||||
if (write(pipefd[0][WRITE_END], input.c_str(), input.size()) == -1) {
|
||||
std::cout << "(exec warning, write failed)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
close(pipefd[0][WRITE_END]);
|
||||
close(pipefd[1][WRITE_END]);
|
||||
|
||||
try {
|
||||
int i;
|
||||
while ((i = read(pipefd[1][READ_END], buffer, 2048)) > 0) {
|
||||
buffer[i] = 0;
|
||||
result += buffer;
|
||||
}
|
||||
} catch(...) {
|
||||
// zombie
|
||||
throw;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void exec_i(std::string cmd) {
|
||||
int status = system(cmd.c_str());
|
||||
if (status != 0) throw std::runtime_error("exec_i/system failed");
|
||||
}
|
||||
|
||||
void mkdir(std::string str) {
|
||||
DIR* dir = ::opendir(str.c_str());
|
||||
if (!dir) {
|
||||
if (ENOENT == errno) {
|
||||
int status = ::mkdir(str.c_str(), S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP | S_IXUSR | S_IXGRP | S_IROTH);
|
||||
if (status != 0) throw std::runtime_error("mkdir/mkdir failed");
|
||||
} else {
|
||||
throw std::runtime_error("mkdir/opendir failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rm(std::string str) {
|
||||
remove(str.c_str()); // ignore errors, we don't really care if it didn't exist, or so.
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Task {
|
||||
public:
|
||||
virtual std::string getName() = 0;
|
||||
virtual std::vector<std::string> dependencies() = 0;
|
||||
virtual bool task() = 0;
|
||||
};
|
||||
|
||||
class TaskBuild : public Task {
|
||||
private:
|
||||
std::string binary;
|
||||
std::vector<std::string> sources;
|
||||
std::vector<std::string> optimization;
|
||||
std::vector<std::string> static_bin;
|
||||
public:
|
||||
TaskBuild(std::string binary, std::vector<std::string> sources, int opt, bool static_bin) : binary(binary) {
|
||||
this->sources = sources;
|
||||
switch (opt) {
|
||||
case 1:
|
||||
optimization = {"-O1"};
|
||||
break;
|
||||
case 2:
|
||||
optimization = {"-O2"};
|
||||
break;
|
||||
case 3:
|
||||
optimization = {"-O3"};
|
||||
break;
|
||||
default:
|
||||
if (opt != 0) {
|
||||
std::cout << "Invalid optimization mode; assuming 0/debug" << std::endl;
|
||||
}
|
||||
optimization = {"-O0","-g"};
|
||||
break;
|
||||
}
|
||||
this->static_bin = static_bin ? std::vector<std::string>{"-static"} : std::vector<std::string>{};
|
||||
}
|
||||
std::string getName() { return "build"; }
|
||||
std::vector<std::string> dependencies() {
|
||||
return { "fonts" };
|
||||
}
|
||||
bool task() {
|
||||
try {
|
||||
SH::mkdir("build/");
|
||||
std::vector<std::string> args = {"g++","-std=c++11","-lm","-o","build/" + binary,"-Iinclude/","-Ifont/"};
|
||||
args.insert(args.end(), sources.begin(), sources.end());
|
||||
args.insert(args.end(), optimization.begin(), optimization.end());
|
||||
args.insert(args.end(), static_bin.begin(), static_bin.end());
|
||||
SH::exec(args, "");
|
||||
} catch (std::runtime_error& err) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class TaskFonts : public Task {
|
||||
private:
|
||||
std::vector<char> chars;
|
||||
public:
|
||||
void add(char start, char end) {
|
||||
for (char i = start; i <= end; i++) {
|
||||
chars.push_back(i);
|
||||
}
|
||||
}
|
||||
TaskFonts() {
|
||||
add('0', '9');
|
||||
add('A', 'Z');
|
||||
add('a', 'z');
|
||||
}
|
||||
std::string getName() { return "fonts"; }
|
||||
std::vector<std::string> dependencies() {
|
||||
return {};
|
||||
}
|
||||
bool task() {
|
||||
SH::mkdir("font");
|
||||
SH::rm("font/font.h");
|
||||
std::ofstream f("font/font.h");
|
||||
for (auto c : chars) {
|
||||
std::string s(1, c);
|
||||
std::string xbm = SH::exec({"convert","-font","./letvezi.ttf","-resize","16x32!", "-pointsize","14","label:"+s, "xbm:-"}, "");
|
||||
std::string tail = SH::exec({"tail", "--lines=7"}, xbm);
|
||||
std::string sed = SH::exec({"sed","s/^static char \\(.*\\)_bits\\[\\]/bits['" + s +"']/"}, tail);
|
||||
f << sed << std::endl;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TaskManager {
|
||||
private:
|
||||
std::map<std::string, std::shared_ptr<Task>> deps;
|
||||
bool sanity_internal(const std::string& start, std::map<std::string,std::string> visited, const std::string& requester) {
|
||||
bool failed = false;
|
||||
if (deps[start] == NULL) {
|
||||
/* dependency not found */
|
||||
std::cout << "Task not found: " << start << " (required by " << requester << ")" << std::endl;
|
||||
return true;
|
||||
}
|
||||
visited[start] = requester;
|
||||
for (auto dep : deps[start]->dependencies()) {
|
||||
if (visited[dep] != "") {
|
||||
std::cout << "Loop found" << std::endl;
|
||||
std::cout << "Task " << dep << " requested by " << requester << std::endl;
|
||||
|
||||
std::string curr = dep;
|
||||
while (visited[dep] != "") {
|
||||
std::cout << "Task " << visited[dep] << " requested by " << dep << std::endl;
|
||||
}
|
||||
std::cout << "---------" << std::endl;
|
||||
failed = true;
|
||||
} else {
|
||||
failed |= sanity_internal(dep, visited, start);
|
||||
// if we are here
|
||||
visited[dep] = "";
|
||||
}
|
||||
}
|
||||
return failed;
|
||||
}
|
||||
bool sanity(const std::string& start) {
|
||||
std::map<std::string,std::string> visited;
|
||||
return !sanity_internal(start, visited, "<<user>>");
|
||||
}
|
||||
/* run_internal assumes there are no loops, and all tasks exist */
|
||||
bool run_internal(std::string task, bool ignore_deps, std::set<std::string> finished) {
|
||||
if (finished.find(task) != finished.end()) return true; // task has been completed already
|
||||
|
||||
bool deps_ok = true;
|
||||
if (!ignore_deps) {
|
||||
std::vector<std::string> deps_v = deps[task]->dependencies();
|
||||
for (auto dep : deps_v) {
|
||||
std::cout << "[NEEDED] " << task << " requires " << dep << std::endl;
|
||||
deps_ok &= run_internal(dep, false, finished);
|
||||
}
|
||||
} else {
|
||||
std::cout << "[WARNING] Assuming dependencies have been met already" << std::endl;
|
||||
}
|
||||
if (!deps_ok) {
|
||||
std::cout << "Some dependencies have failed, cannot continue" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "[RES] Task '" << task << "' | ";
|
||||
bool task_ret = deps[task]->task();
|
||||
if (task_ret) {
|
||||
std::cout << "OK :)" << std::endl;
|
||||
} else {
|
||||
std::cout << "failed :(" << std::endl;
|
||||
}
|
||||
return task_ret;
|
||||
}
|
||||
public:
|
||||
TaskManager() {
|
||||
std::cout.setf(std::ios::unitbuf);
|
||||
};
|
||||
void list_tasks() {
|
||||
std::cout << "Available tasks: " << std::endl;
|
||||
for (auto task : deps) {
|
||||
std::cout << "\t" << task.second->getName() << std::endl;
|
||||
}
|
||||
}
|
||||
void add(std::shared_ptr<Task> task) {
|
||||
if (task == NULL) {
|
||||
std::cout << "NULL Task added (BROKEN CODE)" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (deps[task->getName()] != NULL) {
|
||||
std::cout << "A dependency with the name " << task->getName() << " already exists" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
deps[task->getName()] = task;
|
||||
}
|
||||
|
||||
void run(std::string str, bool ignore_deps) {
|
||||
if (!sanity(str)) {
|
||||
return;
|
||||
}
|
||||
std::set<std::string> finished;
|
||||
run_internal(str, ignore_deps,finished);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
TaskManager man;
|
||||
|
||||
std::vector<std::string> sources = {
|
||||
"main.cxx",
|
||||
"src/Color.cxx",
|
||||
"src/DoubleBuffering.cxx",
|
||||
"src/FontManager.cxx",
|
||||
"src/Pos.cxx",
|
||||
"src/RawFB.cxx",
|
||||
"src/Toolkit.cxx"
|
||||
};
|
||||
|
||||
man.add(std::shared_ptr<Task>(new TaskFonts()));
|
||||
man.add(std::shared_ptr<Task>(new TaskBuild("fb", sources, 0, false)));
|
||||
|
||||
std::string task = "build";
|
||||
bool ignore = false;
|
||||
if (argc > 1) {
|
||||
if(strcmp(argv[1],"ignore_deps") == 0) {
|
||||
ignore = true;
|
||||
if (argc > 2) task = argv[2];
|
||||
} else {
|
||||
task = argv[1];
|
||||
}
|
||||
}
|
||||
man.run(task, ignore);
|
||||
}
|
17
build.sh
17
build.sh
|
@ -1,18 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p build/
|
||||
|
||||
mkdir -p font/
|
||||
|
||||
if [[ "$1" != "ignore_fonts" ]]; then
|
||||
|
||||
rm -f font/font.h
|
||||
for f in {a..z} {A..Z} {0..9}; do
|
||||
convert -resize 16x32\! -font ./letvezi.ttf -pointsize 14 label:"$f" "$f".xbm
|
||||
cat "$f".xbm | tail --lines=7 | sed 's/^static char \(.*\)_bits\[\]/bits['"'\1'"']/' >> font/font.h
|
||||
rm "$f".xbm
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
g++ -o build/fb -Iinclude/ -Ifont/ main.cxx src/* -O0 -g -lm -static -std=c++11
|
||||
g++ -std=c++11 -o build.run build.cxx -O1 && ./build.run $@
|
||||
|
|
Loading…
Reference in New Issue