@@ -177,3 +177,14 @@ void SourceFile::compile(const std::string &outDir) const { | |||
compileFlags_.clear(); | |||
hasCompileFlags_ = false; | |||
} | |||
std::vector<std::string> SourceFile::compileCommand(const std::string &outDir) const { | |||
auto res = toolchain::getCompileCommand(compileFlags(), type_, dir_, name_, outDir); | |||
// Nothing will need compile flags after this, so no reason to | |||
// keep it around in memory | |||
compileFlags_.clear(); | |||
hasCompileFlags_ = false; | |||
return res; | |||
} |
@@ -35,6 +35,7 @@ public: | |||
std::vector<std::string> dependencies() const; | |||
bool needsRecompile(const std::string &outDir) const; | |||
void compile(const std::string &outDir) const; | |||
std::vector<std::string> compileCommand(const std::string &outDir) const; | |||
private: | |||
std::string dir_; |
@@ -159,6 +159,37 @@ static bool compileAndLink( | |||
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) { | |||
@@ -186,39 +217,40 @@ int main(int argc, char **argv) { | |||
std::string target = ""; | |||
enum class Action { | |||
BUILD, PRINT_STATE, | |||
BUILD, PRINT_COMPILE_COMMANDS, PRINT_STATE, | |||
}; | |||
Action action = Action::BUILD; | |||
const char *shortopts = "hvo:j:C:t:p"; | |||
const char *shortopts = "hvo:j:C:cp"; | |||
const struct option opts[] = { | |||
{ "help", no_argument, NULL, 'h' }, | |||
{ "verbose", no_argument, NULL, 'v' }, | |||
{ "output", required_argument, NULL, 'o' }, | |||
{ "jobs", required_argument, NULL, 'j' }, | |||
{ "directory", required_argument, NULL, 'C' }, | |||
{ "target", required_argument, NULL, 't' }, | |||
{ "print-state", no_argument, NULL, 'p' }, | |||
{ "help", no_argument, NULL, 'h' }, | |||
{ "verbose", no_argument, NULL, 'v' }, | |||
{ "output", required_argument, NULL, 'o' }, | |||
{ "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' }, | |||
{}, | |||
}; | |||
const char usage[] = | |||
"Usage: bbbuild [options...] [sources]\n" | |||
"\n" | |||
" -h, --help " | |||
" -h, --help " | |||
"Show this help text.\n" | |||
" -v, --verbose " | |||
"Show every command as it's executing." | |||
" -o, --output <dir> " | |||
" -v, --verbose " | |||
"Show every command as it's executing.\n" | |||
" -o, --output <dir> " | |||
"Set output directory. Default: bbbuild\n" | |||
" -j, --jobs <count> " | |||
" -j, --jobs <count> " | |||
"Set the number of jobs run simultaneously. " | |||
"Default: the number of cores in the machine.\n" | |||
" -C, --directory <dir> " | |||
" -C, --directory <dir> " | |||
"Change directory before doing anything else.\n" | |||
" -t, --target <name> " | |||
"Set the name of the executable.\n" | |||
" -p, --print-state " | |||
" -c, --compile-commands " | |||
"Write compile commands to stdout.\n" | |||
" -p, --print-state " | |||
"Print the state instead of building.\n"; | |||
// Parse options from argv | |||
@@ -255,6 +287,10 @@ int main(int argc, char **argv) { | |||
workDir = optarg; | |||
break; | |||
case 'c': | |||
action = Action::PRINT_COMPILE_COMMANDS; | |||
break; | |||
case 'p': | |||
action = Action::PRINT_STATE; | |||
break; | |||
@@ -316,6 +352,10 @@ int main(int argc, char **argv) { | |||
} | |||
break; | |||
case Action::PRINT_COMPILE_COMMANDS: | |||
printCompileCommands(sources, outDir, std::cout); | |||
break; | |||
case Action::PRINT_STATE: | |||
printState(sources); | |||
break; |
@@ -9,6 +9,7 @@ | |||
#include <sys/types.h> | |||
#include <sys/wait.h> | |||
#include <stdexcept> | |||
#include <system_error> | |||
#include "logger.h" | |||
#include "globals.h" | |||
@@ -44,14 +45,14 @@ bool fileExists(const std::string &path) { | |||
void mkdirp(const std::string &path) { | |||
// TODO: Implement this in C++ instead | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
argv.push_back("mkdir"); | |||
argv.push_back("-p"); | |||
argv.push_back(path.c_str()); | |||
argv.push_back(path); | |||
execute(argv, nullptr, global::verbose >= 2); | |||
} | |||
void execute(std::vector<const char *> &args, std::string *output, bool print) { | |||
void execute(const std::vector<std::string> &args, std::string *output, bool print) { | |||
if (print) { | |||
std::string str; | |||
for (size_t i = 0; i < args.size(); ++i) { | |||
@@ -72,7 +73,7 @@ void execute(std::vector<const char *> &args, std::string *output, bool print) { | |||
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(args[i].c_str()); | |||
} | |||
argv.push_back(nullptr); | |||
@@ -165,4 +166,22 @@ void chdir(const std::string &path) { | |||
} | |||
} | |||
std::string cwd() { | |||
std::vector<char> buf; | |||
buf.reserve(128); | |||
while (1) { | |||
char *res = getcwd(buf.data(), buf.capacity()); | |||
if (res == NULL) { | |||
if (errno == ERANGE) { | |||
buf.reserve(buf.capacity() * 2); | |||
} else { | |||
throw std::system_error(EFAULT, std::generic_category()); | |||
} | |||
} else { | |||
std::string str(buf.data()); | |||
return str; | |||
} | |||
} | |||
} | |||
} |
@@ -14,8 +14,9 @@ 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, bool print); | |||
void execute(const std::vector<std::string> &args, std::string *output, bool print); | |||
void readDir(const std::string &path, std::vector<std::string> &files); | |||
void chdir(const std::string &path); | |||
std::string cwd(); | |||
} |
@@ -129,11 +129,11 @@ std::string targetFilePath( | |||
} | |||
void getPkgConfigFlags(const std::vector<std::string> &pkgs, std::vector<std::string> &flags) { | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
argv.push_back(getPkgConfig()); | |||
argv.push_back("--cflags"); | |||
for (auto &pkg: pkgs) { | |||
argv.push_back(pkg.c_str()); | |||
argv.push_back(pkg); | |||
} | |||
// Execute $(PKG_CONFIG) --cflags $(PKGS) | |||
@@ -143,11 +143,11 @@ void getPkgConfigFlags(const std::vector<std::string> &pkgs, std::vector<std::st | |||
} | |||
void getPkgConfigLDLibs(const std::vector<std::string> &pkgs, std::vector<std::string> &flags) { | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
argv.push_back(getPkgConfig()); | |||
argv.push_back("--libs"); | |||
for (auto &pkg: pkgs) { | |||
argv.push_back(pkg.c_str()); | |||
argv.push_back(pkg); | |||
} | |||
// Execute $(PKG_CONFIG) --libs $(PKGS) | |||
@@ -164,19 +164,19 @@ void getDependencies( | |||
std::vector<std::string> &deps) { | |||
std::string sourcePath = srcDir + "/" + name; | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
// $(compiler) | |||
argv.push_back(getCompilerFor(type)); | |||
// $(flags) | |||
for (auto &flag: flags) { | |||
argv.push_back(flag.c_str()); | |||
argv.push_back(flag); | |||
} | |||
// -MM $< | |||
argv.push_back("-MM"); | |||
argv.push_back(sourcePath.c_str()); | |||
argv.push_back(sourcePath); | |||
// Execute $(compiler) $(flags) -MM $< | |||
std::string output; | |||
@@ -188,20 +188,16 @@ void getDependencies( | |||
} | |||
} | |||
void compile( | |||
std::vector<std::string> getCompileCommand( | |||
const std::vector<std::string> &flags, | |||
SourceFile::FileType type, | |||
const std::string &srcDir, | |||
const std::string &name, | |||
const std::string &outDir) { | |||
std::string sourcePath = srcDir + "/" + name; | |||
std::string destDir = outDir + "/" + srcDir; | |||
std::string objectPath = objectFilePath(srcDir, name, outDir); | |||
// Ensure the output directory actually exists | |||
sys::mkdirp(destDir); | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
// $(compiler) | |||
argv.push_back(getCompilerFor(type)); | |||
@@ -213,11 +209,24 @@ void compile( | |||
// -o $@ -c $< | |||
argv.push_back("-o"); | |||
argv.push_back(objectPath.c_str()); | |||
argv.push_back(std::move(objectPath)); | |||
argv.push_back("-c"); | |||
argv.push_back(sourcePath.c_str()); | |||
argv.push_back(std::move(sourcePath)); | |||
return argv; | |||
} | |||
void compile( | |||
const std::vector<std::string> &flags, | |||
SourceFile::FileType type, | |||
const std::string &srcDir, | |||
const std::string &name, | |||
const std::string &outDir) { | |||
// Ensure the output directory actually exists | |||
std::string destDir = outDir + "/" + srcDir; | |||
sys::mkdirp(destDir); | |||
// Execute $(compiler) $(flags) -o $@ -c $< | |||
std::vector<std::string> argv = getCompileCommand(flags, type, srcDir, name, outDir); | |||
sys::execute(argv, nullptr, global::verbose >= 1); | |||
} | |||
@@ -234,28 +243,28 @@ void link( | |||
// TODO: Use ar to create STATIC_LIBRARY, | |||
// use GCC with -shared to make SHARED_LIBRARY | |||
std::vector<const char *> argv; | |||
std::vector<std::string> argv; | |||
// $(compiler) | |||
argv.push_back(getCompilerFor(type)); | |||
// $(ldflags) | |||
for (auto &flag: ldFlags) { | |||
argv.push_back(flag.c_str()); | |||
argv.push_back(flag); | |||
} | |||
// -o $@ | |||
argv.push_back("-o"); | |||
argv.push_back(outPath.c_str()); | |||
argv.push_back(outPath); | |||
// $(objs) | |||
for (auto &obj: objs) { | |||
argv.push_back(obj.c_str()); | |||
argv.push_back(obj); | |||
} | |||
// $(ldlibs) | |||
for (auto &flag: ldLibs) { | |||
argv.push_back(flag.c_str()); | |||
argv.push_back(flag); | |||
} | |||
// Execute $(compiler) $(ldflags) -o $@ $(objs) $(ldlibs) |
@@ -32,6 +32,13 @@ void getDependencies( | |||
const std::string &name, | |||
std::vector<std::string> &deps); | |||
std::vector<std::string> getCompileCommand( | |||
const std::vector<std::string> &flags, | |||
SourceFile::FileType type, | |||
const std::string &srcDir, | |||
const std::string &name, | |||
const std::string &outDir); | |||
void compile( | |||
const std::vector<std::string> &flags, | |||
SourceFile::FileType type, |