| @@ -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, | |||