Martin Dørum 5 лет назад
Родитель
Сommit
aaaa88a20a
4 измененных файлов: 127 добавлений и 61 удалений
  1. 2
    3
      src/DepNode.cc
  2. 114
    58
      src/main.cc
  3. 10
    0
      src/sys.cc
  4. 1
    0
      src/sys.h

+ 2
- 3
src/DepNode.cc Просмотреть файл

} }


void DepNode::writeCompDB(const std::string &outDir, compdb::Writer &w) { void DepNode::writeCompDB(const std::string &outDir, compdb::Writer &w) {
std::unique_lock<std::mutex> glock(mut_);\
std::unique_lock<std::mutex> lock(mut_);\
doWriteCompDB(outDir, w); doWriteCompDB(outDir, w);
lock.unlock();


// Write children without blocking this node
glock.unlock();
for (auto &dep: deps_) { for (auto &dep: deps_) {
dep->writeCompDB(outDir, w); dep->writeCompDB(outDir, w);
} }

+ 114
- 58
src/main.cc Просмотреть файл

#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <vector>
#include <utility>
#include <stdexcept>


#include "BBParser.h" #include "BBParser.h"
#include "parallel.h" #include "parallel.h"
#include "build.h" #include "build.h"
#include "compdb.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) { int main(int argc, char **argv) {
std::string outDir = "bbbuild"; std::string outDir = "bbbuild";
int jobs = parallel::coreCount() * 1.2 + 2; int jobs = parallel::coreCount() * 1.2 + 2;
std::string workDir = ""; std::string workDir = "";
std::string target = ""; std::string target = "";


const char *shortopts = "hvo:j:C:cp";
const char *shortopts = "hvj:C:";
const struct option opts[] = { const struct option opts[] = {
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' }, { "verbose", no_argument, NULL, 'v' },
{ "output", required_argument, NULL, 'o' },
{ "jobs", required_argument, NULL, 'j' }, { "jobs", required_argument, NULL, 'j' },
{ "directory", required_argument, NULL, 'C' }, { "directory", required_argument, NULL, 'C' },
{ "target", required_argument, NULL, 't' },
{}, {},
}; };


const char usage[] = const char usage[] =
"Usage: bbbuild [options...] [sources]\n"
"Usage: bbbuild [options...] [build | config | compile-commands | clean] [path]\n"
"\n" "\n"
" -h, --help " " -h, --help "
"Show this help text.\n" "Show this help text.\n"
" -v, --verbose " " -v, --verbose "
"Show every command as it's executing.\n" "Show every command as it's executing.\n"
" -o, --output <dir> "
"Set output directory. Default: bbbuild\n"
" -j, --jobs <count> " " -j, --jobs <count> "
"Set the number of jobs run simultaneously. " "Set the number of jobs run simultaneously. "
"Default: the number of cores in the machine.\n" "Default: the number of cores in the machine.\n"
global::verbose += 1; global::verbose += 1;
break; break;


case 'o':
outDir = optarg;
break;

case 'j': case 'j':
jobs = atoi(optarg); jobs = atoi(optarg);
if (jobs <= 0) { if (jobs <= 0) {
sys::chdir(workDir); 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::string> args;
std::vector<std::pair<std::string, std::string>> kwargs;
while (optind < argc) { while (optind < argc) {
char *arg = argv[optind++]; char *arg = argv[optind++];
char *eq = strchr(arg, '='); char *eq = strchr(arg, '=');
if (eq == nullptr) { if (eq == nullptr) {
args.push_back(arg); args.push_back(arg);
} else { } 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));
} }

+ 10
- 0
src/sys.cc Просмотреть файл

execute(argv, nullptr, global::verbose >= 2); execute(argv, nullptr, global::verbose >= 2);
} }


void rmrf(const std::string &path) {
// TODO: Implement this in C++ instead
std::vector<std::string> argv;
argv.push_back("rm");
argv.push_back("-rf");
argv.push_back("--");
argv.push_back(path);
execute(argv, nullptr, global::verbose >= 2);
}

void execute(const std::vector<std::string> &args, std::string *output, bool print) { void execute(const std::vector<std::string> &args, std::string *output, bool print) {
if (print) { if (print) {
std::string str; std::string str;

+ 1
- 0
src/sys.h Просмотреть файл

FileInfo fileInfo(const std::string &path); FileInfo fileInfo(const std::string &path);
bool fileExists(const std::string &path); bool fileExists(const std::string &path);
void mkdirp(const std::string &path); void mkdirp(const std::string &path);
void rmrf(const std::string &path);
void execute(const std::vector<std::string> &args, std::string *output, bool print); void execute(const std::vector<std::string> &args, std::string *output, bool print);
void readDir(const std::string &path, std::vector<std::string> &files); void readDir(const std::string &path, std::vector<std::string> &files);
void chdir(const std::string &path); void chdir(const std::string &path);

Загрузка…
Отмена
Сохранить