//#bx ldlibs := pthread #include #include #include #include #include #include #include #include #include "BXParser.h" #include "parallel.h" #include "toolchain.h" #include "globals.h" #include "logger.h" #include "sys.h" #include "build.h" #include "compdb.h" static void run(std::vector args, std::vector> kwargs) { std::string op; std::string path; if (args.size() == 0) { op = "build"; path = "./bx-out"; } else if (args[0][0] == '.' || args[0][0] == '/') { op = "build"; path = args[0]; } else if (args.size() == 1) { op = args[0]; path = "./bx-out"; } else if (args.size() == 2) { op = args[0]; path = args[1]; } else { // TODO: Print usage instead? throw std::runtime_error("Incorrect number of arguments"); } sys::mkdirp(path); auto buildVariables = [&]() -> BXVariables { BXVariables variables; if (sys::fileExists(path + "/.config.bx")) { std::ifstream f = sys::ifstream(path + "/.config.bx"); BXParser parser(f, BXParser::FLAG_NONE); parser.parse(variables); } for (auto &pair: kwargs) { std::stringstream ss(pair.second); BXParser parser(ss, BXParser::FLAG_NONE); auto &list = variables[pair.first]; list.clear(); parser.parseList(variables, list); } if (kwargs.size() > 0) { std::ofstream f = sys::ofstream(path + "/.config.bx"); BXWriter w(f); w.write(variables); } return variables; }; auto buildTree = [&](BXVariables vars) -> std::unique_ptr { return buildDepTree(path, std::move(vars)); }; auto buildCompileCommands = [&](DepNode &root) { std::ofstream f = sys::ofstream(path + "/compile_commands.json"); compdb::Writer w(f); root.writeCompDB(path, w); sys::symlink(path + "/compile_commands.json", "compile_commands.json"); }; if (op == "build") { auto root = buildTree(buildVariables()); buildCompileCommands(*root); if (root->hasChanged(path)) { root->startBuild(path); root->joinBuild(); } else { logger::log("Nothing to do."); } } else if (op == "config") { BXVariables variables = buildVariables(); printf("%s:\n", (path + "/.config.bx").c_str()); if (variables.size() == 0) { printf("No config options set.\n"); } for (auto &pair: variables) { printf("%s:", pair.first.c_str()); for (auto &val: pair.second) { printf(" %s", val.c_str()); } printf("\n"); } } else if (op == "compile-commands") { buildCompileCommands(*buildTree(buildVariables())); } else if (op == "clean") { // TODO: Remove what's needed, instead of removing everything and // re-creating .config.bx BXVariables variables = buildVariables(); sys::rmrf(path); sys::rmrf("compile_commands.json"); sys::mkdirp(path); std::ofstream f = sys::ofstream(path + "/.config.bx"); BXWriter w(f); w.write(variables); } else { throw std::runtime_error("Unknown operation '" + op + "'"); } } int main(int argc, char **argv) { int jobs = parallel::coreCount() * 1.2 + 2; std::string workDir = ""; std::string target = ""; const char *shortopts = "hvj:C:"; const struct option opts[] = { { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, { "jobs", required_argument, NULL, 'j' }, { "directory", required_argument, NULL, 'C' }, {}, }; const char usage[] = "Usage: %s [options...] [build | config | compile-commands | clean] [path]\n" "\n" " -h, --help " "Show this help text.\n" " -v, --verbose " "Show every command as it's executing.\n" " -j, --jobs " "Set the number of jobs run simultaneously. " "Default: the number of cores in the machine.\n" " -C, --directory " "Change directory before doing anything else.\n"; // Parse options from argv while (1) { int optidx; int c = getopt_long(argc, argv, shortopts, opts, &optidx); if (c < 0) { break; } switch (c) { case 'h': printf(usage, argv[0]); return 0; case 'v': global::verbose += 1; break; case 'j': jobs = atoi(optarg); if (jobs <= 0) { fprintf(stderr, "Can't run %i jobs.\n", jobs); return 1; } break; case 'C': workDir = optarg; break; default: printf("Unknown option: '%c'.\n", (char)c); printf(usage, argv[0]); return 1; } } parallel::ParallelContext par = parallel::init(jobs); // Change directory? if (workDir.size() > 0) { fprintf(stderr, "Entering directory '%s'\n", workDir.c_str()); sys::chdir(workDir); } // Find args and keyword args std::vector args; std::vector> kwargs; while (optind < argc) { char *arg = argv[optind++]; char *eq = strchr(arg, '='); if (eq == nullptr) { args.push_back(arg); } else { kwargs.push_back(std::make_pair( std::string(arg, eq - arg), std::string(eq + 1))); } } run(std::move(args), std::move(kwargs)); }