//#bb ldlibs := -lpthread #include #include #include "SourceFile.h" #include "BBParser.h" #include "parallel.h" #include "toolchain.h" #include "globals.h" #include "logger.h" #include "build.h" static void printState(const std::vector &sources) { for (auto &source: sources) { std::cout << source.dir() << '/' << source.name() << ":\n"; for (auto &kv: source.vars()) { std::cout << " " << kv.first << ":\n"; for (auto &val: kv.second) { std::cout << " " << val << '\n'; } } } } static bool compileAndLink(const build::BuildConf &conf, toolchain::TargetType targetType) { std::string targetPath = toolchain::targetFilePath( targetType, conf.targetName, conf.outDir); if (build::compile(conf) || !sys::fileExists(targetPath)) { build::link(conf, targetType); return true; } return false; } int main(int argc, char **argv) { logger::LogContext logCtx = logger::init(); std::string outDir = "bbbuild"; int jobs = parallel::coreCount(); std::string workDir = ""; std::string target = ""; enum class Action { BUILD, PRINT_STATE, }; Action action = Action::BUILD; const char *shortopts = "hvo:j:C:cp"; const struct option opts[] = { { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, { "output", required_argument, NULL, 'o' }, { "jobs", required_argument, NULL, 'j' }, { "directory", required_argument, NULL, 'C' }, { "target", required_argument, NULL, 't' }, { "print-state", no_argument, NULL, 'p' }, {}, }; const char usage[] = "Usage: bbbuild [options...] [sources]\n" "\n" " -h, --help " "Show this help text.\n" " -v, --verbose " "Show every command as it's executing.\n" " -o, --output " "Set output directory. Default: bbbuild\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" " -p, --print-state " "Print the state instead of building.\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': puts(usage); return 0; case 'v': global::verbose += 1; break; case 'o': outDir = optarg; 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; case 'p': action = Action::PRINT_STATE; break; default: printf("Unknown option: '%c'.\n%s", (char)c, usage); return 1; } } // Change directory? if (workDir.size() > 0) { fprintf(stderr, "Entering directory '%s'\n", workDir.c_str()); sys::chdir(workDir); } // Read everything related to the build configuration, // finding all source files and reading their configs std::vector args; while (optind < argc) { args.push_back(argv[optind++]); } build::BuildConf conf = build::readBuildConf(std::move(outDir), jobs, args); conf.numJobs = jobs; switch (action) { case Action::BUILD: // TODO: Support more types than BINARY if (compileAndLink(conf, toolchain::TargetType::BINARY)) { build::writeCompileCommands(conf); } else { logger::log("Nothing to do."); } break; case Action::PRINT_STATE: printState(conf.sources); break; } }