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.

SourceFile.cc 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "SourceFile.h"
  2. #include <iostream>
  3. #include <fstream>
  4. #include <sstream>
  5. #include <string.h>
  6. #include "toolchain.h"
  7. #include "logger.h"
  8. #include "globals.h"
  9. static bool startsWith(BBParser &parser, const char *str) {
  10. for (size_t i = 0; str[i] != '\0'; ++i) {
  11. if (parser.peek() != str[i])
  12. return false;
  13. parser.skip();
  14. }
  15. return true;
  16. }
  17. SourceFile::FileType SourceFile::fileTypeFrom(const std::string &name) {
  18. size_t idx = name.find_last_of('.');
  19. if (idx >= std::string::npos) {
  20. return FileType::UNKNOWN;
  21. }
  22. char ext[16] = { 0 };
  23. strncpy(ext, name.c_str() + idx, sizeof(ext) - 1);
  24. if (strcmp(ext, ".c") == 0) {
  25. return FileType::C;
  26. } else if (
  27. (strcmp(ext, ".C") == 0) ||
  28. (strcmp(ext, ".cc") == 0) ||
  29. (strcmp(ext, ".cpp") == 0) ||
  30. (strcmp(ext, ".cxx") == 0)) {
  31. return FileType::CXX;
  32. }
  33. return FileType::UNKNOWN;
  34. }
  35. SourceFile::SourceFile(
  36. std::string dir, std::string name,
  37. FileType type, BBParser::Variables vars):
  38. dir_(std::move(dir)), name_(std::move(name)),
  39. type_(type), vars_(std::move(vars)) {
  40. std::ifstream file(dir_ + "/" + name_);
  41. BBParser parser(file, BBParser::FLAG_ONE_LINE);
  42. while (file.good()) {
  43. if (startsWith(parser, "//#bb")) {
  44. parser.parse(vars_);
  45. } else {
  46. while (file.good() && parser.get() != '\n');
  47. }
  48. }
  49. }
  50. std::string SourceFile::objectPath(const std::string &outDir) const {
  51. return toolchain::objectFilePath(dir(), name(), outDir);
  52. }
  53. const std::vector<std::string> *SourceFile::variable(const std::string &name) const {
  54. auto it = vars_.find(name);
  55. if (it == vars_.end()) {
  56. return nullptr;
  57. }
  58. return &it->second;
  59. }
  60. const std::vector<std::string> &SourceFile::compileFlags() const {
  61. if (hasCompileFlags_) {
  62. return compileFlags_;
  63. }
  64. const std::vector<std::string> *pkgs = variable("pkgs");
  65. if (pkgs != nullptr) {
  66. toolchain::getPkgConfigFlags(*pkgs, compileFlags_);
  67. }
  68. const std::vector<std::string> *cflags = nullptr;
  69. switch (type_) {
  70. case SourceFile::FileType::C:
  71. cflags = variable("cflags");
  72. break;
  73. case SourceFile::FileType::CXX:
  74. cflags = variable("cxxflags");
  75. break;
  76. case SourceFile::FileType::UNKNOWN:
  77. break;
  78. }
  79. if (cflags != nullptr) {
  80. for (const std::string &flag: *cflags) {
  81. compileFlags_.push_back(flag);
  82. }
  83. }
  84. hasCompileFlags_ = true;
  85. return compileFlags_;
  86. }
  87. std::vector<std::string> SourceFile::ldFlags() const {
  88. std::vector<std::string> ldFlags;
  89. const std::vector<std::string> *flags = variable("ldflags");
  90. if (flags != nullptr) {
  91. for (const std::string &flag: *flags) {
  92. ldFlags.push_back(std::move(flag));
  93. }
  94. }
  95. return ldFlags;
  96. }
  97. std::vector<std::string> SourceFile::ldLibs() const {
  98. std::vector<std::string> ldLibs;
  99. const std::vector<std::string> *pkgs = variable("pkgs");
  100. if (pkgs != nullptr) {
  101. toolchain::getPkgConfigLDLibs(*pkgs, ldLibs);
  102. }
  103. const std::vector<std::string> *libs = variable("ldlibs");
  104. if (libs != nullptr) {
  105. for (const std::string &flag: *libs) {
  106. ldLibs.push_back(std::move(flag));
  107. }
  108. }
  109. return ldLibs;
  110. }
  111. std::vector<std::string> SourceFile::dependencies() const {
  112. std::vector<std::string> deps;
  113. toolchain::getDependencies(compileFlags(), type_, dir_, name_, deps);
  114. return deps;
  115. }
  116. bool SourceFile::needsRecompile(const std::string &outDir) const {
  117. std::string outPath = objectPath(outDir);
  118. if (!sys::fileExists(outPath)) {
  119. return true;
  120. }
  121. sys::FileInfo outInfo = sys::fileInfo(outPath);
  122. std::vector<std::string> deps = dependencies();
  123. for (std::string &dep: deps) {
  124. sys::FileInfo depInfo = sys::fileInfo(dep);
  125. if (depInfo.mTimeSec > outInfo.mTimeSec || (
  126. depInfo.mTimeSec == outInfo.mTimeSec &&
  127. depInfo.mTimeNsec > outInfo.mTimeNsec)) {
  128. return true;
  129. }
  130. }
  131. return false;
  132. }
  133. void SourceFile::compile(const std::string &outDir) const {
  134. if (global::verbose == 0) {
  135. logger::log("Compile " + objectPath(outDir));
  136. }
  137. toolchain::compile(compileFlags(), type_, dir_, name_, outDir);
  138. // Nothing will need compile flags after it's compiled, so no reason to
  139. // keep it around in memory
  140. compileFlags_.clear();
  141. hasCompileFlags_ = false;
  142. }
  143. std::vector<std::string> SourceFile::compileCommand(const std::string &outDir) const {
  144. auto res = toolchain::getCompileCommand(compileFlags(), type_, dir_, name_, outDir);
  145. // Nothing will need compile flags after this, so no reason to
  146. // keep it around in memory
  147. compileFlags_.clear();
  148. hasCompileFlags_ = false;
  149. return res;
  150. }