cmQtAutoGenerator.cxx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  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 <algorithm>
  15. #include <sstream>
  16. #include <utility>
  17. // -- Class methods
  18. void cmQtAutoGenerator::Logger::RaiseVerbosity(std::string const& value)
  19. {
  20. unsigned long verbosity = 0;
  21. if (cmSystemTools::StringToULong(value.c_str(), &verbosity)) {
  22. if (this->Verbosity_ < verbosity) {
  23. this->Verbosity_ = static_cast<unsigned int>(verbosity);
  24. }
  25. }
  26. }
  27. void cmQtAutoGenerator::Logger::SetColorOutput(bool value)
  28. {
  29. ColorOutput_ = value;
  30. }
  31. std::string cmQtAutoGenerator::Logger::HeadLine(std::string const& title)
  32. {
  33. std::string head = title;
  34. head += '\n';
  35. head.append(head.size() - 1, '-');
  36. head += '\n';
  37. return head;
  38. }
  39. void cmQtAutoGenerator::Logger::Info(GenT genType, std::string const& message)
  40. {
  41. std::string msg = GeneratorName(genType);
  42. msg += ": ";
  43. msg += message;
  44. if (msg.back() != '\n') {
  45. msg.push_back('\n');
  46. }
  47. {
  48. std::lock_guard<std::mutex> lock(Mutex_);
  49. cmSystemTools::Stdout(msg);
  50. }
  51. }
  52. void cmQtAutoGenerator::Logger::Warning(GenT genType,
  53. std::string const& message)
  54. {
  55. std::string msg;
  56. if (message.find('\n') == std::string::npos) {
  57. // Single line message
  58. msg += GeneratorName(genType);
  59. msg += " warning: ";
  60. } else {
  61. // Multi line message
  62. msg += HeadLine(GeneratorName(genType) + " warning");
  63. }
  64. // Message
  65. msg += message;
  66. if (msg.back() != '\n') {
  67. msg.push_back('\n');
  68. }
  69. msg.push_back('\n');
  70. {
  71. std::lock_guard<std::mutex> lock(Mutex_);
  72. cmSystemTools::Stdout(msg);
  73. }
  74. }
  75. void cmQtAutoGenerator::Logger::WarningFile(GenT genType,
  76. std::string const& filename,
  77. std::string const& message)
  78. {
  79. std::string msg = " ";
  80. msg += Quoted(filename);
  81. msg.push_back('\n');
  82. // Message
  83. msg += message;
  84. Warning(genType, msg);
  85. }
  86. void cmQtAutoGenerator::Logger::Error(GenT genType, std::string const& message)
  87. {
  88. std::string msg;
  89. msg += HeadLine(GeneratorName(genType) + " error");
  90. // Message
  91. msg += message;
  92. if (msg.back() != '\n') {
  93. msg.push_back('\n');
  94. }
  95. msg.push_back('\n');
  96. {
  97. std::lock_guard<std::mutex> lock(Mutex_);
  98. cmSystemTools::Stderr(msg);
  99. }
  100. }
  101. void cmQtAutoGenerator::Logger::ErrorFile(GenT genType,
  102. std::string const& filename,
  103. std::string const& message)
  104. {
  105. std::string emsg = " ";
  106. emsg += Quoted(filename);
  107. emsg += '\n';
  108. // Message
  109. emsg += message;
  110. Error(genType, emsg);
  111. }
  112. void cmQtAutoGenerator::Logger::ErrorCommand(
  113. GenT genType, std::string const& message,
  114. std::vector<std::string> const& command, std::string const& output)
  115. {
  116. std::string msg;
  117. msg.push_back('\n');
  118. msg += HeadLine(GeneratorName(genType) + " subprocess error");
  119. msg += message;
  120. if (msg.back() != '\n') {
  121. msg.push_back('\n');
  122. }
  123. msg.push_back('\n');
  124. msg += HeadLine("Command");
  125. msg += QuotedCommand(command);
  126. if (msg.back() != '\n') {
  127. msg.push_back('\n');
  128. }
  129. msg.push_back('\n');
  130. msg += HeadLine("Output");
  131. msg += output;
  132. if (msg.back() != '\n') {
  133. msg.push_back('\n');
  134. }
  135. msg.push_back('\n');
  136. {
  137. std::lock_guard<std::mutex> lock(Mutex_);
  138. cmSystemTools::Stderr(msg);
  139. }
  140. }
  141. bool cmQtAutoGenerator::MakeParentDirectory(std::string const& filename)
  142. {
  143. bool success = true;
  144. std::string const dirName = cmSystemTools::GetFilenamePath(filename);
  145. if (!dirName.empty()) {
  146. success = cmSystemTools::MakeDirectory(dirName);
  147. }
  148. return success;
  149. }
  150. bool cmQtAutoGenerator::FileRead(std::string& content,
  151. std::string const& filename,
  152. std::string* error)
  153. {
  154. content.clear();
  155. if (!cmSystemTools::FileExists(filename, true)) {
  156. if (error != nullptr) {
  157. error->append("Not a file.");
  158. }
  159. return false;
  160. }
  161. unsigned long const length = cmSystemTools::FileLength(filename);
  162. cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
  163. // Use lambda to save destructor calls of ifs
  164. return [&ifs, length, &content, error]() -> bool {
  165. if (!ifs) {
  166. if (error != nullptr) {
  167. error->append("Opening the file for reading failed.");
  168. }
  169. return false;
  170. }
  171. content.reserve(length);
  172. typedef std::istreambuf_iterator<char> IsIt;
  173. content.assign(IsIt{ ifs }, IsIt{});
  174. if (!ifs) {
  175. content.clear();
  176. if (error != nullptr) {
  177. error->append("Reading from the file failed.");
  178. }
  179. return false;
  180. }
  181. return true;
  182. }();
  183. }
  184. bool cmQtAutoGenerator::FileWrite(std::string const& filename,
  185. std::string const& content,
  186. std::string* error)
  187. {
  188. // Make sure the parent directory exists
  189. if (!cmQtAutoGenerator::MakeParentDirectory(filename)) {
  190. if (error != nullptr) {
  191. error->assign("Could not create parent directory.");
  192. }
  193. return false;
  194. }
  195. cmsys::ofstream ofs;
  196. ofs.open(filename.c_str(),
  197. (std::ios::out | std::ios::binary | std::ios::trunc));
  198. // Use lambda to save destructor calls of ofs
  199. return [&ofs, &content, error]() -> bool {
  200. if (!ofs) {
  201. if (error != nullptr) {
  202. error->assign("Opening file for writing failed.");
  203. }
  204. return false;
  205. }
  206. ofs << content;
  207. if (!ofs.good()) {
  208. if (error != nullptr) {
  209. error->assign("File writing failed.");
  210. }
  211. return false;
  212. }
  213. return true;
  214. }();
  215. }
  216. std::string cmQtAutoGenerator::FileSystem::GetRealPath(
  217. std::string const& filename)
  218. {
  219. std::lock_guard<std::mutex> lock(Mutex_);
  220. return cmSystemTools::GetRealPath(filename);
  221. }
  222. std::string cmQtAutoGenerator::FileSystem::CollapseFullPath(
  223. std::string const& file, std::string const& dir)
  224. {
  225. std::lock_guard<std::mutex> lock(Mutex_);
  226. return cmSystemTools::CollapseFullPath(file, dir);
  227. }
  228. void cmQtAutoGenerator::FileSystem::SplitPath(
  229. const std::string& p, std::vector<std::string>& components,
  230. bool expand_home_dir)
  231. {
  232. std::lock_guard<std::mutex> lock(Mutex_);
  233. cmSystemTools::SplitPath(p, components, expand_home_dir);
  234. }
  235. std::string cmQtAutoGenerator::FileSystem::JoinPath(
  236. const std::vector<std::string>& components)
  237. {
  238. std::lock_guard<std::mutex> lock(Mutex_);
  239. return cmSystemTools::JoinPath(components);
  240. }
  241. std::string cmQtAutoGenerator::FileSystem::JoinPath(
  242. std::vector<std::string>::const_iterator first,
  243. std::vector<std::string>::const_iterator last)
  244. {
  245. std::lock_guard<std::mutex> lock(Mutex_);
  246. return cmSystemTools::JoinPath(first, last);
  247. }
  248. std::string cmQtAutoGenerator::FileSystem::GetFilenameWithoutLastExtension(
  249. const std::string& filename)
  250. {
  251. std::lock_guard<std::mutex> lock(Mutex_);
  252. return cmSystemTools::GetFilenameWithoutLastExtension(filename);
  253. }
  254. std::string cmQtAutoGenerator::FileSystem::SubDirPrefix(
  255. std::string const& filename)
  256. {
  257. std::lock_guard<std::mutex> lock(Mutex_);
  258. return cmQtAutoGen::SubDirPrefix(filename);
  259. }
  260. void cmQtAutoGenerator::FileSystem::setupFilePathChecksum(
  261. std::string const& currentSrcDir, std::string const& currentBinDir,
  262. std::string const& projectSrcDir, std::string const& projectBinDir)
  263. {
  264. std::lock_guard<std::mutex> lock(Mutex_);
  265. FilePathChecksum_.setupParentDirs(currentSrcDir, currentBinDir,
  266. projectSrcDir, projectBinDir);
  267. }
  268. std::string cmQtAutoGenerator::FileSystem::GetFilePathChecksum(
  269. std::string const& filename)
  270. {
  271. std::lock_guard<std::mutex> lock(Mutex_);
  272. return FilePathChecksum_.getPart(filename);
  273. }
  274. bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename)
  275. {
  276. std::lock_guard<std::mutex> lock(Mutex_);
  277. return cmSystemTools::FileExists(filename);
  278. }
  279. bool cmQtAutoGenerator::FileSystem::FileExists(std::string const& filename,
  280. bool isFile)
  281. {
  282. std::lock_guard<std::mutex> lock(Mutex_);
  283. return cmSystemTools::FileExists(filename, isFile);
  284. }
  285. unsigned long cmQtAutoGenerator::FileSystem::FileLength(
  286. std::string const& filename)
  287. {
  288. std::lock_guard<std::mutex> lock(Mutex_);
  289. return cmSystemTools::FileLength(filename);
  290. }
  291. bool cmQtAutoGenerator::FileSystem::FileIsOlderThan(
  292. std::string const& buildFile, std::string const& sourceFile,
  293. std::string* error)
  294. {
  295. bool res(false);
  296. int result = 0;
  297. {
  298. std::lock_guard<std::mutex> lock(Mutex_);
  299. res = cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result);
  300. }
  301. if (res) {
  302. res = (result < 0);
  303. } else {
  304. if (error != nullptr) {
  305. error->append(
  306. "File modification time comparison failed for the files\n ");
  307. error->append(Quoted(buildFile));
  308. error->append("\nand\n ");
  309. error->append(Quoted(sourceFile));
  310. }
  311. }
  312. return res;
  313. }
  314. bool cmQtAutoGenerator::FileSystem::FileRead(std::string& content,
  315. std::string const& filename,
  316. std::string* error)
  317. {
  318. std::lock_guard<std::mutex> lock(Mutex_);
  319. return cmQtAutoGenerator::FileRead(content, filename, error);
  320. }
  321. bool cmQtAutoGenerator::FileSystem::FileRead(GenT genType,
  322. std::string& content,
  323. std::string const& filename)
  324. {
  325. std::string error;
  326. if (!FileRead(content, filename, &error)) {
  327. Log()->ErrorFile(genType, filename, error);
  328. return false;
  329. }
  330. return true;
  331. }
  332. bool cmQtAutoGenerator::FileSystem::FileWrite(std::string const& filename,
  333. std::string const& content,
  334. std::string* error)
  335. {
  336. std::lock_guard<std::mutex> lock(Mutex_);
  337. return cmQtAutoGenerator::FileWrite(filename, content, error);
  338. }
  339. bool cmQtAutoGenerator::FileSystem::FileWrite(GenT genType,
  340. std::string const& filename,
  341. std::string const& content)
  342. {
  343. std::string error;
  344. if (!FileWrite(filename, content, &error)) {
  345. Log()->ErrorFile(genType, filename, error);
  346. return false;
  347. }
  348. return true;
  349. }
  350. bool cmQtAutoGenerator::FileSystem::FileDiffers(std::string const& filename,
  351. std::string const& content)
  352. {
  353. bool differs = true;
  354. {
  355. std::string oldContents;
  356. if (FileRead(oldContents, filename)) {
  357. differs = (oldContents != content);
  358. }
  359. }
  360. return differs;
  361. }
  362. bool cmQtAutoGenerator::FileSystem::FileRemove(std::string const& filename)
  363. {
  364. std::lock_guard<std::mutex> lock(Mutex_);
  365. return cmSystemTools::RemoveFile(filename);
  366. }
  367. bool cmQtAutoGenerator::FileSystem::Touch(std::string const& filename,
  368. bool create)
  369. {
  370. std::lock_guard<std::mutex> lock(Mutex_);
  371. return cmSystemTools::Touch(filename, create);
  372. }
  373. bool cmQtAutoGenerator::FileSystem::MakeDirectory(std::string const& dirname)
  374. {
  375. std::lock_guard<std::mutex> lock(Mutex_);
  376. return cmSystemTools::MakeDirectory(dirname);
  377. }
  378. bool cmQtAutoGenerator::FileSystem::MakeDirectory(GenT genType,
  379. std::string const& dirname)
  380. {
  381. if (!MakeDirectory(dirname)) {
  382. Log()->ErrorFile(genType, dirname, "Could not create directory");
  383. return false;
  384. }
  385. return true;
  386. }
  387. bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
  388. std::string const& filename)
  389. {
  390. std::lock_guard<std::mutex> lock(Mutex_);
  391. return cmQtAutoGenerator::MakeParentDirectory(filename);
  392. }
  393. bool cmQtAutoGenerator::FileSystem::MakeParentDirectory(
  394. GenT genType, std::string const& filename)
  395. {
  396. if (!MakeParentDirectory(filename)) {
  397. Log()->ErrorFile(genType, filename, "Could not create parent directory");
  398. return false;
  399. }
  400. return true;
  401. }
  402. int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::init(uv_loop_t* uv_loop,
  403. ReadOnlyProcessT* process)
  404. {
  405. Process_ = process;
  406. Target_ = nullptr;
  407. return UVPipe_.init(*uv_loop, 0, this);
  408. }
  409. int cmQtAutoGenerator::ReadOnlyProcessT::PipeT::startRead(std::string* target)
  410. {
  411. Target_ = target;
  412. return uv_read_start(uv_stream(), &PipeT::UVAlloc, &PipeT::UVData);
  413. }
  414. void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::reset()
  415. {
  416. Process_ = nullptr;
  417. Target_ = nullptr;
  418. UVPipe_.reset();
  419. Buffer_.clear();
  420. Buffer_.shrink_to_fit();
  421. }
  422. void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVAlloc(uv_handle_t* handle,
  423. size_t suggestedSize,
  424. uv_buf_t* buf)
  425. {
  426. auto& pipe = *reinterpret_cast<PipeT*>(handle->data);
  427. pipe.Buffer_.resize(suggestedSize);
  428. buf->base = pipe.Buffer_.data();
  429. buf->len = pipe.Buffer_.size();
  430. }
  431. void cmQtAutoGenerator::ReadOnlyProcessT::PipeT::UVData(uv_stream_t* stream,
  432. ssize_t nread,
  433. const uv_buf_t* buf)
  434. {
  435. auto& pipe = *reinterpret_cast<PipeT*>(stream->data);
  436. if (nread > 0) {
  437. // Append data to merged output
  438. if ((buf->base != nullptr) && (pipe.Target_ != nullptr)) {
  439. pipe.Target_->append(buf->base, nread);
  440. }
  441. } else if (nread < 0) {
  442. // EOF or error
  443. auto* proc = pipe.Process_;
  444. // Check it this an unusual error
  445. if (nread != UV_EOF) {
  446. if (!proc->Result()->error()) {
  447. proc->Result()->ErrorMessage =
  448. "libuv reading from pipe failed with error code ";
  449. proc->Result()->ErrorMessage += std::to_string(nread);
  450. }
  451. }
  452. // Clear libuv pipe handle and try to finish
  453. pipe.reset();
  454. proc->UVTryFinish();
  455. }
  456. }
  457. void cmQtAutoGenerator::ProcessResultT::reset()
  458. {
  459. ExitStatus = 0;
  460. TermSignal = 0;
  461. if (!StdOut.empty()) {
  462. StdOut.clear();
  463. StdOut.shrink_to_fit();
  464. }
  465. if (!StdErr.empty()) {
  466. StdErr.clear();
  467. StdErr.shrink_to_fit();
  468. }
  469. if (!ErrorMessage.empty()) {
  470. ErrorMessage.clear();
  471. ErrorMessage.shrink_to_fit();
  472. }
  473. }
  474. void cmQtAutoGenerator::ReadOnlyProcessT::setup(
  475. ProcessResultT* result, bool mergedOutput,
  476. std::vector<std::string> const& command, std::string const& workingDirectory)
  477. {
  478. Setup_.WorkingDirectory = workingDirectory;
  479. Setup_.Command = command;
  480. Setup_.Result = result;
  481. Setup_.MergedOutput = mergedOutput;
  482. }
  483. static std::string getUVError(const char* prefixString, int uvErrorCode)
  484. {
  485. std::ostringstream ost;
  486. ost << prefixString << ": " << uv_strerror(uvErrorCode);
  487. return ost.str();
  488. }
  489. bool cmQtAutoGenerator::ReadOnlyProcessT::start(
  490. uv_loop_t* uv_loop, std::function<void()>&& finishedCallback)
  491. {
  492. if (IsStarted() || (Result() == nullptr)) {
  493. return false;
  494. }
  495. // Reset result before the start
  496. Result()->reset();
  497. // Fill command string pointers
  498. if (!Setup().Command.empty()) {
  499. CommandPtr_.reserve(Setup().Command.size() + 1);
  500. for (std::string const& arg : Setup().Command) {
  501. CommandPtr_.push_back(arg.c_str());
  502. }
  503. CommandPtr_.push_back(nullptr);
  504. } else {
  505. Result()->ErrorMessage = "Empty command";
  506. }
  507. if (!Result()->error()) {
  508. if (UVPipeOut_.init(uv_loop, this) != 0) {
  509. Result()->ErrorMessage = "libuv stdout pipe initialization failed";
  510. }
  511. }
  512. if (!Result()->error()) {
  513. if (UVPipeErr_.init(uv_loop, this) != 0) {
  514. Result()->ErrorMessage = "libuv stderr pipe initialization failed";
  515. }
  516. }
  517. if (!Result()->error()) {
  518. // -- Setup process stdio options
  519. // stdin
  520. UVOptionsStdIO_[0].flags = UV_IGNORE;
  521. UVOptionsStdIO_[0].data.stream = nullptr;
  522. // stdout
  523. UVOptionsStdIO_[1].flags =
  524. static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
  525. UVOptionsStdIO_[1].data.stream = UVPipeOut_.uv_stream();
  526. // stderr
  527. UVOptionsStdIO_[2].flags =
  528. static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
  529. UVOptionsStdIO_[2].data.stream = UVPipeErr_.uv_stream();
  530. // -- Setup process options
  531. std::fill_n(reinterpret_cast<char*>(&UVOptions_), sizeof(UVOptions_), 0);
  532. UVOptions_.exit_cb = &ReadOnlyProcessT::UVExit;
  533. UVOptions_.file = CommandPtr_[0];
  534. UVOptions_.args = const_cast<char**>(CommandPtr_.data());
  535. UVOptions_.cwd = Setup_.WorkingDirectory.c_str();
  536. UVOptions_.flags = UV_PROCESS_WINDOWS_HIDE;
  537. UVOptions_.stdio_count = static_cast<int>(UVOptionsStdIO_.size());
  538. UVOptions_.stdio = UVOptionsStdIO_.data();
  539. // -- Spawn process
  540. int uvErrorCode = UVProcess_.spawn(*uv_loop, UVOptions_, this);
  541. if (uvErrorCode != 0) {
  542. Result()->ErrorMessage =
  543. getUVError("libuv process spawn failed ", uvErrorCode);
  544. }
  545. }
  546. // -- Start reading from stdio streams
  547. if (!Result()->error()) {
  548. if (UVPipeOut_.startRead(&Result()->StdOut) != 0) {
  549. Result()->ErrorMessage = "libuv start reading from stdout pipe failed";
  550. }
  551. }
  552. if (!Result()->error()) {
  553. if (UVPipeErr_.startRead(Setup_.MergedOutput ? &Result()->StdOut
  554. : &Result()->StdErr) != 0) {
  555. Result()->ErrorMessage = "libuv start reading from stderr pipe failed";
  556. }
  557. }
  558. if (!Result()->error()) {
  559. IsStarted_ = true;
  560. FinishedCallback_ = std::move(finishedCallback);
  561. } else {
  562. // Clear libuv handles and finish
  563. UVProcess_.reset();
  564. UVPipeOut_.reset();
  565. UVPipeErr_.reset();
  566. CommandPtr_.clear();
  567. }
  568. return IsStarted();
  569. }
  570. void cmQtAutoGenerator::ReadOnlyProcessT::UVExit(uv_process_t* handle,
  571. int64_t exitStatus,
  572. int termSignal)
  573. {
  574. auto& proc = *reinterpret_cast<ReadOnlyProcessT*>(handle->data);
  575. if (proc.IsStarted() && !proc.IsFinished()) {
  576. // Set error message on demand
  577. proc.Result()->ExitStatus = exitStatus;
  578. proc.Result()->TermSignal = termSignal;
  579. if (!proc.Result()->error()) {
  580. if (termSignal != 0) {
  581. proc.Result()->ErrorMessage = "Process was terminated by signal ";
  582. proc.Result()->ErrorMessage +=
  583. std::to_string(proc.Result()->TermSignal);
  584. } else if (exitStatus != 0) {
  585. proc.Result()->ErrorMessage = "Process failed with return value ";
  586. proc.Result()->ErrorMessage +=
  587. std::to_string(proc.Result()->ExitStatus);
  588. }
  589. }
  590. // Reset process handle and try to finish
  591. proc.UVProcess_.reset();
  592. proc.UVTryFinish();
  593. }
  594. }
  595. void cmQtAutoGenerator::ReadOnlyProcessT::UVTryFinish()
  596. {
  597. // There still might be data in the pipes after the process has finished.
  598. // Therefore check if the process is finished AND all pipes are closed
  599. // before signaling the worker thread to continue.
  600. if (UVProcess_.get() == nullptr) {
  601. if (UVPipeOut_.uv_pipe() == nullptr) {
  602. if (UVPipeErr_.uv_pipe() == nullptr) {
  603. IsFinished_ = true;
  604. FinishedCallback_();
  605. }
  606. }
  607. }
  608. }
  609. cmQtAutoGenerator::cmQtAutoGenerator()
  610. : FileSys_(&Logger_)
  611. {
  612. // Initialize logger
  613. {
  614. std::string verbose;
  615. if (cmSystemTools::GetEnv("VERBOSE", verbose) && !verbose.empty()) {
  616. unsigned long iVerbose = 0;
  617. if (cmSystemTools::StringToULong(verbose.c_str(), &iVerbose)) {
  618. Logger_.SetVerbosity(static_cast<unsigned int>(iVerbose));
  619. } else {
  620. // Non numeric verbosity
  621. Logger_.SetVerbose(cmSystemTools::IsOn(verbose));
  622. }
  623. }
  624. }
  625. {
  626. std::string colorEnv;
  627. cmSystemTools::GetEnv("COLOR", colorEnv);
  628. if (!colorEnv.empty()) {
  629. Logger_.SetColorOutput(cmSystemTools::IsOn(colorEnv));
  630. } else {
  631. Logger_.SetColorOutput(true);
  632. }
  633. }
  634. // Initialize libuv loop
  635. uv_disable_stdio_inheritance();
  636. #ifdef CMAKE_UV_SIGNAL_HACK
  637. UVHackRAII_ = cm::make_unique<cmUVSignalHackRAII>();
  638. #endif
  639. UVLoop_ = cm::make_unique<uv_loop_t>();
  640. uv_loop_init(UVLoop());
  641. }
  642. cmQtAutoGenerator::~cmQtAutoGenerator()
  643. {
  644. // Close libuv loop
  645. uv_loop_close(UVLoop());
  646. }
  647. bool cmQtAutoGenerator::Run(std::string const& infoFile,
  648. std::string const& config)
  649. {
  650. // Info settings
  651. InfoFile_ = infoFile;
  652. cmSystemTools::ConvertToUnixSlashes(InfoFile_);
  653. InfoDir_ = cmSystemTools::GetFilenamePath(infoFile);
  654. InfoConfig_ = config;
  655. bool success = false;
  656. {
  657. cmake cm(cmake::RoleScript, cmState::Unknown);
  658. cm.SetHomeOutputDirectory(InfoDir());
  659. cm.SetHomeDirectory(InfoDir());
  660. cm.GetCurrentSnapshot().SetDefaultDefinitions();
  661. cmGlobalGenerator gg(&cm);
  662. cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
  663. snapshot.GetDirectory().SetCurrentBinary(InfoDir());
  664. snapshot.GetDirectory().SetCurrentSource(InfoDir());
  665. auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
  666. // The OLD/WARN behavior for policy CMP0053 caused a speed regression.
  667. // https://gitlab.kitware.com/cmake/cmake/issues/17570
  668. makefile->SetPolicyVersion("3.9", std::string());
  669. gg.SetCurrentMakefile(makefile.get());
  670. success = this->Init(makefile.get());
  671. }
  672. if (success) {
  673. success = this->Process();
  674. }
  675. return success;
  676. }
  677. std::string cmQtAutoGenerator::SettingsFind(std::string const& content,
  678. const char* key)
  679. {
  680. std::string prefix(key);
  681. prefix += ':';
  682. std::string::size_type pos = content.find(prefix);
  683. if (pos != std::string::npos) {
  684. pos += prefix.size();
  685. if (pos < content.size()) {
  686. std::string::size_type posE = content.find('\n', pos);
  687. if ((posE != std::string::npos) && (posE != pos)) {
  688. return content.substr(pos, posE - pos);
  689. }
  690. }
  691. }
  692. return std::string();
  693. }