QCMake.cxx 13 KB

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