cmQtAutoGenerator.cxx 19 KB

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