QCMake.cxx 13 KB

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