Build tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CompileStep.cc 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include "CompileStep.h"
  2. #include <fstream>
  3. #include "sys.h"
  4. #include "toolchain.h"
  5. #include "logger.h"
  6. #include "globals.h"
  7. static bool startsWith(BXParser &parser, const char *str) {
  8. for (size_t i = 0; str[i] != '\0'; ++i) {
  9. if (parser.peek() != str[i])
  10. return false;
  11. parser.skip();
  12. }
  13. return true;
  14. }
  15. bool CompileStep::checkHasChanged(const std::string &outDir) {
  16. std::string objPath = toolchain::objectFilePath(path_, outDir);
  17. if (!sys::fileExists(objPath)) {
  18. return true;
  19. }
  20. sys::FileInfo objInfo = sys::fileInfo(objPath);
  21. sys::FileInfo sourceInfo = sys::fileInfo(path_);
  22. if (objInfo.isOlderThan(sourceInfo)) {
  23. return true;
  24. }
  25. std::string confPath = this->confPath(outDir);
  26. if (!sys::fileExists(confPath)) {
  27. return true;
  28. }
  29. BXVariables cachedVariables;
  30. try {
  31. std::ifstream f = sys::ifstream(confPath);
  32. BXParser parser(f, BXParser::FLAG_NONE);
  33. parser.parse(cachedVariables);
  34. } catch (BXParseError &err) {
  35. logger::log(confPath + ": " + err.what());
  36. return true;
  37. }
  38. // We can trust the cached "deps" value here, because we know
  39. // the object file hasn't actually changed.
  40. auto depsIt = cachedVariables.find("deps");
  41. if (depsIt == cachedVariables.end()) {
  42. logger::log(confPath + ": Missing 'deps' field");
  43. return true;
  44. }
  45. const std::vector<std::string> &deps = depsIt->second;
  46. for (const auto &dep: deps) {
  47. if (!sys::fileExists(dep)) {
  48. return true;
  49. }
  50. sys::FileInfo depInfo = sys::fileInfo(dep);
  51. if (objInfo.isOlderThan(depInfo)) {
  52. return true;
  53. }
  54. }
  55. // Maybe the build command has changed?
  56. auto commandIt = cachedVariables.find("command");
  57. if (commandIt == cachedVariables.end()) {
  58. logger::log(confPath + ": Missing 'command' field");
  59. return true;
  60. }
  61. if (compileCommand(outDir) != commandIt->second) {
  62. return true;
  63. }
  64. return false;
  65. }
  66. void CompileStep::doBuild(const std::string &outDir) {
  67. bool verboseCommand = global::verbose >= 1;
  68. if (!verboseCommand) {
  69. logger::log("Compile " + path_);
  70. }
  71. std::string objPath = toolchain::objectFilePath(path_, outDir);
  72. std::string dirPath = sys::dirname(objPath);
  73. std::vector<std::string> command = compileCommand(outDir);
  74. BXVariables newCachedVars = {
  75. { "deps", toolchain::getDependencies(flags(), type_, path_) },
  76. { "command", command},
  77. };
  78. sys::mkdirp(dirPath);
  79. std::ofstream f = sys::ofstream(confPath(outDir));
  80. BXWriter writer(f);
  81. writer.write(newCachedVars);
  82. sys::execute(command, nullptr, verboseCommand);
  83. }
  84. void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) {
  85. w.write(sys::cwd(), path_, compileCommand(outDir));
  86. }
  87. std::vector<std::string> CompileStep::getPublicLDFlags(const std::string &outDir) {
  88. BXVariables &vars = variables();
  89. std::vector<std::string> flags;
  90. toolchain::getLDFlags(vars, flags);
  91. return flags;
  92. }
  93. std::vector<std::string> CompileStep::getPublicLDLibs(const std::string &outDir) {
  94. BXVariables &vars = variables();
  95. std::vector<std::string> libs;
  96. toolchain::getLDLibs(vars, libs);
  97. return libs;
  98. }
  99. std::vector<std::string> CompileStep::getPublicObjects(const std::string &outDir) {
  100. return std::vector<std::string>{ toolchain::objectFilePath(path_, outDir) };
  101. }
  102. BXVariables &CompileStep::variables() {
  103. if (hasVariables_) {
  104. return variables_;
  105. }
  106. std::ifstream f = sys::ifstream(path_);
  107. BXParser parser(f, BXParser::FLAG_ONE_LINE);
  108. while (f.good()) {
  109. if (startsWith(parser, "//#bx")) {
  110. parser.parse(variables_);
  111. } else {
  112. while (f.good() && parser.get() != '\n');
  113. }
  114. }
  115. hasVariables_ = true;
  116. return variables_;
  117. }
  118. std::vector<std::string> &CompileStep::flags() {
  119. if (hasFlags_) {
  120. return flags_;
  121. }
  122. BXVariables &vars = variables();
  123. toolchain::getFlags(vars, type_, flags_);
  124. hasFlags_ = true;
  125. return flags_;
  126. }
  127. std::vector<std::string> &CompileStep::compileCommand(const std::string &outDir) {
  128. if (hasCompileCommand_) {
  129. return compileCommand_;
  130. }
  131. compileCommand_ = toolchain::getCompileCommand(flags(), type_, path_, outDir);
  132. hasCompileCommand_ = true;
  133. return compileCommand_;
  134. }