|
|
@@ -5,6 +5,9 @@ |
|
|
|
#include <iostream> |
|
|
|
#include <fstream> |
|
|
|
#include <sstream> |
|
|
|
#include <vector> |
|
|
|
#include <utility> |
|
|
|
#include <stdexcept> |
|
|
|
|
|
|
|
#include "BBParser.h" |
|
|
|
#include "parallel.h" |
|
|
@@ -15,32 +18,132 @@ |
|
|
|
#include "build.h" |
|
|
|
#include "compdb.h" |
|
|
|
|
|
|
|
static void run(std::vector<std::string> args, std::vector<std::pair<std::string, std::string>> kwargs) { |
|
|
|
std::string op; |
|
|
|
std::string path; |
|
|
|
|
|
|
|
if (args.size() == 0) { |
|
|
|
op = "build"; |
|
|
|
path = "./bb-out"; |
|
|
|
} else if (args[0][0] == '.' || args[0][0] == '/') { |
|
|
|
op = "build"; |
|
|
|
path = args[0]; |
|
|
|
} else if (args.size() == 1) { |
|
|
|
op = args[0]; |
|
|
|
path = "./bb-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 = [&]() -> BBVariables { |
|
|
|
BBVariables variables; |
|
|
|
if (sys::fileExists(path + "/.config.bb")) { |
|
|
|
std::ifstream f = sys::ifstream(path + "/.config.bb"); |
|
|
|
BBParser parser(f, BBParser::FLAG_NONE); |
|
|
|
parser.parse(variables); |
|
|
|
} |
|
|
|
|
|
|
|
for (auto &pair: kwargs) { |
|
|
|
std::stringstream ss(pair.second); |
|
|
|
BBParser parser(ss, BBParser::FLAG_NONE); |
|
|
|
auto &list = variables[pair.first]; |
|
|
|
list.clear(); |
|
|
|
parser.parseList(variables, list); |
|
|
|
} |
|
|
|
|
|
|
|
if (kwargs.size() > 0) { |
|
|
|
std::ofstream f = sys::ofstream(path + "/.config.bb"); |
|
|
|
BBWriter w(f); |
|
|
|
w.write(variables); |
|
|
|
} |
|
|
|
|
|
|
|
return variables; |
|
|
|
}; |
|
|
|
|
|
|
|
auto buildTree = [&](BBVariables vars) -> std::unique_ptr<DepNode> { |
|
|
|
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") { |
|
|
|
BBVariables variables = buildVariables(); |
|
|
|
|
|
|
|
printf("%s:\n", (path + "/.config.bb").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.bb |
|
|
|
BBVariables variables = buildVariables(); |
|
|
|
sys::rmrf(path); |
|
|
|
sys::rmrf("compile_commands.json"); |
|
|
|
sys::mkdirp(path); |
|
|
|
std::ofstream f = sys::ofstream(path + "/.config.bb"); |
|
|
|
BBWriter w(f); |
|
|
|
w.write(variables); |
|
|
|
|
|
|
|
} else { |
|
|
|
throw std::runtime_error("Unknown operation '" + op + "'"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char **argv) { |
|
|
|
std::string outDir = "bbbuild"; |
|
|
|
int jobs = parallel::coreCount() * 1.2 + 2; |
|
|
|
std::string workDir = ""; |
|
|
|
std::string target = ""; |
|
|
|
|
|
|
|
const char *shortopts = "hvo:j:C:cp"; |
|
|
|
const char *shortopts = "hvj:C:"; |
|
|
|
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' }, |
|
|
|
{}, |
|
|
|
}; |
|
|
|
|
|
|
|
const char usage[] = |
|
|
|
"Usage: bbbuild [options...] [sources]\n" |
|
|
|
"Usage: bbbuild [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" |
|
|
|
" -o, --output <dir> " |
|
|
|
"Set output directory. Default: bbbuild\n" |
|
|
|
" -j, --jobs <count> " |
|
|
|
"Set the number of jobs run simultaneously. " |
|
|
|
"Default: the number of cores in the machine.\n" |
|
|
@@ -65,10 +168,6 @@ int main(int argc, char **argv) { |
|
|
|
global::verbose += 1; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'o': |
|
|
|
outDir = optarg; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'j': |
|
|
|
jobs = atoi(optarg); |
|
|
|
if (jobs <= 0) { |
|
|
@@ -96,62 +195,19 @@ int main(int argc, char **argv) { |
|
|
|
sys::chdir(workDir); |
|
|
|
} |
|
|
|
|
|
|
|
// Read in variables from conf if it exists |
|
|
|
BBVariables variables; |
|
|
|
if (sys::fileExists(outDir + "/.config.bb")) { |
|
|
|
std::ifstream f = sys::ifstream(outDir + "/.config.bb"); |
|
|
|
BBParser parser(f, BBParser::FLAG_NONE); |
|
|
|
parser.parse(variables); |
|
|
|
} |
|
|
|
|
|
|
|
// Read non-option arguments (variable definitions and args) |
|
|
|
bool varsChanged = false; |
|
|
|
// Find args and keyword args |
|
|
|
std::vector<std::string> args; |
|
|
|
std::vector<std::pair<std::string, std::string>> kwargs; |
|
|
|
while (optind < argc) { |
|
|
|
char *arg = argv[optind++]; |
|
|
|
char *eq = strchr(arg, '='); |
|
|
|
if (eq == nullptr) { |
|
|
|
args.push_back(arg); |
|
|
|
} else { |
|
|
|
varsChanged = true; |
|
|
|
std::stringstream val(eq + 1); |
|
|
|
BBParser parser(val, BBParser::FLAG_NONE); |
|
|
|
std::string key(arg, eq - arg); |
|
|
|
std::vector<std::string> &list = variables[key]; |
|
|
|
list.clear(); |
|
|
|
parser.parseList(variables, list); |
|
|
|
kwargs.push_back(std::make_pair( |
|
|
|
std::string(arg, eq - arg), std::string(eq + 1))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// If our variables changed, write out the new ones |
|
|
|
if (varsChanged) { |
|
|
|
std::ofstream f = sys::ofstream(outDir + "/.config.bb"); |
|
|
|
BBWriter w(f); |
|
|
|
w.write(variables); |
|
|
|
} |
|
|
|
|
|
|
|
// Build dependency graph |
|
|
|
std::unique_ptr<DepNode> root = buildDepTree(outDir, variables); |
|
|
|
if (root == nullptr) { |
|
|
|
logger::log("No source files."); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
sys::mkdirp(outDir); |
|
|
|
|
|
|
|
// Build compile commands |
|
|
|
{ |
|
|
|
std::ofstream f = sys::ofstream(outDir + "/compile_commands.json"); |
|
|
|
compdb::Writer writer(f); |
|
|
|
root->writeCompDB(outDir, writer); |
|
|
|
sys::symlink(outDir + "/compile_commands.json", "compile_commands.json"); |
|
|
|
} |
|
|
|
|
|
|
|
// Build the project |
|
|
|
if (root->hasChanged(outDir)) { |
|
|
|
root->startBuild(outDir); |
|
|
|
root->joinBuild(); |
|
|
|
} else { |
|
|
|
logger::log("Nothing to do."); |
|
|
|
} |
|
|
|
run(std::move(args), std::move(kwargs)); |
|
|
|
} |