QCMake.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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 "QCMake.h"
  4. #include <QCoreApplication>
  5. #include <QDir>
  6. #include "cmExternalMakefileProjectGenerator.h"
  7. #include "cmState.h"
  8. #include "cmSystemTools.h"
  9. #ifdef Q_OS_WIN
  10. # include "qt_windows.h" // For SetErrorMode
  11. #endif
  12. QCMake::QCMake(QObject* p)
  13. : QObject(p)
  14. {
  15. this->WarnUninitializedMode = false;
  16. this->WarnUnusedMode = false;
  17. qRegisterMetaType<QCMakeProperty>();
  18. qRegisterMetaType<QCMakePropertyList>();
  19. cmSystemTools::DisableRunCommandOutput();
  20. cmSystemTools::SetRunCommandHideConsole(true);
  21. cmSystemTools::SetMessageCallback(
  22. [this](const char* msg, const char* title) {
  23. this->messageCallback(msg, title);
  24. });
  25. cmSystemTools::SetStdoutCallback(
  26. [this](const char* msg, size_t len) { this->stdoutCallback(msg, len); });
  27. cmSystemTools::SetStderrCallback(
  28. [this](const char* msg, size_t len) { this->stderrCallback(msg, len); });
  29. this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project);
  30. this->CMakeInstance->SetCMakeEditCommand(
  31. cmSystemTools::GetCMakeGUICommand());
  32. this->CMakeInstance->SetProgressCallback(
  33. [this](const char* msg, float percent) {
  34. this->progressCallback(msg, percent);
  35. });
  36. cmSystemTools::SetInterruptCallback(
  37. [this] { return this->interruptCallback(); });
  38. std::vector<cmake::GeneratorInfo> generators;
  39. this->CMakeInstance->GetRegisteredGenerators(
  40. generators, /*includeNamesWithPlatform=*/false);
  41. std::vector<cmake::GeneratorInfo>::const_iterator it;
  42. for (it = generators.begin(); it != generators.end(); ++it) {
  43. this->AvailableGenerators.push_back(*it);
  44. }
  45. }
  46. QCMake::~QCMake()
  47. {
  48. delete this->CMakeInstance;
  49. // cmDynamicLoader::FlushCache();
  50. }
  51. void QCMake::loadCache(const QString& dir)
  52. {
  53. this->setBinaryDirectory(dir);
  54. }
  55. void QCMake::setSourceDirectory(const QString& _dir)
  56. {
  57. QString dir = QString::fromLocal8Bit(
  58. cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
  59. if (this->SourceDirectory != dir) {
  60. this->SourceDirectory = QDir::fromNativeSeparators(dir);
  61. emit this->sourceDirChanged(this->SourceDirectory);
  62. }
  63. }
  64. void QCMake::setBinaryDirectory(const QString& _dir)
  65. {
  66. QString dir = QString::fromLocal8Bit(
  67. cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str());
  68. if (this->BinaryDirectory != dir) {
  69. this->BinaryDirectory = QDir::fromNativeSeparators(dir);
  70. emit this->binaryDirChanged(this->BinaryDirectory);
  71. cmState* state = this->CMakeInstance->GetState();
  72. this->setGenerator(QString());
  73. this->setToolset(QString());
  74. this->setPlatform(QString());
  75. if (!this->CMakeInstance->LoadCache(
  76. this->BinaryDirectory.toLocal8Bit().data())) {
  77. QDir testDir(this->BinaryDirectory);
  78. if (testDir.exists("CMakeCache.txt")) {
  79. cmSystemTools::Error(
  80. "There is a CMakeCache.txt file for the current binary "
  81. "tree but cmake does not have permission to read it. "
  82. "Please check the permissions of the directory you are trying to "
  83. "run CMake on.");
  84. }
  85. }
  86. QCMakePropertyList props = this->properties();
  87. emit this->propertiesChanged(props);
  88. const char* homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
  89. if (homeDir) {
  90. setSourceDirectory(QString::fromLocal8Bit(homeDir));
  91. }
  92. const char* gen = state->GetCacheEntryValue("CMAKE_GENERATOR");
  93. if (gen) {
  94. const std::string* extraGen =
  95. state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
  96. std::string curGen =
  97. cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
  98. gen, extraGen ? *extraGen : "");
  99. this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
  100. }
  101. const char* platform =
  102. state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
  103. if (platform) {
  104. this->setPlatform(QString::fromLocal8Bit(platform));
  105. }
  106. const char* toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
  107. if (toolset) {
  108. this->setToolset(QString::fromLocal8Bit(toolset));
  109. }
  110. checkOpenPossible();
  111. }
  112. }
  113. void QCMake::setGenerator(const QString& gen)
  114. {
  115. if (this->Generator != gen) {
  116. this->Generator = gen;
  117. emit this->generatorChanged(this->Generator);
  118. }
  119. }
  120. void QCMake::setPlatform(const QString& platform)
  121. {
  122. if (this->Platform != platform) {
  123. this->Platform = platform;
  124. emit this->platformChanged(this->Platform);
  125. }
  126. }
  127. void QCMake::setToolset(const QString& toolset)
  128. {
  129. if (this->Toolset != toolset) {
  130. this->Toolset = toolset;
  131. emit this->toolsetChanged(this->Toolset);
  132. }
  133. }
  134. void QCMake::configure()
  135. {
  136. #ifdef Q_OS_WIN
  137. UINT lastErrorMode = SetErrorMode(0);
  138. #endif
  139. this->CMakeInstance->SetHomeDirectory(
  140. this->SourceDirectory.toLocal8Bit().data());
  141. this->CMakeInstance->SetHomeOutputDirectory(
  142. this->BinaryDirectory.toLocal8Bit().data());
  143. this->CMakeInstance->SetGlobalGenerator(
  144. this->CMakeInstance->CreateGlobalGenerator(
  145. this->Generator.toLocal8Bit().data()));
  146. this->CMakeInstance->SetGeneratorPlatform(
  147. this->Platform.toLocal8Bit().data());
  148. this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data());
  149. this->CMakeInstance->LoadCache();
  150. this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode);
  151. this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode);
  152. this->CMakeInstance->PreLoadCMakeFiles();
  153. InterruptFlag = 0;
  154. cmSystemTools::ResetErrorOccuredFlag();
  155. int err = this->CMakeInstance->Configure();
  156. #ifdef Q_OS_WIN
  157. SetErrorMode(lastErrorMode);
  158. #endif
  159. emit this->propertiesChanged(this->properties());
  160. emit this->configureDone(err);
  161. }
  162. void QCMake::generate()
  163. {
  164. #ifdef Q_OS_WIN
  165. UINT lastErrorMode = SetErrorMode(0);
  166. #endif
  167. InterruptFlag = 0;
  168. cmSystemTools::ResetErrorOccuredFlag();
  169. int err = this->CMakeInstance->Generate();
  170. #ifdef Q_OS_WIN
  171. SetErrorMode(lastErrorMode);
  172. #endif
  173. emit this->generateDone(err);
  174. checkOpenPossible();
  175. }
  176. void QCMake::open()
  177. {
  178. #ifdef Q_OS_WIN
  179. UINT lastErrorMode = SetErrorMode(0);
  180. #endif
  181. InterruptFlag = 0;
  182. cmSystemTools::ResetErrorOccuredFlag();
  183. auto successful = this->CMakeInstance->Open(
  184. this->BinaryDirectory.toLocal8Bit().data(), false);
  185. #ifdef Q_OS_WIN
  186. SetErrorMode(lastErrorMode);
  187. #endif
  188. emit this->openDone(successful);
  189. }
  190. void QCMake::setProperties(const QCMakePropertyList& newProps)
  191. {
  192. QCMakePropertyList props = newProps;
  193. QStringList toremove;
  194. // set the value of properties
  195. cmState* state = this->CMakeInstance->GetState();
  196. std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
  197. for (std::vector<std::string>::const_iterator it = cacheKeys.begin();
  198. it != cacheKeys.end(); ++it) {
  199. cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*it);
  200. if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) {
  201. continue;
  202. }
  203. QCMakeProperty prop;
  204. prop.Key = QString::fromLocal8Bit(it->c_str());
  205. int idx = props.indexOf(prop);
  206. if (idx == -1) {
  207. toremove.append(QString::fromLocal8Bit(it->c_str()));
  208. } else {
  209. prop = props[idx];
  210. if (prop.Value.type() == QVariant::Bool) {
  211. state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
  212. } else {
  213. state->SetCacheEntryValue(*it,
  214. prop.Value.toString().toLocal8Bit().data());
  215. }
  216. props.removeAt(idx);
  217. }
  218. }
  219. // remove some properites
  220. foreach (QString const& s, toremove) {
  221. this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data());
  222. state->RemoveCacheEntry(s.toLocal8Bit().data());
  223. }
  224. // add some new properites
  225. foreach (QCMakeProperty const& s, props) {
  226. this->CMakeInstance->WatchUnusedCli(s.Key.toLocal8Bit().data());
  227. if (s.Type == QCMakeProperty::BOOL) {
  228. this->CMakeInstance->AddCacheEntry(
  229. s.Key.toLocal8Bit().data(), s.Value.toBool() ? "ON" : "OFF",
  230. s.Help.toLocal8Bit().data(), cmStateEnums::BOOL);
  231. } else if (s.Type == QCMakeProperty::STRING) {
  232. this->CMakeInstance->AddCacheEntry(
  233. s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
  234. s.Help.toLocal8Bit().data(), cmStateEnums::STRING);
  235. } else if (s.Type == QCMakeProperty::PATH) {
  236. this->CMakeInstance->AddCacheEntry(
  237. s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
  238. s.Help.toLocal8Bit().data(), cmStateEnums::PATH);
  239. } else if (s.Type == QCMakeProperty::FILEPATH) {
  240. this->CMakeInstance->AddCacheEntry(
  241. s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
  242. s.Help.toLocal8Bit().data(), cmStateEnums::FILEPATH);
  243. }
  244. }
  245. this->CMakeInstance->SaveCache(this->BinaryDirectory.toLocal8Bit().data());
  246. }
  247. QCMakePropertyList QCMake::properties() const
  248. {
  249. QCMakePropertyList ret;
  250. cmState* state = this->CMakeInstance->GetState();
  251. std::vector<std::string> cacheKeys = state->GetCacheEntryKeys();
  252. for (std::vector<std::string>::const_iterator i = cacheKeys.begin();
  253. i != cacheKeys.end(); ++i) {
  254. cmStateEnums::CacheEntryType t = state->GetCacheEntryType(*i);
  255. if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC ||
  256. t == cmStateEnums::UNINITIALIZED) {
  257. continue;
  258. }
  259. const char* cachedValue = state->GetCacheEntryValue(*i);
  260. QCMakeProperty prop;
  261. prop.Key = QString::fromLocal8Bit(i->c_str());
  262. prop.Help =
  263. QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
  264. prop.Value = QString::fromLocal8Bit(cachedValue);
  265. prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
  266. if (t == cmStateEnums::BOOL) {
  267. prop.Type = QCMakeProperty::BOOL;
  268. prop.Value = cmSystemTools::IsOn(cachedValue);
  269. } else if (t == cmStateEnums::PATH) {
  270. prop.Type = QCMakeProperty::PATH;
  271. } else if (t == cmStateEnums::FILEPATH) {
  272. prop.Type = QCMakeProperty::FILEPATH;
  273. } else if (t == cmStateEnums::STRING) {
  274. prop.Type = QCMakeProperty::STRING;
  275. const char* stringsProperty =
  276. state->GetCacheEntryProperty(*i, "STRINGS");
  277. if (stringsProperty) {
  278. prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
  279. }
  280. }
  281. ret.append(prop);
  282. }
  283. return ret;
  284. }
  285. void QCMake::interrupt()
  286. {
  287. this->InterruptFlag.ref();
  288. }
  289. bool QCMake::interruptCallback()
  290. {
  291. #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
  292. return this->InterruptFlag;
  293. #else
  294. return this->InterruptFlag.load();
  295. #endif
  296. }
  297. void QCMake::progressCallback(const char* msg, float percent)
  298. {
  299. if (percent >= 0) {
  300. emit this->progressChanged(QString::fromLocal8Bit(msg), percent);
  301. } else {
  302. emit this->outputMessage(QString::fromLocal8Bit(msg));
  303. }
  304. QCoreApplication::processEvents();
  305. }
  306. void QCMake::messageCallback(const char* msg, const char* /*title*/)
  307. {
  308. emit this->errorMessage(QString::fromLocal8Bit(msg));
  309. QCoreApplication::processEvents();
  310. }
  311. void QCMake::stdoutCallback(const char* msg, size_t len)
  312. {
  313. emit this->outputMessage(QString::fromLocal8Bit(msg, int(len)));
  314. QCoreApplication::processEvents();
  315. }
  316. void QCMake::stderrCallback(const char* msg, size_t len)
  317. {
  318. emit this->outputMessage(QString::fromLocal8Bit(msg, int(len)));
  319. QCoreApplication::processEvents();
  320. }
  321. QString QCMake::binaryDirectory() const
  322. {
  323. return this->BinaryDirectory;
  324. }
  325. QString QCMake::sourceDirectory() const
  326. {
  327. return this->SourceDirectory;
  328. }
  329. QString QCMake::generator() const
  330. {
  331. return this->Generator;
  332. }
  333. std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const
  334. {
  335. return AvailableGenerators;
  336. }
  337. void QCMake::deleteCache()
  338. {
  339. // delete cache
  340. this->CMakeInstance->DeleteCache(this->BinaryDirectory.toLocal8Bit().data());
  341. // reload to make our cache empty
  342. this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
  343. // emit no generator and no properties
  344. this->setGenerator(QString());
  345. this->setToolset(QString());
  346. QCMakePropertyList props = this->properties();
  347. emit this->propertiesChanged(props);
  348. }
  349. void QCMake::reloadCache()
  350. {
  351. // emit that the cache was cleaned out
  352. QCMakePropertyList props;
  353. emit this->propertiesChanged(props);
  354. // reload
  355. this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data());
  356. // emit new cache properties
  357. props = this->properties();
  358. emit this->propertiesChanged(props);
  359. }
  360. void QCMake::setDebugOutput(bool flag)
  361. {
  362. if (flag != this->CMakeInstance->GetDebugOutput()) {
  363. this->CMakeInstance->SetDebugOutputOn(flag);
  364. emit this->debugOutputChanged(flag);
  365. }
  366. }
  367. bool QCMake::getDebugOutput() const
  368. {
  369. return this->CMakeInstance->GetDebugOutput();
  370. }
  371. bool QCMake::getSuppressDevWarnings()
  372. {
  373. return this->CMakeInstance->GetSuppressDevWarnings();
  374. }
  375. void QCMake::setSuppressDevWarnings(bool value)
  376. {
  377. this->CMakeInstance->SetSuppressDevWarnings(value);
  378. }
  379. bool QCMake::getSuppressDeprecatedWarnings()
  380. {
  381. return this->CMakeInstance->GetSuppressDeprecatedWarnings();
  382. }
  383. void QCMake::setSuppressDeprecatedWarnings(bool value)
  384. {
  385. this->CMakeInstance->SetSuppressDeprecatedWarnings(value);
  386. }
  387. bool QCMake::getDevWarningsAsErrors()
  388. {
  389. return this->CMakeInstance->GetDevWarningsAsErrors();
  390. }
  391. void QCMake::setDevWarningsAsErrors(bool value)
  392. {
  393. this->CMakeInstance->SetDevWarningsAsErrors(value);
  394. }
  395. bool QCMake::getDeprecatedWarningsAsErrors()
  396. {
  397. return this->CMakeInstance->GetDeprecatedWarningsAsErrors();
  398. }
  399. void QCMake::setDeprecatedWarningsAsErrors(bool value)
  400. {
  401. this->CMakeInstance->SetDeprecatedWarningsAsErrors(value);
  402. }
  403. void QCMake::setWarnUninitializedMode(bool value)
  404. {
  405. this->WarnUninitializedMode = value;
  406. }
  407. void QCMake::setWarnUnusedMode(bool value)
  408. {
  409. this->WarnUnusedMode = value;
  410. }
  411. void QCMake::checkOpenPossible()
  412. {
  413. auto data = this->BinaryDirectory.toLocal8Bit().data();
  414. auto possible = this->CMakeInstance->Open(data, true);
  415. emit openPossible(possible);
  416. }