#include "CompileStep.h" #include #include "sys.h" #include "toolchain.h" #include "logger.h" #include "globals.h" static bool startsWith(BBParser &parser, const char *str) { for (size_t i = 0; str[i] != '\0'; ++i) { if (parser.peek() != str[i]) return false; parser.skip(); } return true; } bool CompileStep::checkHasChanged(const std::string &outDir) { std::string objPath = toolchain::objectFilePath(path_, outDir); if (!sys::fileExists(objPath)) { return true; } sys::FileInfo objInfo = sys::fileInfo(objPath); sys::FileInfo sourceInfo = sys::fileInfo(path_); if (objInfo.isOlderThan(sourceInfo)) { return true; } std::string bbPath = this->bbPath(outDir); if (!sys::fileExists(bbPath)) { return true; } BBVariables cachedVariables; try { std::ifstream f = sys::ifstream(bbPath); BBParser parser(f, BBParser::FLAG_NONE); parser.parse(cachedVariables); } catch (BBParseError &err) { logger::log(bbPath + ": " + err.what()); return true; } // We can trust the cached "deps" value here, because we know // the object file hasn't actually changed. auto depsIt = cachedVariables.find("deps"); if (depsIt == cachedVariables.end()) { logger::log(bbPath + ": Missing 'deps' field"); return true; } const std::vector &deps = depsIt->second; for (const auto &dep: deps) { if (!sys::fileExists(dep)) { return true; } sys::FileInfo depInfo = sys::fileInfo(dep); if (objInfo.isOlderThan(depInfo)) { return true; } } // Maybe the build command has changed? auto commandIt = cachedVariables.find("command"); if (commandIt == cachedVariables.end()) { logger::log(bbPath + ": Missing 'command' field"); return true; } if (compileCommand(outDir) != commandIt->second) { return true; } return false; } void CompileStep::doBuild(const std::string &outDir) { bool verboseCommand = global::verbose >= 1; if (!verboseCommand) { logger::log("Compile " + path_); } std::string objPath = toolchain::objectFilePath(path_, outDir); std::string dirPath = sys::dirname(objPath); std::vector command = compileCommand(outDir); BBVariables newCachedVars = { { "deps", toolchain::getDependencies(flags(), type_, path_) }, { "command", command}, }; sys::mkdirp(dirPath); std::ofstream f = sys::ofstream(bbPath(outDir)); BBWriter writer(f); writer.write(newCachedVars); sys::execute(command, nullptr, verboseCommand); } void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) { w.write(sys::cwd(), path_, compileCommand(outDir)); } std::vector CompileStep::getPublicLDFlags(const std::string &outDir) { BBVariables &vars = variables(); std::vector flags; toolchain::getLDFlags(vars, flags); return flags; } std::vector CompileStep::getPublicLDLibs(const std::string &outDir) { BBVariables &vars = variables(); std::vector libs; toolchain::getLDLibs(vars, libs); return libs; } std::vector CompileStep::getPublicObjects(const std::string &outDir) { return std::vector{ toolchain::objectFilePath(path_, outDir) }; } BBVariables &CompileStep::variables() { if (hasVariables_) { return variables_; } std::ifstream f = sys::ifstream(path_); BBParser parser(f, BBParser::FLAG_ONE_LINE); while (f.good()) { if (startsWith(parser, "//#bb")) { parser.parse(variables_); } else { while (f.good() && parser.get() != '\n'); } } hasVariables_ = true; return variables_; } std::vector &CompileStep::flags() { if (hasFlags_) { return flags_; } BBVariables &vars = variables(); toolchain::getFlags(vars, type_, flags_); hasFlags_ = true; return flags_; } std::vector &CompileStep::compileCommand(const std::string &outDir) { if (hasCompileCommand_) { return compileCommand_; } compileCommand_ = toolchain::getCompileCommand(flags(), type_, path_, outDir); hasCompileCommand_ = true; return compileCommand_; }