Browse Source

add --run option

feature/new-parser
Martin Dørum 3 years ago
parent
commit
b15c1c2d5e
5 changed files with 120 additions and 22 deletions
  1. 55
    21
      cmd/main.cc
  2. 5
    1
      lib/build.cc
  3. 5
    0
      lib/build.h
  4. 54
    0
      lib/sys.cc
  5. 1
    0
      lib/sys.h

+ 55
- 21
cmd/main.cc View File

@@ -16,22 +16,29 @@
#include "build.h"
#include "compdb.h"

static void run(std::vector<std::string> args, std::vector<std::pair<std::string, std::string>> kwargs) {
struct Conf {
std::vector<std::string> args;
std::vector<std::string> args2;
std::vector<std::pair<std::string, std::string>> kwargs;
bool exec = false;
};

static void run(Conf conf) {
std::string op;
std::string path;

if (args.size() == 0) {
if (conf.args.size() == 0) {
op = "build";
path = "./bx-out";
} else if (args[0][0] == '.' || args[0][0] == '/') {
} else if (conf.args[0][0] == '.' || conf.args[0][0] == '/') {
op = "build";
path = args[0];
} else if (args.size() == 1) {
op = args[0];
path = conf.args[0];
} else if (conf.args.size() == 1) {
op = conf.args[0];
path = "./bx-out";
} else if (args.size() == 2) {
op = args[0];
path = args[1];
} else if (conf.args.size() == 2) {
op = conf.args[0];
path = conf.args[1];
} else {
// TODO: Print usage instead?
throw std::runtime_error("Incorrect number of arguments");
@@ -47,7 +54,7 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string
parser.parse(variables);
}

for (auto &pair: kwargs) {
for (auto &pair: conf.kwargs) {
bufio::ISStream ss(pair.second);
BXParser parser(ss);
auto &list = variables[pair.first];
@@ -55,7 +62,7 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string
parser.parseList(variables, list);
}

if (kwargs.size() > 0) {
if (conf.kwargs.size() > 0) {
bufio::OFStream f(path + "/.config.bx");
BXWriter w(f);
w.write(variables);
@@ -65,7 +72,7 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string
};

auto buildTree = [&](BXVariables vars) -> std::unique_ptr<DepNode> {
return buildDepTree(path, std::move(vars));
return build::buildDepTree(path, std::move(vars));
};

auto buildCompileCommands = [&](DepNode &root) {
@@ -76,7 +83,9 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string
};

if (op == "build") {
auto root = buildTree(buildVariables());
auto vars = buildVariables();
std::string targetName = build::findTargetName(vars);
auto root = buildTree(vars);
buildCompileCommands(*root);

if (root->hasChanged(path)) {
@@ -86,6 +95,20 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string
logger::log("Nothing to do.");
}

if (conf.exec) {
std::vector<std::string> argv;
argv.reserve(conf.args2.size() + 1);
argv.push_back(path + '/' + targetName);
for (const auto &arg: conf.args2) {
argv.push_back(std::move(arg));
}
try {
sys::execute(argv, true);
} catch (std::exception &ex) {
logger::log(ex.what());
}
}

} else if (op == "config") {
BXVariables variables = buildVariables();

@@ -122,6 +145,7 @@ static void run(std::vector<std::string> args, std::vector<std::pair<std::string

int main(int argc, char **argv) {
int jobs = parallel::coreCount() * 1.2 + 2;
Conf conf;
std::string workDir = "";
std::string target = "";

@@ -131,6 +155,7 @@ int main(int argc, char **argv) {
{ "verbose", no_argument, NULL, 'v' },
{ "jobs", required_argument, NULL, 'j' },
{ "directory", required_argument, NULL, 'C' },
{ "run", no_argument, NULL, 'R' },
{},
};

@@ -145,10 +170,13 @@ int main(int argc, char **argv) {
"Set the number of jobs run simultaneously. "
"Default: the number of cores in the machine.\n"
" -C, --directory <dir> "
"Change directory before doing anything else.\n";
"Change directory before doing anything else.\n"
" -R, --run <args...> "
"Run executable after building.\n";

// Parse options from argv
while (1) {
bool parsingOpts = true;
while (parsingOpts) {
int optidx;
int c = getopt_long(argc, argv, shortopts, opts, &optidx);

@@ -177,6 +205,14 @@ int main(int argc, char **argv) {
workDir = optarg;
break;

case 'R':
conf.exec = true;
parsingOpts = false;
for (; optind < argc; ++optind) {
conf.args2.push_back(argv[optind]);
}
break;

default:
printf("Unknown option: '%c'.\n", (char)c);
printf(usage, argv[0]);
@@ -193,18 +229,16 @@ int main(int argc, char **argv) {
}

// Find args and keyword args
std::vector<std::string> args;
std::vector<std::pair<std::string, std::string>> kwargs;
while (optind < argc) {
for (; optind < argc; ++optind) {
char *arg = argv[optind++];
char *eq = strchr(arg, '=');
if (eq == nullptr) {
args.push_back(arg);
conf.args.push_back(arg);
} else {
kwargs.push_back(std::make_pair(
conf.kwargs.push_back(std::make_pair(
std::string(arg, eq - arg), std::string(eq + 1)));
}
}

run(std::move(args), std::move(kwargs));
run(std::move(conf));
}

+ 5
- 1
lib/build.cc View File

@@ -11,6 +11,8 @@
#include "LinkStep.h"
#include "logger.h"

namespace build {

static std::string extension(const std::string &path) {
size_t idx = path.find_last_of('.');
if (idx >= std::string::npos) {
@@ -87,7 +89,7 @@ static void findDeps(
}
}

static std::string findTargetName(const BXVariables &variables) {
std::string findTargetName(const BXVariables &variables) {
auto it = variables.find("target");
if (it != variables.end() && it->second.size() != 0) {
return it->second[0];
@@ -132,3 +134,5 @@ std::unique_ptr<DepNode> buildDepTree(const std::string &outDir, BXVariables var

return link;
}

}

+ 5
- 0
lib/build.h View File

@@ -6,4 +6,9 @@
#include "DepNode.h"
#include "BXParser.h"

namespace build {

std::string findTargetName(const BXVariables &variables);
std::unique_ptr<DepNode> buildDepTree(const std::string &outDir, BXVariables variables);

}

+ 54
- 0
lib/sys.cc View File

@@ -186,6 +186,60 @@ void execute(const std::vector<std::string> &args, std::string *output, bool pri
}
}

void execute(const std::vector<std::string> &args, bool print) {
if (print) {
std::string str;
for (size_t i = 0; i < args.size(); ++i) {
if (i != 0) {
str += " ";
}
str += args[i];
}
logger::log(str);
}

// argv[0] should be interpreted as a shell command, because being able to run
// CC='gcc --sysroot=/blah' is used by some systems.
std::string command = std::string(args[0]) + " \"$@\"";
static thread_local std::vector<const char *> argv;
argv.clear();
argv.push_back("/bin/sh"); // TODO: Use $SHELL?
argv.push_back("-c");
argv.push_back(command.c_str());
argv.push_back("--");
for (size_t i = 1; i < args.size(); ++i) {
argv.push_back(args[i].c_str());
}

argv.push_back(nullptr);

pid_t child = fork();
if (child == 0) {
// So, from what I've read, execvp should never modify its argv; so this should be fine?
if (execvp(argv[0], (char *const *)argv.data()) < 0) {
perror(argv[0]);
abort();
}

// This shouldn't happen
exit(0);
} else if (child < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

int wstatus;
waitpid(child, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != 0) {
throw std::runtime_error(std::string(args[0]) +
" exited with code " + std::to_string(WEXITSTATUS(wstatus)));
}

if (WTERMSIG(wstatus)) {
throw std::runtime_error(std::string(args[0]) +
" terminated due to " + strsignal(WTERMSIG(wstatus)));
}
}

void readDir(const std::string &path, std::vector<std::string> &files) {
DIR *d = opendir(path.c_str());
if (d == NULL) {

+ 1
- 0
lib/sys.h View File

@@ -23,6 +23,7 @@ bool fileExists(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, bool print);
void readDir(const std::string &path, std::vector<std::string> &files);
void chdir(const std::string &path);
std::string cwd();

Loading…
Cancel
Save