Build tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.cc 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #include <getopt.h>
  2. #include <string.h>
  3. #include <iostream>
  4. #include <fstream>
  5. #include <sstream>
  6. #include <vector>
  7. #include <utility>
  8. #include <stdexcept>
  9. #include "BXParser.h"
  10. #include "parallel.h"
  11. #include "toolchain.h"
  12. #include "globals.h"
  13. #include "logger.h"
  14. #include "sys.h"
  15. #include "build.h"
  16. #include "compdb.h"
  17. static void run(std::vector<std::string> args, std::vector<std::pair<std::string, std::string>> kwargs) {
  18. std::string op;
  19. std::string path;
  20. if (args.size() == 0) {
  21. op = "build";
  22. path = "./bx-out";
  23. } else if (args[0][0] == '.' || args[0][0] == '/') {
  24. op = "build";
  25. path = args[0];
  26. } else if (args.size() == 1) {
  27. op = args[0];
  28. path = "./bx-out";
  29. } else if (args.size() == 2) {
  30. op = args[0];
  31. path = args[1];
  32. } else {
  33. // TODO: Print usage instead?
  34. throw std::runtime_error("Incorrect number of arguments");
  35. }
  36. sys::mkdirp(path);
  37. auto buildVariables = [&]() -> BXVariables {
  38. BXVariables variables;
  39. if (sys::fileExists(path + "/.config.bx")) {
  40. bufio::IFStream f(path + "/.config.bx");
  41. BXParser parser(f, BXParser::FLAG_NONE);
  42. parser.parse(variables);
  43. }
  44. for (auto &pair: kwargs) {
  45. bufio::ISStream ss(pair.second);
  46. BXParser parser(ss, BXParser::FLAG_NONE);
  47. auto &list = variables[pair.first];
  48. list.clear();
  49. parser.parseList(variables, list);
  50. }
  51. if (kwargs.size() > 0) {
  52. bufio::OFStream f(path + "/.config.bx");
  53. BXWriter w(f);
  54. w.write(variables);
  55. }
  56. return variables;
  57. };
  58. auto buildTree = [&](BXVariables vars) -> std::unique_ptr<DepNode> {
  59. return buildDepTree(path, std::move(vars));
  60. };
  61. auto buildCompileCommands = [&](DepNode &root) {
  62. bufio::OFStream f(path + "/compile_commands.json");
  63. compdb::Writer w(f);
  64. root.writeCompDB(path, w);
  65. sys::symlink(path + "/compile_commands.json", "compile_commands.json");
  66. };
  67. if (op == "build") {
  68. auto root = buildTree(buildVariables());
  69. buildCompileCommands(*root);
  70. if (root->hasChanged(path)) {
  71. root->startBuild(path);
  72. root->joinBuild();
  73. } else {
  74. logger::log("Nothing to do.");
  75. }
  76. } else if (op == "config") {
  77. BXVariables variables = buildVariables();
  78. printf("%s:\n", (path + "/.config.bx").c_str());
  79. if (variables.size() == 0) {
  80. printf("No config options set.\n");
  81. }
  82. for (auto &pair: variables) {
  83. printf("%s:", pair.first.c_str());
  84. for (auto &val: pair.second) {
  85. printf(" %s", val.c_str());
  86. }
  87. printf("\n");
  88. }
  89. } else if (op == "compile-commands") {
  90. buildCompileCommands(*buildTree(buildVariables()));
  91. } else if (op == "clean") {
  92. // TODO: Remove what's needed, instead of removing everything and
  93. // re-creating .config.bx
  94. BXVariables variables = buildVariables();
  95. sys::rmrf(path);
  96. sys::rmrf("compile_commands.json");
  97. sys::mkdirp(path);
  98. bufio::OFStream f(path + "/.config.bx");
  99. BXWriter w(f);
  100. w.write(variables);
  101. } else {
  102. throw std::runtime_error("Unknown operation '" + op + "'");
  103. }
  104. }
  105. int main(int argc, char **argv) {
  106. int jobs = parallel::coreCount() * 1.2 + 2;
  107. std::string workDir = "";
  108. std::string target = "";
  109. const char *shortopts = "hvj:C:";
  110. const struct option opts[] = {
  111. { "help", no_argument, NULL, 'h' },
  112. { "verbose", no_argument, NULL, 'v' },
  113. { "jobs", required_argument, NULL, 'j' },
  114. { "directory", required_argument, NULL, 'C' },
  115. {},
  116. };
  117. const char usage[] =
  118. "Usage: %s [options...] [build | config | compile-commands | clean] [path]\n"
  119. "\n"
  120. " -h, --help "
  121. "Show this help text.\n"
  122. " -v, --verbose "
  123. "Show every command as it's executing.\n"
  124. " -j, --jobs <count> "
  125. "Set the number of jobs run simultaneously. "
  126. "Default: the number of cores in the machine.\n"
  127. " -C, --directory <dir> "
  128. "Change directory before doing anything else.\n";
  129. // Parse options from argv
  130. while (1) {
  131. int optidx;
  132. int c = getopt_long(argc, argv, shortopts, opts, &optidx);
  133. if (c < 0) {
  134. break;
  135. }
  136. switch (c) {
  137. case 'h':
  138. printf(usage, argv[0]);
  139. return 0;
  140. case 'v':
  141. global::verbose += 1;
  142. break;
  143. case 'j':
  144. jobs = atoi(optarg);
  145. if (jobs <= 0) {
  146. fprintf(stderr, "Can't run %i jobs.\n", jobs);
  147. return 1;
  148. }
  149. break;
  150. case 'C':
  151. workDir = optarg;
  152. break;
  153. default:
  154. printf("Unknown option: '%c'.\n", (char)c);
  155. printf(usage, argv[0]);
  156. return 1;
  157. }
  158. }
  159. parallel::ParallelContext par = parallel::init(jobs);
  160. // Change directory?
  161. if (workDir.size() > 0) {
  162. fprintf(stderr, "Entering directory '%s'\n", workDir.c_str());
  163. sys::chdir(workDir);
  164. }
  165. // Find args and keyword args
  166. std::vector<std::string> args;
  167. std::vector<std::pair<std::string, std::string>> kwargs;
  168. while (optind < argc) {
  169. char *arg = argv[optind++];
  170. char *eq = strchr(arg, '=');
  171. if (eq == nullptr) {
  172. args.push_back(arg);
  173. } else {
  174. kwargs.push_back(std::make_pair(
  175. std::string(arg, eq - arg), std::string(eq + 1)));
  176. }
  177. }
  178. run(std::move(args), std::move(kwargs));
  179. }