@@ -1,8 +1,8 @@ | |||
SRCS = \ | |||
src/BBBParser.cc src/SourceFile.cc src/toolchain.cc src/globals.cc \ | |||
src/sys.cc src/parallel.cc src/main.cc | |||
src/logger.cc src/sys.cc src/parallel.cc src/main.cc | |||
HDRS = src/BBBParser.h src/SourceFile.h src/toolchain.h src/globals.h \ | |||
src/sys.h src/parallel.h | |||
src/logger.h src/sys.h src/parallel.h | |||
BUILD = build | |||
OBJS = $(patsubst %,$(BUILD)/%.o,$(SRCS)) | |||
CFLAGS = -g -Wall -Wextra -Wno-unused-parameter |
@@ -6,6 +6,7 @@ | |||
#include <string.h> | |||
#include "toolchain.h" | |||
#include "logger.h" | |||
static bool startsWith(BBBParser &parser, const char *str) { | |||
for (size_t i = 0; str[i] != '\0'; ++i) { | |||
@@ -166,7 +167,7 @@ bool SourceFile::needsRecompile(const std::string &outDir) const { | |||
void SourceFile::compile(const std::string &outDir) const { | |||
// TODO: Send this as a message to some printer thread instead, | |||
// because this happens in multiple threads | |||
std::cerr << "Compile " << objectPath(outDir) << '\n'; | |||
logger::log("Compile " + objectPath(outDir)); | |||
toolchain::compile(compileFlags(), type_, dir_, name_, outDir); | |||
// Nothing will need compile flags after it's compiled, so no reason to |
@@ -0,0 +1,54 @@ | |||
#include "logger.h" | |||
#include <mutex> | |||
#include <vector> | |||
#include <condition_variable> | |||
#include <thread> | |||
#include <iostream> | |||
#include <atomic> | |||
namespace logger { | |||
static std::vector<std::string> queue; | |||
static std::mutex mut; | |||
static std::condition_variable cond; | |||
static std::thread thread; | |||
static std::atomic_bool running; | |||
static void print(const std::string &msg) { | |||
std::cerr << msg << '\n'; | |||
} | |||
LogContext::~LogContext() { | |||
running.store(false); | |||
cond.notify_one(); | |||
thread.join(); | |||
} | |||
void log(std::string msg) { | |||
std::unique_lock<std::mutex> lock(mut); | |||
queue.emplace_back(std::move(msg)); | |||
lock.unlock(); | |||
cond.notify_one(); | |||
} | |||
LogContext init() { | |||
running = true; | |||
thread = std::thread([&] { | |||
std::unique_lock<std::mutex> lock(mut); | |||
while (running.load()) { | |||
cond.wait(lock, [&] { return !queue.empty() || !running.load(); }); | |||
for (std::string &msg: queue) { | |||
print(msg); | |||
} | |||
queue.clear(); | |||
} | |||
}); | |||
return LogContext{}; | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
#pragma once | |||
#include <string> | |||
namespace logger { | |||
struct LogContext { | |||
~LogContext(); | |||
}; | |||
void log(std::string msg); | |||
LogContext init(); | |||
} |
@@ -16,6 +16,7 @@ | |||
#include "parallel.h" | |||
#include "toolchain.h" | |||
#include "globals.h" | |||
#include "logger.h" | |||
static void readDir(std::string dir, std::vector<SourceFile> &sources, | |||
BBBParser::Variables vars); | |||
@@ -113,7 +114,7 @@ static void link( | |||
const std::vector<SourceFile> &sources, | |||
const std::string &outDir, const std::string &name, | |||
toolchain::TargetType targetType) { | |||
std::cerr << "Link " << outDir << '/' << name << '\n'; | |||
logger::log("Link " + outDir + '/' + name); | |||
std::vector<std::string> ldFlags; | |||
std::unordered_set<std::string> ldFlagsSet; | |||
@@ -175,6 +176,8 @@ static bool compileAndLink( | |||
} | |||
int main(int argc, char **argv) { | |||
logger::LogContext logCtx = logger::init(); | |||
std::vector<std::string> srcDirs; | |||
std::string outDir = "bbbuild"; | |||
int jobs = parallel::coreCount(); | |||
@@ -301,7 +304,7 @@ int main(int argc, char **argv) { | |||
case Action::BUILD: | |||
// TODO: Support more types than BINARY | |||
if (!compileAndLink(sources, outDir, jobs, target, toolchain::TargetType::BINARY)) { | |||
std::cerr << "Nothing to do.\n"; | |||
logger::log("Nothing to do.\n"); | |||
} | |||
break; | |||
@@ -10,6 +10,7 @@ | |||
#include <stdexcept> | |||
#include "globals.h" | |||
#include "logger.h" | |||
namespace sys { | |||
@@ -51,14 +52,16 @@ void mkdirp(const std::string &path) { | |||
void execute(std::vector<const char *> &args, std::string *output) { | |||
if (global::verbose) { | |||
std::string str; | |||
for (size_t i = 0; i < args.size(); ++i) { | |||
if (i == 0) { | |||
fprintf(stderr, " %s", args[i]); | |||
str += " "; | |||
} else { | |||
fprintf(stderr, " %s", args[i]); | |||
str += " "; | |||
} | |||
str += args[i]; | |||
} | |||
fprintf(stderr, "\n"); | |||
logger::log(str); | |||
} | |||
// argv[0] should be interpreted as a shell command, because being able to run | |||
@@ -90,6 +93,9 @@ void execute(std::vector<const char *> &args, std::string *output) { | |||
perror(argv[0]); | |||
abort(); | |||
} | |||
// This shouldn't happen | |||
exit(0); | |||
} else if (child < 0) { | |||
throw std::runtime_error(std::string("fork: ") + strerror(errno)); | |||
} | |||
@@ -104,13 +110,15 @@ void execute(std::vector<const char *> &args, std::string *output) { | |||
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)); | |||
throw std::runtime_error( | |||
std::string("read: ") + strerror(errno) + | |||
" (fd: " + std::to_string(fds[0]) + ")"); | |||
} else if (num < 0) { | |||
continue; | |||
} | |||
if (num == 0) { | |||
close(fds[1]); | |||
close(fds[0]); | |||
break; | |||
} | |||