@@ -1,9 +1,9 @@ | |||
SRCS = \ | |||
src/BBParser.cc src/build.cc src/CompileStep.cc src/DepNode.cc \ | |||
src/BBParser.cc src/build.cc src/compdb.cc src/CompileStep.cc src/DepNode.cc \ | |||
src/globals.cc src/LinkStep.cc src/logger.cc src/parallel.cc src/sys.cc \ | |||
src/toolchain.cc src/main.cc | |||
HDRS = \ | |||
src/BBParser.h src/build.h src/CompileStep.h src/DepNode.h \ | |||
src/BBParser.h src/build.h src/compdb.h src/CompileStep.h src/DepNode.h \ | |||
src/globals.h src/LinkStep.h src/logger.h src/parallel.h src/sys.h \ | |||
src/toolchain.h | |||
BUILD = build |
@@ -98,6 +98,10 @@ void CompileStep::doBuild(const std::string &outDir) { | |||
sys::execute(command, nullptr, global::verbose >= 1); | |||
} | |||
void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) { | |||
w.write(sys::cwd(), path_, compileCommand(outDir)); | |||
} | |||
std::vector<std::string> CompileStep::getPublicLDFlags(const std::string &outDir) { | |||
BBVariables &vars = variables(); | |||
auto it = vars.find("ldflags"); |
@@ -15,6 +15,7 @@ private: | |||
bool checkHasChanged(const std::string &outDir) override; | |||
void doBuild(const std::string &outDir) override; | |||
void doWriteCompDB(const std::string &outDir, compdb::Writer &w) override; | |||
std::vector<std::string> getPublicLDFlags(const std::string &outDir) override; | |||
std::vector<std::string> getPublicLDLibs(const std::string &outDir) override; | |||
std::vector<std::string> getPublicObjects(const std::string &outDir) override; |
@@ -62,7 +62,7 @@ bool DepNode::haveDepsChanged(const std::string &outDir) { | |||
} | |||
bool DepNode::hasChanged(const std::string &outDir) { | |||
std::lock_guard<std::mutex> lock(mut_); | |||
std::unique_lock<std::mutex> glock(mut_); | |||
if (was_rebuilt_) { | |||
return true; | |||
@@ -74,8 +74,12 @@ bool DepNode::hasChanged(const std::string &outDir) { | |||
return false; | |||
} else { | |||
bool changed = checkHasChanged(outDir); | |||
if (!changed) { | |||
// Check children without blocking this node | |||
glock.unlock(); | |||
changed = haveDepsChanged(outDir); | |||
glock.lock(); | |||
} | |||
if (changed) { | |||
@@ -90,13 +94,15 @@ bool DepNode::hasChanged(const std::string &outDir) { | |||
void DepNode::build(const std::string &outDir) { | |||
bool changed = hasChanged(outDir); | |||
std::lock_guard<std::mutex> lock(mut_);\ | |||
std::unique_lock<std::mutex> glock(mut_);\ | |||
if (!was_rebuilt_ && changed) { | |||
int workers = 0; | |||
std::mutex mut; | |||
std::condition_variable cond; | |||
// Build children without blocking this node | |||
glock.unlock(); | |||
std::unique_lock<std::mutex> lock(mut, std::defer_lock); | |||
for (auto &dep: deps_) { | |||
if (dep->hasChanged(outDir)) { | |||
@@ -116,11 +122,23 @@ void DepNode::build(const std::string &outDir) { | |||
lock.lock(); | |||
cond.wait(lock, [&] { return workers == 0; }); | |||
glock.lock(); | |||
doBuild(outDir); | |||
was_rebuilt_ = true; | |||
} | |||
} | |||
void DepNode::writeCompDB(const std::string &outDir, compdb::Writer &w) { | |||
std::unique_lock<std::mutex> glock(mut_);\ | |||
doWriteCompDB(outDir, w); | |||
// Write children without blocking this node | |||
glock.unlock(); | |||
for (auto &dep: deps_) { | |||
dep->writeCompDB(outDir, w); | |||
} | |||
} | |||
std::vector<std::string> DepNode::publicLDFlags(const std::string &outDir) { | |||
std::unordered_set<std::string> set; | |||
std::vector<std::string> flags; |
@@ -4,12 +4,16 @@ | |||
#include <memory> | |||
#include <mutex> | |||
#include <string> | |||
#include <ostream> | |||
#include "compdb.h" | |||
class DepNode { | |||
public: | |||
void addChild(std::shared_ptr<DepNode> node); | |||
bool hasChanged(const std::string &outDir); | |||
void build(const std::string &outDir); | |||
void writeCompDB(const std::string &outDir, compdb::Writer &w); | |||
virtual std::vector<std::string> publicLDFlags(const std::string &outDir); | |||
virtual std::vector<std::string> publicLDLibs(const std::string &outDir); | |||
virtual std::vector<std::string> publicObjects(const std::string &outDir); | |||
@@ -21,6 +25,7 @@ protected: | |||
virtual bool checkHasChanged(const std::string &outDir) = 0; | |||
virtual void doBuild(const std::string &outDir) = 0; | |||
virtual void doWriteCompDB(const std::string &outDir, compdb::Writer &w) {} | |||
virtual std::vector<std::string> getPublicLDFlags(const std::string &outDir) { return {}; } | |||
virtual std::vector<std::string> getPublicLDLibs(const std::string &outDir) { return {}; } | |||
virtual std::vector<std::string> getPublicObjects(const std::string &outDir) { return {}; } |
@@ -0,0 +1,57 @@ | |||
#include "compdb.h" | |||
namespace compdb { | |||
std::string escape(const std::string &str) { | |||
std::string out; | |||
// TODO: Handle unicode according to JSON spec | |||
for (char ch: str) { | |||
if (ch == '\\' || ch == '\"') { | |||
out += '\\'; | |||
out += ch; | |||
} else if (ch == '\r') { | |||
out += '\\'; | |||
out += 'r'; | |||
} else if (ch == '\n') { | |||
out += '\\'; | |||
out += 'n'; | |||
} else { | |||
out += ch; | |||
} | |||
} | |||
return out; | |||
} | |||
void Writer::write( | |||
const std::string &dir, const std::string &file, | |||
const std::vector<std::string> &cmd) { | |||
if (first_) { | |||
stream_ << "[\n\t{\n"; | |||
first_ = false; | |||
} else { | |||
stream_ << ", {\n"; | |||
} | |||
stream_ | |||
<< "\t\t\"directory\": \"" << escape(dir) << "\"\n" | |||
<< "\t\t\"file\": \"" << escape(file) << "\"\n" | |||
<< "\t\t\"command\": \"" << escape(cmd[0]); | |||
for (size_t i = 1; i < cmd.size(); ++i) { | |||
stream_ << ' ' << escape('"' + escape(cmd[i]) + '"'); | |||
} | |||
stream_ << "\"\n\t}"; | |||
} | |||
Writer::~Writer() { | |||
if (first_) { | |||
stream_ << "[]\n"; | |||
} else { | |||
stream_ << "\n]\n"; | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
#pragma once | |||
#include <string> | |||
#include <vector> | |||
#include <ostream> | |||
namespace compdb { | |||
class Writer { | |||
public: | |||
Writer(std::ostream &stream): stream_(stream) {} | |||
~Writer(); | |||
void write( | |||
const std::string &dir, const std::string &file, | |||
const std::vector<std::string> &cmd); | |||
private: | |||
std::ostream &stream_; | |||
bool first_ = true; | |||
}; | |||
} |
@@ -2,6 +2,7 @@ | |||
#include <getopt.h> | |||
#include <iostream> | |||
#include <fstream> | |||
#include "BBParser.h" | |||
#include "parallel.h" | |||
@@ -10,6 +11,7 @@ | |||
#include "logger.h" | |||
#include "sys.h" | |||
#include "build.h" | |||
#include "compdb.h" | |||
int main(int argc, char **argv) { | |||
std::string outDir = "bbbuild"; | |||
@@ -105,7 +107,17 @@ int main(int argc, char **argv) { | |||
std::unique_ptr<DepNode> root = buildDepTree(outDir, vars); | |||
if (root == nullptr) { | |||
logger::log("No source files."); | |||
} else if (root->hasChanged(outDir)) { | |||
return 0; | |||
} | |||
{ | |||
std::ofstream f(outDir + "/compile_commands.json"); | |||
compdb::Writer writer(f); | |||
root->writeCompDB(outDir, writer); | |||
sys::symlink(outDir + "/compile_commands.json", "compile_commands.json"); | |||
} | |||
if (root->hasChanged(outDir)) { | |||
root->build(outDir); | |||
} else { | |||
logger::log("Nothing to do."); |