// HyperRogue: alternative build system // This reads the file 'hyper.cpp' and compiles the cpp files it includes into separate object files, and then links them. // Tested in Linux, should work in other systems with some changes. // Options: // -O2 -- optimize // -O3 -- optimize // -D... -- change compilation flags // [file.cpp] -- add a module to the build (e.g. ./mymake rogueviz) #include #include #include #include #include #include #include #include using namespace std; string opts; string default_standard = " -std=c++11"; string standard = default_standard; string preprocessor; string compiler; string linker; string libs; int batch_size = 1; void set_linux() { preprocessor = "g++ -E"; compiler = "g++ -Wall -Wextra -Wno-maybe-uninitialized -Wno-unused-parameter -Wno-implicit-fallthrough -rdynamic -fdiagnostics-color=always -c"; linker = "g++ -rdynamic -o hyper"; opts = "-DFHS -DLINUX -I/usr/include/SDL"; libs = " savepng.o -lSDL -lSDL_ttf -lSDL_mixer -lSDL_gfx -lGLEW -lGL -lpng -rdynamic -lpthread -lz"; } void set_mac() { preprocessor = "g++ -E"; compiler = "g++ -march=native -W -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-implicit-fallthrough -c"; linker = "g++ -o hyper"; opts = "-DMAC -I/usr/local/include"; libs = " savepng.o -L/usr/local/lib -framework AppKit -framework OpenGL -lSDL -lSDLMain -lSDL_gfx -lSDL_mixer -lSDL_ttf -lpng -lpthread -lz"; } void set_win() { preprocessor = "g++ -E"; compiler = "runbat bwin-g.bat -c"; linker = "runbat bwin-linker.bat"; opts = "-DFHS -DLINUX -I/usr/include/SDL"; libs = ""; standard = ""; } vector modules; time_t get_file_time(const string s) { struct stat attr; if(stat(s.c_str(), &attr)) return 0; return attr.st_mtime; } int optimized = 0; string obj_dir = "mymake_files"; string setdir = "../"; int system(string cmdline) { return system(cmdline.c_str()); } bool file_exists(string fname) { return access(fname.c_str(), F_OK) != -1; } int main(int argc, char **argv) { #if defined(MAC) set_mac(); #elif defined(WINDOWS) set_win(); #else set_linux(); #endif for(string fname: {"Makefile.loc", "Makefile.simple", "Makefile"}) if(file_exists(fname)) { system("make -f " + fname + " language-data.cpp autohdr.h savepng.o"); break; } for(int i=1; i= 5 && s.substr(s.size() - 4) == ".cpp") s = s.substr(0, s.size() - 4); modules.push_back(s); } } if(!optimized) compiler += " -g3"; preprocessor += " " + standard; compiler += " " + standard; ifstream fs("hyper.cpp"); system("mkdir -p " + obj_dir); ofstream fsm(obj_dir + "/hyper.cpp"); fsm << "#if REM\n#define INCLUDE(x)\n#endif\n"; string s; while(getline(fs, s)) { if(s.substr(0, 8) == "#include") { string t; bool in = false; bool ext = false; string iext = ""; for(char c: s) if(c == '"') in = !in; else if(!in) ; else if(c == '.') ext = !ext; else if(!ext) t += c; else iext += c; if(iext == "h") { fsm << "#include \"" + setdir + "hyper.h\"\n"; continue; } if(iext != "cpp") printf("unknown extension: %s\n", iext.c_str()); fsm << "INCLUDE(\"" << t << "\")\n"; continue; } fsm << s << "\n"; } fsm.close(); printf("preprocessing...\n"); if(system(preprocessor + " " + opts + " "+obj_dir+"/hyper.cpp -o "+obj_dir+"/hyper.E")) { printf("preprocessing error\n"); exit(1); } if(true) { ifstream fs2(obj_dir+"/hyper.E"); while(getline(fs2, s)) { if(s.substr(0, 7) == "INCLUDE") { s = s.substr(9); s = s.substr(0,s.size() - 2); modules.push_back(s); } } } if(get_file_time(obj_dir + "/hyper.o") < get_file_time("hyper.cpp")) { printf("compiling hyper...\n"); if(system(compiler + " -DREM " + opts + " " + obj_dir + "/hyper.cpp -c -o " + obj_dir + "/hyper.o")) { printf("error\n"); exit(1); } } string allobj = " " + obj_dir + "/hyper.o"; int id = 0; vector> tasks; for(string m: modules) { string src = m + ".cpp"; string m2 = m; for(char& c: m2) if(c == '/') c = '_'; string obj = obj_dir + "/" + m2 + ".o"; time_t src_time = get_file_time(src); if(!src_time) { printf("file not found: %s\n", src.c_str()); exit(1); } time_t obj_time = get_file_time(obj); if(src_time > obj_time) { pair task(id, compiler + " " + opts + " " + src + " -o " + obj); tasks.push_back(task); } else { printf("ok: %s\n", m.c_str()); } allobj += " "; allobj += obj; id++; } chrono::milliseconds quantum(25); vector> workers(batch_size); int tasks_amt = tasks.size(); int tasks_taken = 0, tasks_done = 0; bool finished = tasks.empty(); while (!finished) for (auto & worker : workers) { check_lollygagging: if (worker.valid()) { if (worker.wait_for(quantum) != future_status::ready) continue; else { int res = worker.get(); if (res) { printf("compilation error!\n"); exit(1); } ++tasks_done; goto check_lollygagging; } } else if (tasks_taken < tasks_amt) { auto task = tasks[tasks_taken]; int mid = task.first; string cmdline = task.second; printf("compiling %s... [%d/%d]\n", modules[mid].c_str(), tasks_taken+1, tasks_amt); worker = async(launch::async, (int (*)(string))system, cmdline); ++tasks_taken; } else if (tasks_done == tasks_amt) { finished = true; break; } } printf("linking...\n"); system(linker + allobj + libs); return 0; }