cmQtAutoGenerator.cxx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmQtAutoGenerator.h"
  4. #include <cm/memory>
  5. #include "cmsys/FStream.hxx"
  6. #include "cmGlobalGenerator.h"
  7. #include "cmMakefile.h"
  8. #include "cmQtAutoGen.h"
  9. #include "cmState.h"
  10. #include "cmStateDirectory.h"
  11. #include "cmStateSnapshot.h"
  12. #include "cmStringAlgorithms.h"
  13. #include "cmSystemTools.h"
  14. #include "cmake.h"
  15. cmQtAutoGenerator::Logger::Logger()
  16. {
  17. // Initialize logger
  18. {
  19. std::string verbose;
  20. if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
  21. unsigned long iVerbose = 0;
  22. if (cmStrToULong(verbose, &iVerbose)) {
  23. SetVerbosity(static_cast<unsigned int>(iVerbose));
  24. } else {
  25. // Non numeric verbosity
  26. SetVerbose(cmIsOn(verbose));
  27. }
  28. }
  29. }
  30. {
  31. std::string colorEnv;
  32. cmSystemTools::GetEnv("COLOR", colorEnv);
  33. if (!colorEnv.empty()) {
  34. SetColorOutput(cmIsOn(colorEnv));
  35. } else {
  36. SetColorOutput(true);
  37. }
  38. }
  39. }
  40. cmQtAutoGenerator::Logger::~Logger() = default;
  41. void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
  42. {
  43. unsigned long verbosity = 0;
  44. if (cmStrToULong(value, &verbosity)) {
  45. if (this->Verbosity_ < verbosity) {
  46. this->Verbosity_ = static_cast<unsigned int>(verbosity);
  47. }
  48. }
  49. }
  50. void cmQtAutoGenerator::Logger::SetColorOutput(bool value)
  51. {
  52. ColorOutput_ = value;
  53. }
  54. std::string cmQtAutoGenerator::Logger::HeadLine(cm::string_view title)
  55. {
  56. return cmStrCat(title, '\n', std::string(title.size(), '-'), '\n');
  57. }
  58. void cmQtAutoGenerator::Logger::Info(GenT genType,
  59. cm::string_view message) const
  60. {
  61. std::string msg = cmStrCat(GeneratorName(genType), ": ", message,
  62. cmHasSuffix(message, '\n') ? "" : "\n");
  63. {
  64. std::lock_guard<std::mutex> lock(Mutex_);
  65. cmSystemTools::Stdout(msg);
  66. }
  67. }
  68. void cmQtAutoGenerator::Logger::Warning(GenT genType,
  69. cm::string_view message) const
  70. {
  71. std::string msg;
  72. if (message.find('\n') == std::string::npos) {
  73. // Single line message
  74. msg = cmStrCat(GeneratorName(genType), " warning: ", message,
  75. cmHasSuffix(message, '\n') ? "\n" : "\n\n");
  76. } else {
  77. // Multi line message
  78. msg = cmStrCat(HeadLine(cmStrCat(GeneratorName(genType), " warning")),
  79. message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
  80. }
  81. {
  82. std::lock_guard<std::mutex> lock(Mutex_);
  83. cmSystemTools::Stdout(msg);
  84. }
  85. }
  86. void cmQtAutoGenerator::Logger::Error(GenT genType,
  87. cm::string_view message) const
  88. {
  89. std::string msg =
  90. cmStrCat('\n', HeadLine(cmStrCat(GeneratorName(genType), " error")),
  91. message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
  92. {
  93. std::lock_guard<std::mutex> lock(Mutex_);
  94. cmSystemTools::Stderr(msg);
  95. }
  96. }
  97. void cmQtAutoGenerator::Logger::ErrorCommand(
  98. GenT genType, cm::string_view message,
  99. std::vector<std::string> const& command, std::string const& output) const
  100. {
  101. std::string msg = cmStrCat(
  102. '\n', HeadLine(cmStrCat(GeneratorName(genType), " subprocess error")),
  103. message, cmHasSuffix(message, '\n') ? "\n" : "\n\n");
  104. msg += cmStrCat(HeadLine("Command"), QuotedCommand(command), "\n\n");
  105. msg += cmStrCat(HeadLine("Output"), output,
  106. cmHasSuffix(output, '\n') ? "\n" : "\n\n");
  107. {
  108. std::lock_guard<std::mutex> lock(Mutex_);
  109. cmSystemTools::Stderr(msg);
  110. }
  111. }
  112. bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
  113. {
  114. bool success = true;
  115. std::string const dirName = cmSystemTools::GetFilenamePath(filename);
  116. if (!dirName.empty()) {
  117. success = cmSystemTools::MakeDirectory(dirName);
  118. }
  119. return success;
  120. }
  121. bool cmQtAutoGenerator::FileRead(std::string& content,
  122. std::string const& filename,
  123. std::string* error)
  124. {
  125. content.clear();
  126. if (!cmSystemTools::FileExists(filename, true)) {
  127. if (error != nullptr) {
  128. *error = "Not a file.";
  129. }
  130. return false;
  131. }
  132. unsigned long const length = cmSystemTools::FileLength(filename);
  133. cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
  134. // Use lambda to save destructor calls of ifs
  135. return [&ifs, length, &content, error]() -> bool {
  136. if (!ifs) {
  137. if (error != nullptr) {
  138. *error = "Opening the file for reading failed.";
  139. }
  140. return false;
  141. }
  142. content.reserve(length);
  143. using IsIt = std::istreambuf_iterator<char>;
  144. content.assign(IsIt{ ifs }, IsIt{});
  145. if (!ifs) {
  146. content.clear();
  147. if (error != nullptr) {
  148. *error = "Reading from the file failed.";
  149. }
  150. return false;
  151. }
  152. return true;
  153. }();
  154. }
  155. bool cmQtAutoGenerator::FileWrite(std::string const& filename,
  156. std::string const& content,
  157. std::string* error)
  158. {
  159. // Make sure the parent directory exists
  160. if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
  161. if (error != nullptr) {
  162. *error = "Could not create parent directory.";
  163. }
  164. return false;
  165. }
  166. cmsys::ofstream ofs;
  167. ofs.open(filename.c_str(),
  168. (std::ios::out | std::ios::binary | std::ios::trunc));
  169. // Use lambda to save destructor calls of ofs
  170. return [&ofs, &content, error]() -> bool {
  171. if (!ofs) {
  172. if (error != nullptr) {
  173. *error = "Opening file for writing failed.";
  174. }
  175. return false;
  176. }
  177. ofs << content;
  178. if (!ofs.good()) {
  179. if (error != nullptr) {
  180. *error = "File writing failed.";
  181. }
  182. return false;
  183. }
  184. return true;
  185. }();
  186. }
  187. bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
  188. std::string const& content)
  189. {
  190. bool differs = true;
  191. std::string oldContents;
  192. if (FileRead(oldContents, filename) && (oldContents == content)) {
  193. differs = false;
  194. }
  195. return differs;
  196. }
  197. cmQtAutoGenerator::cmQtAutoGenerator() = default;
  198. cmQtAutoGenerator::~cmQtAutoGenerator() = default;
  199. bool cmQtAutoGenerator::Run(std::string const& infoFile,
  200. std::string const& config)
  201. {
  202. // Info settings
  203. InfoFile_ = infoFile;
  204. cmSystemTools::ConvertToUnixSlashes(InfoFile_);
  205. if (!InfoFileTime_.Load(InfoFile_)) {
  206. cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ",
  207. Quoted(InfoFile_), " is not readable\n"));
  208. return false;
  209. }
  210. InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
  211. InfoConfig_ = config;
  212. bool success = false;
  213. {
  214. cmake cm(cmake::RoleScript, cmState::Unknown);
  215. cm.SetHomeOutputDirectory(InfoDir());
  216. cm.SetHomeDirectory(InfoDir());
  217. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  218. cmGlobalGenerator gg(&cm);
  219. cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
  220. snapshot.GetDirectory().SetCurrentBinary(InfoDir());
  221. snapshot.GetDirectory().SetCurrentSource(InfoDir());
  222. auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
  223. // The OLD/WARN behavior for policy CMP0053 caused a speed regression.
  224. // https://gitlab.kitware.com/cmake/cmake/issues/17570
  225. makefile->SetPolicyVersion("3.9", std::string());
  226. gg.SetCurrentMakefile(makefile.get());
  227. success = this->Init(makefile.get());
  228. }
  229. if (success) {
  230. success = this->Process();
  231. }
  232. return success;
  233. }
  234. std::string cmQtAutoGenerator::SettingsFind(std::string const& content,
  235. const char* key)
  236. {
  237. std::string prefix = cmStrCat(key, ':');
  238. std::string::size_type pos = content.find(prefix);
  239. if (pos != std::string::npos) {
  240. pos += prefix.size();
  241. if (pos < content.size()) {
  242. std::string::size_type posE = content.find('\n', pos);
  243. if ((posE != std::string::npos) && (posE != pos)) {
  244. return content.substr(pos, posE - pos);
  245. }
  246. }
  247. }
  248. return std::string();
  249. }
  250. std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const
  251. {
  252. std::string res;
  253. if (cmHasPrefix(path, ProjectDirs().Source)) {
  254. res = cmStrCat("SRC:", path.substr(ProjectDirs().Source.size()));
  255. } else if (cmHasPrefix(path, ProjectDirs().Binary)) {
  256. res = cmStrCat("BIN:", path.substr(ProjectDirs().Binary.size()));
  257. } else {
  258. res = std::string(path);
  259. }
  260. return cmQtAutoGen::Quoted(res);
  261. }