Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdlib.h>
- #include <string>
- #include <vector>
- #include <functional>
- #include <fstream>
- #include <map>
- #include <list>
- #include "ws/tools/app.hpp"
- #include "ws/base.hpp"
- #include "ws/exception.hpp"
- #include "ws/data/decoder.hpp"
- #include "ws/io.hpp"
- #include "ws/sys/process.hpp"
- #include "ws/sys/time.hpp"
- #include "ws/sys/console.hpp"
- #include "ws/list.hpp"
- #include "ws/path.hpp"
- char toLower(char in){
- if(in<='Z' && in>='A')
- return in-('Z'-'z');
- return in;
- }
- namespace ws {
- using namespace std;
- class pibuilder {
- public:
- struct source {
- string path;
- string actualPath;
- };
- string basePath;
- string filePath;
- string compiler = "g++ -std=gnu++11 -O3 -Wall -c -fmessage-length=0 ";
- string linker = "g++ ";
- string output = "bin/program.exe";
- string buildPath =
- #if osWindows
- "build/windows";
- #elif osLinux
- "build/linux";
- #endif
- string vipath;
- bool debug = false;
- list<string> includePaths;
- string libraryPaths;
- string libraries;
- list<source> sourceFiles;
- list<string> objStack;
- list<string> smartLibs;
- list<string> processedSmartlibs;
- list<string> runPostbuild;
- struct SBool {
- bool b = false;
- operator bool(){return b;}
- void operator=(bool _b){b=_b;}
- };
- map<string,SBool> includesParsed;
- path::time oldestObj;
- string objects;
- list<string> IgnoreList;
- public:
- pibuilder(const string& f){
- string file = f;
- std::cout << console::white;
- Exception::displayFile = false;
- for(char& c: file)
- if(c == '\\') c = '/';
- if(file.find(".pi") >= file.size())
- file = findPi(file.substr(0, file.find_last_of('/')));
- if(!file.size()) throw Exception("no project file found: \"%\"", f);
- if(file.find("/") < file.size()){
- basePath = file.substr(0, file.find_last_of("/")+1);
- filePath = file.substr(file.find_last_of('/')+1, file.size()-file.find_last_of('/')-1);
- } else {
- basePath = "";
- filePath = file;
- }
- if(basePath.size()){
- chdir(basePath.c_str());
- }
- objStack.push_back("");
- decodeFile();
- }
- string findPi(string s){
- while(path::isFolder(s)){
- for(string f: path::list(s)){
- if(f.find_last_of('.') < f.size() and f.substr(f.find_last_of('.'), f.size()-f.find_last_of('.')) == ".pi")
- return s + '/' + f;
- }
- if(s.find_last_of('/') < s.size())
- s = s.substr(0, s.find_last_of('/'));
- else break;
- }
- return "";
- }
- void decodeFile(){
- std::function<void(const string&,const string&,bool)> callback = [&](const string& cmd, const string& content, bool block){
- if(debug)
- io::writeln("%: [%][%]", block ? "block" : "var", cmd, content);
- if(cmd == "linux")
- #if osLinux
- decode::text(content, callback)
- #endif
- ;else if(cmd == "windows")
- #if osWindows
- decode::text(content, callback)
- #endif
- ;else if(cmd == "compiler")
- compiler = content + " ";
- else if(cmd == "linker")
- linker = content + " ";
- else if(cmd == "output"){
- output = content
- #if osWindows
- + ".exe"
- #endif
- ;
- uint cur = 0;
- while(true){
- cur = content.find('/', cur+1);
- if(cur >= content.size()) break;
- string dir = content.substr(0, cur);
- path::create(dir);
- }
- }
- else if(cmd == "vipath"){
- vipath = content;
- }
- else if(cmd == "buildpath" || cmd == "objs"){
- buildPath = content +
- #if osWindows
- "/windows"
- #elif osLinux
- "/linux"
- #endif
- ;
- }
- else if(cmd == "source"){
- if(block){
- decode::text(content, [&](const string& c, const string& cnt, bool block){
- if(c == "path"){
- addSourcePath(cnt);
- }
- });
- }else{
- addSourcePath(content);
- }
- }
- else if(cmd == "include"){
- if(block){
- decode::text(content, [&](const string& c, const string& cnt, bool block){
- if(c == "path"){
- if(!path::isFolder(basePath + cnt))
- throw Exception("Couldn't find include directory \"" + cnt + "\"");
- includePaths.push_back(basePath + cnt);
- }
- });
- }else{
- if(!path::isFolder(content))
- throw Exception("Couldn't find include directory \"" + content + "\"");
- includePaths.push_back(content);
- }
- }
- else if(cmd == "library"){
- if(block){
- decode::text(content, [&](const string& c, const string& cnt, bool block){
- if(c == "lib"){
- libraries = " -l\"" + cnt + "\"" + libraries;
- }else if(c == "path"){
- if(!path::isFolder(basePath + cnt))
- throw Exception("Couldn't find library directory \"" + cnt + "\"");
- libraryPaths += " -L\"" + basePath + cnt + "\"";
- }
- });
- }else{
- libraries = " -l\"" + content + "\"" + libraries;
- }
- }
- else if(cmd == "smartlib"){
- if(block){
- decode::text(content, [&](const string& c, const string& cnt, bool block){
- if(c == "path"){
- if(!path::isFolder(basePath + cnt))
- throw Exception("Couldn't find smartlib directory \"" + cnt + "\"");
- smartLibs.push_back(basePath + cnt);
- includePaths.push_back(basePath + cnt);
- }
- });
- } else {
- if(!path::isFolder(basePath + content))
- throw Exception("Couldn't find smartlib directory \"" + content + "\"");
- smartLibs.push_back(basePath + content);
- includePaths.push_back(basePath + content);
- }
- }
- else if(cmd == "debug"){
- if(content == "on")
- debug = true;
- else
- debug = false;
- }
- else if(cmd == "run" || cmd == "do"){
- if(content == "output")
- runPostbuild.push_back(output);
- else
- runPostbuild.push_back(content);
- }
- else {
- io::writeln("Unknown option: " + cmd);
- }
- };
- decode::file(basePath + filePath, callback);
- }
- void Clean(){
- path::remove(basePath + buildPath);
- io::writeln("deleted \"%\"", basePath + buildPath);
- }
- bool Compile(){
- bool newObject = !path::isFile(basePath + output);
- for(source& s: sourceFiles){
- includesParsed.clear();
- string obj;
- try {
- processSource(s.actualPath, 1, s.path);
- obj = getObjectPath(s.path);
- objects += " \"" + obj + "\"";
- if(!checkActuality(s, obj)) continue;
- } catch(Exception& e) {
- throw Exception(e, "error while parsing \"" + s.path + "\"");
- }
- io::writeln("compiling %% [% includes]", vipath.size() ? vipath + '/' : "", s.path, includesParsed.size());
- io::write(console::yellow);
- path::create(obj);
- string incl;
- for(string& i: includePaths)
- incl += " -I\"" + i + "\"";
- if(TryProgram(compiler + incl + " -o \"" + obj + "\" \"" + s.actualPath + "\""))
- throw Exception("compiler error");
- io::write(console::white);
- newObject = true;
- }
- return newObject;
- }
- void Link(){
- io::writeln("linking \"%\"", output);
- std::cout << console::yellow;
- if(TryProgram(linker + "-o" + "\"" + basePath + output + "\"" + libraryPaths + objects + libraries))
- throw Exception("failed to link");
- std::cout << console::white;
- }
- string getObjectPath(string p){
- while(p.find("../") < p.size())
- p.erase(0, 3);
- if(p.find('.') < p.size())
- p = basePath + buildPath + '/' + p.substr(0, p.find_last_of('.')) + ".o";
- else
- throw Exception("\"" + p + "\" has no file extension");
- return p;
- }
- void RunPost(){
- for(string& s: runPostbuild)
- if(s == "pause") std::cin.get();
- else if(sys::process(basePath + s))
- throw Exception("Failed to run \"" + s + "\"");
- }
- list<string> parseIncludes(const string& path, bool all = false){
- if(!path::isFile(path)) return {};
- list<string> files;
- ifstream f(path);
- string block;
- while(f.good()){
- string buffer;
- std::getline(f, buffer);
- while(buffer.find('\r') < buffer.size())
- buffer.erase(buffer.find('\r'),1);
- block += buffer + '\n';
- if(block.find("/*") < block.size()){
- uint start = block.find("/*");
- uint end = block.find("*/", start)+2;
- if(end < block.size()){
- block.erase(start, end-start);
- } else
- continue;
- }
- if(block.find("//") < block.size()){
- uint start = block.find("//");
- uint end = block.find("\n", start)+1;
- if(end < block.size()){
- block.erase(start, end-start);
- } else
- continue;
- }
- if(block.find("#include") < block.size()){
- for(ulong i=block.find("#include")+8; i<block.size(); i++){
- uint start = 0;
- uint end = 0;
- if(block[i] == ' ' || block[i] == '\t') continue;
- if(block[i] != '\"' && (!all || block[i] != '<')) break;
- start = i;
- end = block.find_first_of('\"', start+1);
- if(!start || end >= block.size()) break;
- string result = block.substr(start+1, end-start-1);
- #if osWindows
- for(size_t i=0; i<result.size(); i++)
- result[i] = toLower(result[i]);
- #endif
- if(!includesParsed[result]){
- includesParsed[result] = true;
- }
- files.push_back(result);
- break;
- }
- }
- block.erase();
- }
- return files;
- }
- void processSource(const string& s, long level = 0, string nicePath = ""){
- if(find(processedSmartlibs, s) >= 0) return;
- processedSmartlibs.push_back(s);
- if(s.find(".h") < s.size() && findFile(s.substr(0, s.find_last_of('.'))+".cpp").size()){
- string srcPath = findFile(s.substr(0, s.find_last_of('.'))+".cpp");
- source src = { srcPath, srcPath };
- if(nicePath.size())
- src.path = nicePath.substr(0, nicePath.find_last_of('.')) + string(".cpp");
- bool already = false;
- for(source f: sourceFiles)
- if(f.actualPath == srcPath)
- already = true;
- if(!already)
- sourceFiles.push_back(src);
- }
- for(string i: parseIncludes(s)){
- bool found = false;
- for(string& l: includePaths){
- string src;
- if(path::isFile(l + '/' + i))
- src = l + '/' + i;
- else if(path::isFile(s.substr(0, s.find_last_of('/')+1) + i))
- src = s.substr(0, s.find_last_of('/')+1) + i;
- else
- continue;
- found = true;
- try {
- processSource(src, level + 1, i);
- } catch(Exception& e) {
- throw Exception(e, "error while parsing \"" + i + "\"");
- }
- break;
- }
- if(!found)
- throw Exception("failed to find \"" + i + "\"");
- }
- }
- bool checkActuality(const source& s, const string& obj, long level = 0){
- if(!path::isFile(s.actualPath)) throw Exception("could not find \"" + s.path + "\"");
- if(!path::isFile(obj)) return true;
- if(path::time(s.actualPath) >= path::time(obj)) return true;
- if(debug){
- for(long i=0; i<=level; i++)
- io::write(" ");
- io::writeln(s.path);
- }
- for(string file: parseIncludes(s.actualPath)){
- try {
- if(findFile(file).size()){
- if(checkActuality({file, findFile(file)}, obj, level + 1))
- return true;
- } else {
- if(findFile(s.actualPath.substr(0, s.actualPath.find_last_of('/')+1) + file).size()){
- if(checkActuality({file, findFile(s.actualPath.substr(0, s.actualPath.find_last_of('/')+1) + file)}, obj, level + 1))
- return true;
- } else {
- throw Exception("could not find \"" + file + "\"");
- }
- }
- } catch(Exception& e) {
- throw Exception(e, "error while parsing \"" + s.path + "\"");
- }
- }
- return false;
- }
- void addSourcePath(string sourcePath){
- if(!path::isFolder(sourcePath)){
- if(!path::isFolder(basePath + sourcePath))
- throw Exception("folder \"" + sourcePath + "\" not found");
- sourcePath = basePath + sourcePath;
- }
- for(string& entry: path::list(sourcePath)){
- if(path::isFolder(sourcePath + '/' + entry))
- addSourcePath(sourcePath + '/' + entry);
- else {
- unsigned long extPos = entry.find_last_of('.');
- if(extPos >= entry.size()) continue;
- string ext = entry.substr(extPos, entry.size() - extPos);
- if(ext == ".cpp" || ext == ".c")
- sourceFiles.push_back({entry, sourcePath + '/' + entry});
- }
- }
- }
- int TryProgram(const string& s){
- if(debug)
- io::writeln(s);
- return system(s.c_str());
- }
- string findFile(const string& base){
- if(path::isFile(base)) return base;
- for(string& i: includePaths)
- if(path::isFile(i + '/' + base))
- return i + '/' + base;
- return "";
- }
- string findObj(const string& obj){
- if(path::isFile(obj)) return obj;
- if(path::isFile(getObjectPath(obj))) return getObjectPath(obj);
- for(string& i: smartLibs)
- if(path::isFile(getObjectPath(i + '/' + obj)))
- return getObjectPath(i + '/' + obj);
- return "";
- }
- };
- }
- void ws::app(std::vector<string> args){
- try {
- if(args.size() < 2)
- throw ws::Exception("Not enough arguments given");
- if(args[1] == "clean"){
- if(args.size() < 3)
- throw ws::Exception("Not enough arguments given");
- ws::pibuilder builder(args[2]);
- builder.Clean();
- } else if(args[1] == "debug") {
- if(args.size() < 3)
- throw ws::Exception("Not enough arguments given");
- io::writeln("debugging");
- ws::pibuilder builder(args[2]);
- builder.debug = true;
- if(builder.Compile())
- builder.Link();
- builder.RunPost();
- } else {
- ws::pibuilder builder(args[1]);
- if(builder.Compile())
- builder.Link();
- builder.RunPost();
- }
- } catch(ws::Exception& e) {
- ws::io::errln(e.msg(), console::white);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement