compileFlags_.clear(); | compileFlags_.clear(); | ||||
hasCompileFlags_ = false; | 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; | |||||
} |
std::vector<std::string> dependencies() const; | std::vector<std::string> dependencies() const; | ||||
bool needsRecompile(const std::string &outDir) const; | bool needsRecompile(const std::string &outDir) const; | ||||
void compile(const std::string &outDir) const; | void compile(const std::string &outDir) const; | ||||
std::vector<std::string> compileCommand(const std::string &outDir) const; | |||||
private: | private: | ||||
std::string dir_; | std::string dir_; |
return false; | 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( | static std::string findTargetName( | ||||
const BBParser::Variables &vars, | const BBParser::Variables &vars, | ||||
const std::vector<SourceFile> &sources) { | const std::vector<SourceFile> &sources) { | ||||
std::string target = ""; | std::string target = ""; | ||||
enum class Action { | enum class Action { | ||||
BUILD, PRINT_STATE, | |||||
BUILD, PRINT_COMPILE_COMMANDS, PRINT_STATE, | |||||
}; | }; | ||||
Action action = Action::BUILD; | Action action = Action::BUILD; | ||||
const char *shortopts = "hvo:j:C:t:p"; | |||||
const char *shortopts = "hvo:j:C:cp"; | |||||
const struct option opts[] = { | 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[] = | const char usage[] = | ||||
"Usage: bbbuild [options...] [sources]\n" | "Usage: bbbuild [options...] [sources]\n" | ||||
"\n" | "\n" | ||||
" -h, --help " | |||||
" -h, --help " | |||||
"Show this help text.\n" | "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" | "Set output directory. Default: bbbuild\n" | ||||
" -j, --jobs <count> " | |||||
" -j, --jobs <count> " | |||||
"Set the number of jobs run simultaneously. " | "Set the number of jobs run simultaneously. " | ||||
"Default: the number of cores in the machine.\n" | "Default: the number of cores in the machine.\n" | ||||
" -C, --directory <dir> " | |||||
" -C, --directory <dir> " | |||||
"Change directory before doing anything else.\n" | "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"; | "Print the state instead of building.\n"; | ||||
// Parse options from argv | // Parse options from argv | ||||
workDir = optarg; | workDir = optarg; | ||||
break; | break; | ||||
case 'c': | |||||
action = Action::PRINT_COMPILE_COMMANDS; | |||||
break; | |||||
case 'p': | case 'p': | ||||
action = Action::PRINT_STATE; | action = Action::PRINT_STATE; | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
case Action::PRINT_COMPILE_COMMANDS: | |||||
printCompileCommands(sources, outDir, std::cout); | |||||
break; | |||||
case Action::PRINT_STATE: | case Action::PRINT_STATE: | ||||
printState(sources); | printState(sources); | ||||
break; | break; |
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
#include <stdexcept> | #include <stdexcept> | ||||
#include <system_error> | |||||
#include "logger.h" | #include "logger.h" | ||||
#include "globals.h" | #include "globals.h" | ||||
void mkdirp(const std::string &path) { | void mkdirp(const std::string &path) { | ||||
// TODO: Implement this in C++ instead | // TODO: Implement this in C++ instead | ||||
std::vector<const char *> argv; | |||||
std::vector<std::string> argv; | |||||
argv.push_back("mkdir"); | argv.push_back("mkdir"); | ||||
argv.push_back("-p"); | argv.push_back("-p"); | ||||
argv.push_back(path.c_str()); | |||||
argv.push_back(path); | |||||
execute(argv, nullptr, global::verbose >= 2); | 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) { | if (print) { | ||||
std::string str; | std::string str; | ||||
for (size_t i = 0; i < args.size(); ++i) { | for (size_t i = 0; i < args.size(); ++i) { | ||||
argv.push_back(command.c_str()); | argv.push_back(command.c_str()); | ||||
argv.push_back("--"); | argv.push_back("--"); | ||||
for (size_t i = 1; i < args.size(); ++i) { | 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); | argv.push_back(nullptr); | ||||
} | } | ||||
} | } | ||||
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; | |||||
} | |||||
} | |||||
} | |||||
} | } |
FileInfo fileInfo(const std::string &path); | FileInfo fileInfo(const std::string &path); | ||||
bool fileExists(const std::string &path); | bool fileExists(const std::string &path); | ||||
void mkdirp(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 readDir(const std::string &path, std::vector<std::string> &files); | ||||
void chdir(const std::string &path); | void chdir(const std::string &path); | ||||
std::string cwd(); | |||||
} | } |
} | } | ||||
void getPkgConfigFlags(const std::vector<std::string> &pkgs, std::vector<std::string> &flags) { | 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(getPkgConfig()); | ||||
argv.push_back("--cflags"); | argv.push_back("--cflags"); | ||||
for (auto &pkg: pkgs) { | for (auto &pkg: pkgs) { | ||||
argv.push_back(pkg.c_str()); | |||||
argv.push_back(pkg); | |||||
} | } | ||||
// Execute $(PKG_CONFIG) --cflags $(PKGS) | // Execute $(PKG_CONFIG) --cflags $(PKGS) | ||||
} | } | ||||
void getPkgConfigLDLibs(const std::vector<std::string> &pkgs, std::vector<std::string> &flags) { | 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(getPkgConfig()); | ||||
argv.push_back("--libs"); | argv.push_back("--libs"); | ||||
for (auto &pkg: pkgs) { | for (auto &pkg: pkgs) { | ||||
argv.push_back(pkg.c_str()); | |||||
argv.push_back(pkg); | |||||
} | } | ||||
// Execute $(PKG_CONFIG) --libs $(PKGS) | // Execute $(PKG_CONFIG) --libs $(PKGS) | ||||
std::vector<std::string> &deps) { | std::vector<std::string> &deps) { | ||||
std::string sourcePath = srcDir + "/" + name; | std::string sourcePath = srcDir + "/" + name; | ||||
std::vector<const char *> argv; | |||||
std::vector<std::string> argv; | |||||
// $(compiler) | // $(compiler) | ||||
argv.push_back(getCompilerFor(type)); | argv.push_back(getCompilerFor(type)); | ||||
// $(flags) | // $(flags) | ||||
for (auto &flag: flags) { | for (auto &flag: flags) { | ||||
argv.push_back(flag.c_str()); | |||||
argv.push_back(flag); | |||||
} | } | ||||
// -MM $< | // -MM $< | ||||
argv.push_back("-MM"); | argv.push_back("-MM"); | ||||
argv.push_back(sourcePath.c_str()); | |||||
argv.push_back(sourcePath); | |||||
// Execute $(compiler) $(flags) -MM $< | // Execute $(compiler) $(flags) -MM $< | ||||
std::string output; | std::string output; | ||||
} | } | ||||
} | } | ||||
void compile( | |||||
std::vector<std::string> getCompileCommand( | |||||
const std::vector<std::string> &flags, | const std::vector<std::string> &flags, | ||||
SourceFile::FileType type, | SourceFile::FileType type, | ||||
const std::string &srcDir, | const std::string &srcDir, | ||||
const std::string &name, | const std::string &name, | ||||
const std::string &outDir) { | const std::string &outDir) { | ||||
std::string sourcePath = srcDir + "/" + name; | std::string sourcePath = srcDir + "/" + name; | ||||
std::string destDir = outDir + "/" + srcDir; | |||||
std::string objectPath = objectFilePath(srcDir, name, outDir); | 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) | // $(compiler) | ||||
argv.push_back(getCompilerFor(type)); | argv.push_back(getCompilerFor(type)); | ||||
// -o $@ -c $< | // -o $@ -c $< | ||||
argv.push_back("-o"); | argv.push_back("-o"); | ||||
argv.push_back(objectPath.c_str()); | |||||
argv.push_back(std::move(objectPath)); | |||||
argv.push_back("-c"); | 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); | sys::execute(argv, nullptr, global::verbose >= 1); | ||||
} | } | ||||
// TODO: Use ar to create STATIC_LIBRARY, | // TODO: Use ar to create STATIC_LIBRARY, | ||||
// use GCC with -shared to make SHARED_LIBRARY | // use GCC with -shared to make SHARED_LIBRARY | ||||
std::vector<const char *> argv; | |||||
std::vector<std::string> argv; | |||||
// $(compiler) | // $(compiler) | ||||
argv.push_back(getCompilerFor(type)); | argv.push_back(getCompilerFor(type)); | ||||
// $(ldflags) | // $(ldflags) | ||||
for (auto &flag: ldFlags) { | for (auto &flag: ldFlags) { | ||||
argv.push_back(flag.c_str()); | |||||
argv.push_back(flag); | |||||
} | } | ||||
// -o $@ | // -o $@ | ||||
argv.push_back("-o"); | argv.push_back("-o"); | ||||
argv.push_back(outPath.c_str()); | |||||
argv.push_back(outPath); | |||||
// $(objs) | // $(objs) | ||||
for (auto &obj: objs) { | for (auto &obj: objs) { | ||||
argv.push_back(obj.c_str()); | |||||
argv.push_back(obj); | |||||
} | } | ||||
// $(ldlibs) | // $(ldlibs) | ||||
for (auto &flag: ldLibs) { | for (auto &flag: ldLibs) { | ||||
argv.push_back(flag.c_str()); | |||||
argv.push_back(flag); | |||||
} | } | ||||
// Execute $(compiler) $(ldflags) -o $@ $(objs) $(ldlibs) | // Execute $(compiler) $(ldflags) -o $@ $(objs) $(ldlibs) |
const std::string &name, | const std::string &name, | ||||
std::vector<std::string> &deps); | 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( | void compile( | ||||
const std::vector<std::string> &flags, | const std::vector<std::string> &flags, | ||||
SourceFile::FileType type, | SourceFile::FileType type, |