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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. bufio::IFStream f(confPath);
  32. BXParser parser(f);
  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. std::string objPath = toolchain::objectFilePath(path_, outDir);
  68. std::string dirPath = sys::dirname(objPath);
  69. std::vector<std::string> command = compileCommand(outDir);
  70. BXVariables newCachedVars = {
  71. { "deps", toolchain::getDependencies(flags(), type_, path_) },
  72. { "command", command},
  73. };
  74. sys::mkdirp(dirPath);
  75. bufio::OFStream f(confPath(outDir));
  76. BXWriter writer(f);
  77. writer.write(newCachedVars);
  78. sys::ProcConf conf;
  79. conf.print = true;
  80. switch (type_) {
  81. case toolchain::FileType::C:
  82. conf.prefix = "(CC)";
  83. break;
  84. case toolchain::FileType::CXX:
  85. conf.prefix = "(CXX)";
  86. break;
  87. }
  88. sys::execute(command, conf);
  89. }
  90. void CompileStep::doWriteCompDB(const std::string &outDir, compdb::Writer &w) {
  91. w.write(sys::cwd(), path_, compileCommand(outDir));
  92. }
  93. std::vector<std::string> CompileStep::getPublicLDFlags(const std::string &outDir) {
  94. BXVariables &vars = variables();
  95. std::vector<std::string> flags;
  96. toolchain::getLDFlags(vars, flags);
  97. return flags;
  98. }
  99. std::vector<std::string> CompileStep::getPublicLDLibs(const std::string &outDir) {
  100. BXVariables &vars = variables();
  101. std::vector<std::string> libs;
  102. toolchain::getLDLibs(vars, libs);
  103. return libs;
  104. }
  105. std::vector<std::string> CompileStep::getPublicObjects(const std::string &outDir) {
  106. return std::vector<std::string>{ toolchain::objectFilePath(path_, outDir) };
  107. }
  108. BXVariables &CompileStep::variables() {
  109. if (hasVariables_) {
  110. return variables_;
  111. }
  112. bufio::IFStream f(path_);
  113. BXParser parser(f);
  114. while (parser.peek() != EOF) {
  115. if (startsWith(parser, "//#bx")) {
  116. parser.parseLine(variables_);
  117. } else {
  118. while (parser.peek() != EOF && parser.get() != '\n');
  119. }
  120. }
  121. hasVariables_ = true;
  122. return variables_;
  123. }
  124. std::vector<std::string> &CompileStep::flags() {
  125. if (hasFlags_) {
  126. return flags_;
  127. }
  128. BXVariables &vars = variables();
  129. toolchain::getFlags(vars, type_, flags_);
  130. hasFlags_ = true;
  131. return flags_;
  132. }
  133. std::vector<std::string> &CompileStep::compileCommand(const std::string &outDir) {
  134. if (hasCompileCommand_) {
  135. return compileCommand_;
  136. }
  137. compileCommand_ = toolchain::getCompileCommand(flags(), type_, path_, outDir);
  138. hasCompileCommand_ = true;
  139. return compileCommand_;
  140. }