cmQtAutoGenerator.cxx 8.7 KB

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