cmQtAutoGenerator.cxx 8.5 KB

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