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