|
|
@@ -1,12 +1,7 @@ |
|
|
|
//#bb ldlibs := -lpthread |
|
|
|
|
|
|
|
#include <getopt.h> |
|
|
|
#include <stdexcept> |
|
|
|
#include <fstream> |
|
|
|
#include <iostream> |
|
|
|
#include <sstream> |
|
|
|
#include <unordered_set> |
|
|
|
#include <mutex> |
|
|
|
|
|
|
|
#include "SourceFile.h" |
|
|
|
#include "BBParser.h" |
|
|
@@ -14,58 +9,7 @@ |
|
|
|
#include "toolchain.h" |
|
|
|
#include "globals.h" |
|
|
|
#include "logger.h" |
|
|
|
|
|
|
|
static void findSourcesInDir(std::string dir, std::vector<SourceFile> &sources, |
|
|
|
BBParser::Variables vars); |
|
|
|
|
|
|
|
static void findSources(std::string dir, std::string name, |
|
|
|
std::vector<SourceFile> &sources, BBParser::Variables vars) { |
|
|
|
std::string path = dir + "/" + name; |
|
|
|
sys::FileInfo finfo = sys::fileInfo(path); |
|
|
|
|
|
|
|
if (finfo.isDir) { |
|
|
|
// We don't want to send 'files' |
|
|
|
BBParser::Variables subvars = vars; |
|
|
|
subvars.erase("files"); |
|
|
|
findSourcesInDir(path, sources, std::move(subvars)); |
|
|
|
} else { |
|
|
|
SourceFile::FileType type = SourceFile::fileTypeFrom(name); |
|
|
|
if (type != SourceFile::FileType::UNKNOWN) { |
|
|
|
sources.emplace_back(dir, name, type, vars); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void findSourcesInDir(std::string dir, std::vector<SourceFile> &sources, |
|
|
|
BBParser::Variables vars) { |
|
|
|
std::ifstream buildFile(dir + "/build.bb"); |
|
|
|
std::vector<std::string> files; |
|
|
|
bool hasFiles = false; |
|
|
|
|
|
|
|
// Parse $dir/build.bb, see if it specifies a 'files' value. |
|
|
|
if (buildFile.good()) { |
|
|
|
BBParser parser(buildFile, BBParser::FLAG_NONE); |
|
|
|
parser.parse(vars); |
|
|
|
|
|
|
|
auto it = vars.find("files"); |
|
|
|
if (it != vars.end()) { |
|
|
|
files = it->second; |
|
|
|
hasFiles = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// If build.bb didn't specify 'files', we have to readdir |
|
|
|
if (!hasFiles) { |
|
|
|
sys::readDir(dir, files); |
|
|
|
} |
|
|
|
|
|
|
|
// Go through files |
|
|
|
for (auto &ent: files) { |
|
|
|
std::string path = dir + "/" + ent; |
|
|
|
BBParser::Variables subvars = vars; |
|
|
|
findSources(dir, ent, sources, vars); |
|
|
|
} |
|
|
|
} |
|
|
|
#include "build.h" |
|
|
|
|
|
|
|
static void printState(const std::vector<SourceFile> &sources) { |
|
|
|
for (auto &source: sources) { |
|
|
@@ -79,135 +23,18 @@ static void printState(const std::vector<SourceFile> &sources) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static bool compile(const std::vector<SourceFile> &sources, const std::string &outDir, int jobs) { |
|
|
|
bool compiled = false; |
|
|
|
std::mutex mut; |
|
|
|
parallel::parallel(jobs, sources, [&](const SourceFile &source) { |
|
|
|
if (source.needsRecompile(outDir)) { |
|
|
|
source.compile(outDir); |
|
|
|
mut.lock(); |
|
|
|
compiled = true; |
|
|
|
mut.unlock(); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
return compiled; |
|
|
|
} |
|
|
|
|
|
|
|
static void link( |
|
|
|
const std::vector<SourceFile> &sources, |
|
|
|
const std::string &outDir, const std::string &name, |
|
|
|
toolchain::TargetType targetType) { |
|
|
|
logger::log("Link " + outDir + '/' + name); |
|
|
|
|
|
|
|
std::vector<std::string> ldFlags; |
|
|
|
std::unordered_set<std::string> ldFlagsSet; |
|
|
|
std::vector<std::string> ldLibs; |
|
|
|
std::unordered_set<std::string> ldLibsSet; |
|
|
|
std::vector<std::string> objects; |
|
|
|
|
|
|
|
SourceFile::FileType type = SourceFile::FileType::C; |
|
|
|
|
|
|
|
// Gather ldflags, ldlibs and objects from sources |
|
|
|
std::vector<std::string> flags; |
|
|
|
for (auto &source: sources) { |
|
|
|
if (source.type() != SourceFile::FileType::C) { |
|
|
|
type = source.type(); |
|
|
|
} |
|
|
|
|
|
|
|
flags = source.ldFlags(); |
|
|
|
for (auto &flag: flags) { |
|
|
|
if (flag[0] == '-' && flag[1] == 'l') { |
|
|
|
std::cerr << "Warning: -l flags should go in ldlibs " |
|
|
|
<< "(at " << source.path() << ": " << flag << ")\n"; |
|
|
|
} |
|
|
|
|
|
|
|
auto it = ldFlagsSet.find(flag); |
|
|
|
if (it == ldFlagsSet.end()) { |
|
|
|
ldFlagsSet.emplace(flag); |
|
|
|
ldFlags.push_back(std::move(flag)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
flags = source.ldLibs(); |
|
|
|
for (auto &flag: flags) { |
|
|
|
auto it = ldLibsSet.find(flag); |
|
|
|
if (it == ldLibsSet.end()) { |
|
|
|
ldLibsSet.emplace(flag); |
|
|
|
ldLibs.push_back(std::move(flag)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
objects.push_back(std::move(source.objectPath(outDir))); |
|
|
|
} |
|
|
|
|
|
|
|
flags.clear(); |
|
|
|
|
|
|
|
toolchain::link(name, ldFlags, ldLibs, type, targetType, objects, outDir); |
|
|
|
} |
|
|
|
|
|
|
|
static bool compileAndLink( |
|
|
|
const std::vector<SourceFile> &sources, const std::string &outDir, |
|
|
|
int jobs, const std::string &target, toolchain::TargetType targetType) { |
|
|
|
std::string targetPath = toolchain::targetFilePath(targetType, target, outDir); |
|
|
|
static bool compileAndLink(const build::BuildConf &conf, toolchain::TargetType targetType) { |
|
|
|
std::string targetPath = toolchain::targetFilePath( |
|
|
|
targetType, conf.targetName, conf.outDir); |
|
|
|
|
|
|
|
if (compile(sources, outDir, jobs) || !sys::fileExists(targetPath)) { |
|
|
|
link(sources, outDir, target, targetType); |
|
|
|
if (build::compile(conf) || !sys::fileExists(targetPath)) { |
|
|
|
build::link(conf, targetType); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
static void printCompileCommands( |
|
|
|
const std::vector<SourceFile> &sources, const std::string &outDir, |
|
|
|
std::ostream &os) { |
|
|
|
std::string cwd = sys::cwd(); |
|
|
|
|
|
|
|
os << "[\n\t"; |
|
|
|
|
|
|
|
bool first = true; |
|
|
|
for (auto &source: sources) { |
|
|
|
std::string command; |
|
|
|
for (auto arg: source.compileCommand(outDir)) { |
|
|
|
command += arg + ' '; |
|
|
|
} |
|
|
|
command.pop_back(); |
|
|
|
|
|
|
|
if (!first) { |
|
|
|
os << ", "; |
|
|
|
} |
|
|
|
|
|
|
|
os << "{\n" |
|
|
|
<< "\t\t\"directory\":\"" << cwd << "\"\n" |
|
|
|
<< "\t\t\"command\":\"" << command << "\"\n" |
|
|
|
<< "\t\t\"file\":\"" << source.path() << "\"\n" |
|
|
|
<< "\t}"; |
|
|
|
|
|
|
|
first = false; |
|
|
|
} |
|
|
|
|
|
|
|
os << "\n]\n"; |
|
|
|
} |
|
|
|
|
|
|
|
static std::string findTargetName( |
|
|
|
const BBParser::Variables &vars, |
|
|
|
const std::vector<SourceFile> &sources) { |
|
|
|
auto it = vars.find("target"); |
|
|
|
if (it != vars.end() && it->second.size() != 0) { |
|
|
|
return it->second[0]; |
|
|
|
} |
|
|
|
|
|
|
|
for (auto &source: sources) { |
|
|
|
const std::vector<std::string> *ptr = source.variable("target"); |
|
|
|
if (ptr != nullptr && ptr->size() != 0) { |
|
|
|
return (*ptr)[0]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return "target"; |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char **argv) { |
|
|
|
logger::LogContext logCtx = logger::init(); |
|
|
|
|
|
|
@@ -217,7 +44,7 @@ int main(int argc, char **argv) { |
|
|
|
std::string target = ""; |
|
|
|
|
|
|
|
enum class Action { |
|
|
|
BUILD, PRINT_COMPILE_COMMANDS, PRINT_STATE, |
|
|
|
BUILD, PRINT_STATE, |
|
|
|
}; |
|
|
|
Action action = Action::BUILD; |
|
|
|
|
|
|
@@ -229,7 +56,6 @@ int main(int argc, char **argv) { |
|
|
|
{ "jobs", required_argument, NULL, 'j' }, |
|
|
|
{ "directory", required_argument, NULL, 'C' }, |
|
|
|
{ "target", required_argument, NULL, 't' }, |
|
|
|
{ "compile-commands", no_argument, NULL, 'c' }, |
|
|
|
{ "print-state", no_argument, NULL, 'p' }, |
|
|
|
{}, |
|
|
|
}; |
|
|
@@ -248,8 +74,6 @@ int main(int argc, char **argv) { |
|
|
|
"Default: the number of cores in the machine.\n" |
|
|
|
" -C, --directory <dir> " |
|
|
|
"Change directory before doing anything else.\n" |
|
|
|
" -c, --compile-commands " |
|
|
|
"Write compile commands to stdout.\n" |
|
|
|
" -p, --print-state " |
|
|
|
"Print the state instead of building.\n"; |
|
|
|
|
|
|
@@ -287,10 +111,6 @@ int main(int argc, char **argv) { |
|
|
|
workDir = optarg; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'c': |
|
|
|
action = Action::PRINT_COMPILE_COMMANDS; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'p': |
|
|
|
action = Action::PRINT_STATE; |
|
|
|
break; |
|
|
@@ -307,57 +127,27 @@ int main(int argc, char **argv) { |
|
|
|
sys::chdir(workDir); |
|
|
|
} |
|
|
|
|
|
|
|
// Read config from file |
|
|
|
BBParser::Variables variables; |
|
|
|
if (sys::fileExists("build.bb")) { |
|
|
|
std::ifstream stream("build.bb"); |
|
|
|
BBParser parser(stream, BBParser::FLAG_NONE); |
|
|
|
parser.parse(variables); |
|
|
|
} |
|
|
|
|
|
|
|
// Read variables from argv |
|
|
|
// Read everything related to the build configuration, |
|
|
|
// finding all source files and reading their configs |
|
|
|
std::vector<std::string> args; |
|
|
|
while (optind < argc) { |
|
|
|
std::istringstream stream(argv[optind++]); |
|
|
|
BBParser parser(stream, BBParser::FLAG_ONE_LINE); |
|
|
|
parser.parse(variables); |
|
|
|
} |
|
|
|
|
|
|
|
// Find source dirs |
|
|
|
std::vector<std::string> sourceDirs; |
|
|
|
{ |
|
|
|
auto it = variables.find("files"); |
|
|
|
if (it == variables.end()) { |
|
|
|
sys::readDir(".", sourceDirs); |
|
|
|
} else { |
|
|
|
sourceDirs = it->second; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Read configs from source dirs |
|
|
|
std::vector<SourceFile> sources; |
|
|
|
for (std::string &dir: sourceDirs) { |
|
|
|
findSources(".", dir, sources, variables); |
|
|
|
} |
|
|
|
|
|
|
|
// Find target name |
|
|
|
if (target.size() == 0) { |
|
|
|
target = findTargetName(variables, sources); |
|
|
|
args.push_back(argv[optind++]); |
|
|
|
} |
|
|
|
build::BuildConf conf = build::readBuildConf(std::move(outDir), jobs, args); |
|
|
|
conf.numJobs = jobs; |
|
|
|
|
|
|
|
switch (action) { |
|
|
|
case Action::BUILD: |
|
|
|
// TODO: Support more types than BINARY |
|
|
|
if (!compileAndLink(sources, outDir, jobs, target, toolchain::TargetType::BINARY)) { |
|
|
|
if (compileAndLink(conf, toolchain::TargetType::BINARY)) { |
|
|
|
build::writeCompileCommands(conf); |
|
|
|
} else { |
|
|
|
logger::log("Nothing to do."); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case Action::PRINT_COMPILE_COMMANDS: |
|
|
|
printCompileCommands(sources, outDir, std::cout); |
|
|
|
break; |
|
|
|
|
|
|
|
case Action::PRINT_STATE: |
|
|
|
printState(sources); |
|
|
|
printState(conf.sources); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |