#include "toolchain.h" #include #include #include #include #include #include "sys.h" namespace toolchain { static const char *getPkgConfig() { static const char *pkgConfig = nullptr; if (pkgConfig != nullptr) { return pkgConfig; } pkgConfig = getenv("PKG_CONFIG"); if (pkgConfig != nullptr) { return pkgConfig; } return (pkgConfig = "pkg-config"); } static const char *getCCompiler() { static const char *cCompiler = nullptr; if (cCompiler != nullptr) { return cCompiler; } cCompiler = getenv("CC"); if (cCompiler != nullptr) { return cCompiler; } return (cCompiler = "cc"); } static const char *getCXXCompiler() { static const char *cxxCompiler = nullptr; if (cxxCompiler != nullptr) { return cxxCompiler; } cxxCompiler = getenv("CC"); if (cxxCompiler != nullptr) { return cxxCompiler; } return (cxxCompiler = "g++"); } static const char *getCompilerFor(SourceFile::FileType type) { switch (type) { case SourceFile::FileType::C: return getCCompiler(); case SourceFile::FileType::CXX: return getCXXCompiler(); case SourceFile::FileType::UNKNOWN: abort(); } abort(); } static bool isWhitespace(char ch) { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'; } static void parseWhitespaceSeparated( const std::string &input, std::vector &output, size_t pos = 0) { size_t i = pos; while (true) { // Skip leading whitespace char ch = input[i]; while (isWhitespace(ch) || (ch == '\\' && isWhitespace(input[i + 1]))) { ch = input[i += 1]; } // Read non-whitespace std::string str; while (!isWhitespace(ch) && ch != '\0') { if (ch == '\\') { str += input[i + 1]; ch = input[i += 2]; } else { str += input[i]; ch = input[i += 1]; } } output.push_back(std::move(str)); if (ch == '\0') { break; } } } void pkgFlags(const std::vector &pkgs, std::vector &flags) { std::vector argv; argv.push_back(getPkgConfig()); argv.push_back("--cflags"); for (auto &pkg: pkgs) { argv.push_back(pkg.c_str()); } std::string output; sys::execute(argv, &output); parseWhitespaceSeparated(output, flags); } void pkgLDLibs(const std::vector &pkgs, std::vector &flags) { std::vector argv; argv.push_back(getPkgConfig()); argv.push_back("--libs"); for (auto &pkg: pkgs) { argv.push_back(pkg.c_str()); } std::string output; sys::execute(argv, &output); parseWhitespaceSeparated(output, flags); } void getDependencies( const std::vector &flags, SourceFile::FileType type, const std::string &srcDir, const std::string &name, std::vector &deps) { std::string sourcePath = srcDir + "/" + name; std::vector argv; argv.push_back(getCompilerFor(type)); for (auto &flag: flags) { argv.push_back(flag.c_str()); } argv.push_back("-MM"); argv.push_back("-c"); argv.push_back(sourcePath.c_str()); std::string output; sys::execute(argv, &output); size_t idx = output.find(':'); if (idx != std::string::npos) { parseWhitespaceSeparated(output, deps, idx + 1); } } void compile( const std::vector &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 destPath = destDir + "/" + name + ".o"; sys::mkdirp(outDir); std::vector argv; argv.push_back(getCompilerFor(type)); for (auto &flag: flags) { argv.push_back(flag.c_str()); } argv.push_back("-o"); argv.push_back(destPath.c_str()); argv.push_back("-c"); argv.push_back(sourcePath.c_str()); sys::execute(argv, nullptr); } }