cmQtAutoGenerator.cxx 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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 "cmQtAutoGen.h"
  5. #include "cmsys/FStream.hxx"
  6. #include "cmAlgorithms.h"
  7. #include "cmGlobalGenerator.h"
  8. #include "cmMakefile.h"
  9. #include "cmState.h"
  10. #include "cmStateDirectory.h"
  11. #include "cmStateSnapshot.h"
  12. #include "cmSystemTools.h"
  13. #include "cmake.h"
  14. #include <memory>
  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 (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
  23. SetVerbosity(static_cast<unsigned int>(iVerbose));
  24. } else {
  25. // Non numeric verbosity
  26. SetVerbose(cmSystemTools::IsOn(verbose));
  27. }
  28. }
  29. }
  30. {
  31. std::string colorEnv;
  32. cmSystemTools::GetEnv("COLOR", colorEnv);
  33. if (!colorEnv.empty()) {
  34. SetColorOutput(cmSystemTools::IsOn(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 (cmSystemTools::StringToULong(value.c_str(), &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(std::string const& title)
  55. {
  56. std::string head = title;
  57. head += '\n';
  58. head.append(head.size() - 1, '-');
  59. head += '\n';
  60. return head;
  61. }
  62. void cmQtAutoGenerator::Logger::Info(GenT genType,
  63. std::string const& message) const
  64. {
  65. std::string msg = GeneratorName(genType);
  66. msg += ": ";
  67. msg += message;
  68. if (msg.back() != '\n') {
  69. msg.push_back('\n');
  70. }
  71. {
  72. std::lock_guard<std::mutex> lock(Mutex_);
  73. cmSystemTools::Stdout(msg);
  74. }
  75. }
  76. void cmQtAutoGenerator::Logger::Warning(GenT genType,
  77. std::string const& message) const
  78. {
  79. std::string msg;
  80. if (message.find('\n') == std::string::npos) {
  81. // Single line message
  82. msg += GeneratorName(genType);
  83. msg += " warning: ";
  84. } else {
  85. // Multi line message
  86. msg += HeadLine(GeneratorName(genType) + " warning");
  87. }
  88. // Message
  89. msg += message;
  90. if (msg.back() != '\n') {
  91. msg.push_back('\n');
  92. }
  93. msg.push_back('\n');
  94. {
  95. std::lock_guard<std::mutex> lock(Mutex_);
  96. cmSystemTools::Stdout(msg);
  97. }
  98. }
  99. void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
  100. std::string const& filename,
  101. std::string const& message) const
  102. {
  103. std::string msg = " ";
  104. msg += Quoted(filename);
  105. msg.push_back('\n');
  106. // Message
  107. msg += message;
  108. Warning(genType, msg);
  109. }
  110. void cmQtAutoGenerator::Logger::Error(GenT genType,
  111. std::string const& message) const
  112. {
  113. std::string msg;
  114. msg += HeadLine(GeneratorName(genType) + " error");
  115. // Message
  116. msg += message;
  117. if (msg.back() != '\n') {
  118. msg.push_back('\n');
  119. }
  120. msg.push_back('\n');
  121. {
  122. std::lock_guard<std::mutex> lock(Mutex_);
  123. cmSystemTools::Stderr(msg);
  124. }
  125. }
  126. void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
  127. std::string const& filename,
  128. std::string const& message) const
  129. {
  130. std::string emsg = " ";
  131. emsg += Quoted(filename);
  132. emsg += '\n';
  133. // Message
  134. emsg += message;
  135. Error(genType, emsg);
  136. }
  137. void cmQtAutoGenerator::Logger::ErrorCommand(
  138. GenT genType, std::string const& message,
  139. std::vector<std::string> const& command, std::string const& output) const
  140. {
  141. std::string msg;
  142. msg.push_back('\n');
  143. msg += HeadLine(GeneratorName(genType) + " subprocess error");
  144. msg += message;
  145. if (msg.back() != '\n') {
  146. msg.push_back('\n');
  147. }
  148. msg.push_back('\n');
  149. msg += HeadLine("Command");
  150. msg += QuotedCommand(command);
  151. if (msg.back() != '\n') {
  152. msg.push_back('\n');
  153. }
  154. msg.push_back('\n');
  155. msg += HeadLine("Output");
  156. msg += output;
  157. if (msg.back() != '\n') {
  158. msg.push_back('\n');
  159. }
  160. msg.push_back('\n');
  161. {
  162. std::lock_guard<std::mutex> lock(Mutex_);
  163. cmSystemTools::Stderr(msg);
  164. }
  165. }
  166. bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
  167. {
  168. bool success = true;
  169. std::string const dirName = cmSystemTools::GetFilenamePath(filename);
  170. if (!dirName.empty()) {
  171. success = cmSystemTools::MakeDirectory(dirName);
  172. }
  173. return success;
  174. }
  175. bool cmQtAutoGenerator::FileRead(std::string& content,
  176. std::string const& filename,
  177. std::string* error)
  178. {
  179. content.clear();
  180. if (!cmSystemTools::FileExists(filename, true)) {
  181. if (error != nullptr) {
  182. *error = "Not a file.";
  183. }
  184. return false;
  185. }
  186. unsigned long const length = cmSystemTools::FileLength(filename);
  187. cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
  188. // Use lambda to save destructor calls of ifs
  189. return [&ifs, length, &content, error]() -> bool {
  190. if (!ifs) {
  191. if (error != nullptr) {
  192. *error = "Opening the file for reading failed.";
  193. }
  194. return false;
  195. }
  196. content.reserve(length);
  197. typedef std::istreambuf_iterator<char> IsIt;
  198. content.assign(IsIt{ ifs }, IsIt{});
  199. if (!ifs) {
  200. content.clear();
  201. if (error != nullptr) {
  202. *error = "Reading from the file failed.";
  203. }
  204. return false;
  205. }
  206. return true;
  207. }();
  208. }
  209. bool cmQtAutoGenerator::FileWrite(std::string const& filename,
  210. std::string const& content,
  211. std::string* error)
  212. {
  213. // Make sure the parent directory exists
  214. if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
  215. if (error != nullptr) {
  216. *error = "Could not create parent directory.";
  217. }
  218. return false;
  219. }
  220. cmsys::ofstream ofs;
  221. ofs.open(filename.c_str(),
  222. (std::ios::out | std::ios::binary | std::ios::trunc));
  223. // Use lambda to save destructor calls of ofs
  224. return [&ofs, &content, error]() -> bool {
  225. if (!ofs) {
  226. if (error != nullptr) {
  227. *error = "Opening file for writing failed.";
  228. }
  229. return false;
  230. }
  231. ofs << content;
  232. if (!ofs.good()) {
  233. if (error != nullptr) {
  234. *error = "File writing failed.";
  235. }
  236. return false;
  237. }
  238. return true;
  239. }();
  240. }
  241. bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
  242. std::string const& content)
  243. {
  244. bool differs = true;
  245. std::string oldContents;
  246. if (FileRead(oldContents, filename) && (oldContents == content)) {
  247. differs = false;
  248. }
  249. return differs;
  250. }
  251. cmQtAutoGenerator::cmQtAutoGenerator() = default;
  252. cmQtAutoGenerator::~cmQtAutoGenerator() = default;
  253. bool cmQtAutoGenerator::Run(std::string const& infoFile,
  254. std::string const& config)
  255. {
  256. // Info settings
  257. InfoFile_ = infoFile;
  258. cmSystemTools::ConvertToUnixSlashes(InfoFile_);
  259. if (!InfoFileTime_.Load(InfoFile_)) {
  260. std::string msg = "AutoGen: The info file ";
  261. msg += Quoted(InfoFile_);
  262. msg += " is not readable\n";
  263. cmSystemTools::Stderr(msg);
  264. return false;
  265. }
  266. InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
  267. InfoConfig_ = config;
  268. bool success = false;
  269. {
  270. cmake cm(cmake::RoleScript, cmState::Unknown);
  271. cm.SetHomeOutputDirectory(InfoDir());
  272. cm.SetHomeDirectory(InfoDir());
  273. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  274. cmGlobalGenerator gg(&cm);
  275. cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
  276. snapshot.GetDirectory().SetCurrentBinary(InfoDir());
  277. snapshot.GetDirectory().SetCurrentSource(InfoDir());
  278. auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
  279. // The OLD/WARN behavior for policy CMP0053 caused a speed regression.
  280. // https://gitlab.kitware.com/cmake/cmake/issues/17570
  281. makefile->SetPolicyVersion("3.9", std::string());
  282. gg.SetCurrentMakefile(makefile.get());
  283. success = this->Init(makefile.get());
  284. }
  285. if (success) {
  286. success = this->Process();
  287. }
  288. return success;
  289. }
  290. std::string cmQtAutoGenerator::SettingsFind(std::string const& content,
  291. const char* key)
  292. {
  293. std::string prefix(key);
  294. prefix += ':';
  295. std::string::size_type pos = content.find(prefix);
  296. if (pos != std::string::npos) {
  297. pos += prefix.size();
  298. if (pos < content.size()) {
  299. std::string::size_type posE = content.find('\n', pos);
  300. if ((posE != std::string::npos) && (posE != pos)) {
  301. return content.substr(pos, posE - pos);
  302. }
  303. }
  304. }
  305. return std::string();
  306. }