Browse Source

compile_commands

feature/dependency-graph
Martin Dørum 3 years ago
parent
commit
33bef52e6d
7 changed files with 132 additions and 44 deletions
  1. 11
    0
      src/SourceFile.cc
  2. 1
    0
      src/SourceFile.h
  3. 58
    18
      src/main.cc
  4. 23
    4
      src/sys.cc
  5. 2
    1
      src/sys.h
  6. 30
    21
      src/toolchain.cc
  7. 7
    0
      src/toolchain.h

+ 11
- 0
src/SourceFile.cc View File

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;
}

+ 1
- 0
src/SourceFile.h View File

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_;

+ 58
- 18
src/main.cc View File

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;

+ 23
- 4
src/sys.cc View File

#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;
}
}
}

} }

+ 2
- 1
src/sys.h View File

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();


} }

+ 30
- 21
src/toolchain.cc View File

} }


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)

+ 7
- 0
src/toolchain.h View File

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,

Loading…
Cancel
Save