Преглед на файлове

move execute to sys, add sys::mkdirp

feature/dependency-graph
Martin Dørum преди 3 години
родител
ревизия
e4bfcd4663
променени са 5 файла, в които са добавени 111 реда и са изтрити 107 реда
  1. 0
    1
      example-project/build.bbb
  2. 1
    0
      src/parallel.h
  3. 100
    0
      src/sys.cc
  4. 3
    0
      src/sys.h
  5. 7
    106
      src/toolchain.cc

+ 0
- 1
example-project/build.bbb Целия файл

@@ -1 +0,0 @@
cflags := -O3

+ 1
- 0
src/parallel.h Целия файл

@@ -6,6 +6,7 @@ namespace parallel {

template<typename Container, typename Func>
void parallel(int jobs, Container &cont, Func func) {
// TODO: Actually run this in parallel
for (auto &elem: cont) {
func(elem);
}

+ 100
- 0
src/sys.cc Целия файл

@@ -5,8 +5,12 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdexcept>

#include "globals.h"

namespace sys {

FileInfo fileInfo(const std::string &path) {
@@ -36,4 +40,100 @@ bool fileExists(const std::string &path) {
return true;
}

void mkdirp(const std::string &path) {
// TODO: Implement this in C++ instead
std::vector<const char *> argv;
argv.push_back("mkdir");
argv.push_back("-p");
argv.push_back(path.c_str());
execute(argv, nullptr);
}

void execute(std::vector<const char *> &args, std::string *output) {
if (global::verbose) {
for (size_t i = 0; i < args.size(); ++i) {
if (i == 0) {
fprintf(stderr, "%s", args[i]);
} else {
fprintf(stderr, " %s", args[i]);
}
}
fprintf(stderr, "\n");
}

// 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]) + " \"$@\"";
std::vector<const char *> argv;
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]);
}

argv.push_back(nullptr);

int fds[2];
if (pipe(fds) < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

pid_t child = fork();
if (child == 0) {
close(fds[0]);
dup2(fds[1], 1);

// 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();
}
} else if (child < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

close(fds[1]);

if (output == nullptr) {
close(fds[0]);
} else {
char buf[1025];
while (true) {
ssize_t num = read(fds[0], buf, sizeof(buf) - 1);
if (num < 0 && errno != EAGAIN) {
close(fds[0]);
throw std::runtime_error(std::string("read: ") + strerror(errno));
} else if (num < 0) {
continue;
}

if (num == 0) {
close(fds[1]);
break;
}

buf[num] = '\0';
*output += buf;
}
}

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)));
}

if (output != nullptr && output->back() == '\n') {
output->pop_back();
}
}

}

+ 3
- 0
src/sys.h Целия файл

@@ -1,6 +1,7 @@
#pragma once

#include <string>
#include <vector>

namespace sys {

@@ -12,5 +13,7 @@ struct FileInfo {

FileInfo fileInfo(const std::string &path);
bool fileExists(const std::string &path);
void mkdirp(const std::string &path);
void execute(std::vector<const char *> &args, std::string *output);

}

+ 7
- 106
src/toolchain.cc Целия файл

@@ -2,21 +2,14 @@

#include <stdexcept>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#include "globals.h"
#include "sys.h"

namespace toolchain {

// TODO: Decide whether it would be better to use $SHELL
static const char *getShell() {
return "/bin/sh";
}

static const char *getPkgConfig() {
static const char *pkgConfig = nullptr;
if (pkgConfig != nullptr) {
@@ -74,93 +67,6 @@ static const char *getCompilerFor(SourceFile::FileType type) {
abort();
}

static void execute(std::vector<const char *> &args, std::string *output) {
if (global::verbose) {
for (size_t i = 0; i < args.size(); ++i) {
if (i == 0) {
fprintf(stderr, "%s", args[i]);
} else {
fprintf(stderr, " %s", args[i]);
}
}
fprintf(stderr, "\n");
}

// 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]) + " \"$@\"";
std::vector<const char *> argv;
argv.push_back(getShell());
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]);
}

argv.push_back(nullptr);

int fds[2];
if (pipe(fds) < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

pid_t child = fork();
if (child == 0) {
close(fds[0]);
dup2(fds[1], 1);

// 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();
}
} else if (child < 0) {
throw std::runtime_error(std::string("fork: ") + strerror(errno));
}

close(fds[1]);

if (output == nullptr) {
close(fds[0]);
} else {
char buf[1025];
while (true) {
ssize_t num = read(fds[0], buf, sizeof(buf) - 1);
if (num < 0 && errno != EAGAIN) {
close(fds[0]);
throw std::runtime_error(std::string("read: ") + strerror(errno));
} else if (num < 0) {
continue;
}

if (num == 0) {
close(fds[1]);
break;
}

buf[num] = '\0';
*output += buf;
}
}

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)));
}

if (output != nullptr && output->back() == '\n') {
output->pop_back();
}
}

static bool isWhitespace(char ch) {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
}
@@ -206,7 +112,7 @@ void pkgFlags(const std::vector<std::string> &pkgs, std::vector<std::string> &fl
}

std::string output;
execute(argv, &output);
sys::execute(argv, &output);
parseWhitespaceSeparated(output, flags);
}

@@ -219,7 +125,7 @@ void pkgLDLibs(const std::vector<std::string> &pkgs, std::vector<std::string> &f
}

std::string output;
execute(argv, &output);
sys::execute(argv, &output);
parseWhitespaceSeparated(output, flags);
}

@@ -241,7 +147,7 @@ void getDependencies(
argv.push_back("-c");
argv.push_back(sourcePath.c_str());
std::string output;
execute(argv, &output);
sys::execute(argv, &output);

size_t idx = output.find(':');
if (idx != std::string::npos) {
@@ -259,14 +165,9 @@ void compile(
std::string destDir = outDir + "/" + srcDir;
std::string destPath = destDir + "/" + name + ".o";

// TODO: Change this to a C++ mkdirp function
std::vector<const char *> argv;
argv.push_back("mkdir");
argv.push_back("-p");
argv.push_back(destDir.c_str());
execute(argv, nullptr);
sys::mkdirp(outDir);

argv.clear();
std::vector<const char *> argv;
argv.push_back(getCompilerFor(type));
for (auto &flag: flags) {
argv.push_back(flag.c_str());
@@ -276,7 +177,7 @@ void compile(
argv.push_back(destPath.c_str());
argv.push_back("-c");
argv.push_back(sourcePath.c_str());
execute(argv, nullptr);
sys::execute(argv, nullptr);
}

}

Loading…
Отказ
Запис