diff options
Diffstat (limited to 'Source/QtDialog/QCMake.cxx')
-rw-r--r-- | Source/QtDialog/QCMake.cxx | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx new file mode 100644 index 0000000..f357f90 --- /dev/null +++ b/Source/QtDialog/QCMake.cxx @@ -0,0 +1,490 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "QCMake.h" + +#include <QCoreApplication> +#include <QDir> + +#include "cmExternalMakefileProjectGenerator.h" +#include "cmState.h" +#include "cmSystemTools.h" + +#ifdef Q_OS_WIN +# include "qt_windows.h" // For SetErrorMode +#endif + +QCMake::QCMake(QObject* p) + : QObject(p) +{ + this->WarnUninitializedMode = false; + this->WarnUnusedMode = false; + qRegisterMetaType<QCMakeProperty>(); + qRegisterMetaType<QCMakePropertyList>(); + + cmSystemTools::DisableRunCommandOutput(); + cmSystemTools::SetRunCommandHideConsole(true); + + cmSystemTools::SetMessageCallback( + [this](std::string const& msg, const char* title) { + this->messageCallback(msg, title); + }); + cmSystemTools::SetStdoutCallback( + [this](std::string const& msg) { this->stdoutCallback(msg); }); + cmSystemTools::SetStderrCallback( + [this](std::string const& msg) { this->stderrCallback(msg); }); + + this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project); + this->CMakeInstance->SetCMakeEditCommand( + cmSystemTools::GetCMakeGUICommand()); + this->CMakeInstance->SetProgressCallback( + [this](const std::string& msg, float percent) { + this->progressCallback(msg, percent); + }); + + cmSystemTools::SetInterruptCallback( + [this] { return this->interruptCallback(); }); + + std::vector<cmake::GeneratorInfo> generators; + this->CMakeInstance->GetRegisteredGenerators( + generators, /*includeNamesWithPlatform=*/false); + + for (cmake::GeneratorInfo const& gen : generators) { + this->AvailableGenerators.push_back(gen); + } +} + +QCMake::~QCMake() +{ + delete this->CMakeInstance; + // cmDynamicLoader::FlushCache(); +} + +void QCMake::loadCache(const QString& dir) +{ + this->setBinaryDirectory(dir); +} + +void QCMake::setSourceDirectory(const QString& _dir) +{ + QString dir = QString::fromLocal8Bit( + cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str()); + if (this->SourceDirectory != dir) { + this->SourceDirectory = QDir::fromNativeSeparators(dir); + emit this->sourceDirChanged(this->SourceDirectory); + } +} + +void QCMake::setBinaryDirectory(const QString& _dir) +{ + QString dir = QString::fromLocal8Bit( + cmSystemTools::GetActualCaseForPath(_dir.toLocal8Bit().data()).c_str()); + if (this->BinaryDirectory != dir) { + this->BinaryDirectory = QDir::fromNativeSeparators(dir); + emit this->binaryDirChanged(this->BinaryDirectory); + cmState* state = this->CMakeInstance->GetState(); + this->setGenerator(QString()); + this->setToolset(QString()); + this->setPlatform(QString()); + if (!this->CMakeInstance->LoadCache( + this->BinaryDirectory.toLocal8Bit().data())) { + QDir testDir(this->BinaryDirectory); + if (testDir.exists("CMakeCache.txt")) { + cmSystemTools::Error( + "There is a CMakeCache.txt file for the current binary " + "tree but cmake does not have permission to read it. " + "Please check the permissions of the directory you are trying to " + "run CMake on."); + } + } + + QCMakePropertyList props = this->properties(); + emit this->propertiesChanged(props); + const char* homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); + if (homeDir) { + setSourceDirectory(QString::fromLocal8Bit(homeDir)); + } + const char* gen = state->GetCacheEntryValue("CMAKE_GENERATOR"); + if (gen) { + const std::string* extraGen = + state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR"); + std::string curGen = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + gen, extraGen ? *extraGen : ""); + this->setGenerator(QString::fromLocal8Bit(curGen.c_str())); + } + + const char* platform = + state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM"); + if (platform) { + this->setPlatform(QString::fromLocal8Bit(platform)); + } + + const char* toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET"); + if (toolset) { + this->setToolset(QString::fromLocal8Bit(toolset)); + } + + checkOpenPossible(); + } +} + +void QCMake::setGenerator(const QString& gen) +{ + if (this->Generator != gen) { + this->Generator = gen; + emit this->generatorChanged(this->Generator); + } +} + +void QCMake::setPlatform(const QString& platform) +{ + if (this->Platform != platform) { + this->Platform = platform; + emit this->platformChanged(this->Platform); + } +} + +void QCMake::setToolset(const QString& toolset) +{ + if (this->Toolset != toolset) { + this->Toolset = toolset; + emit this->toolsetChanged(this->Toolset); + } +} + +void QCMake::configure() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + this->CMakeInstance->SetHomeDirectory( + this->SourceDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetHomeOutputDirectory( + this->BinaryDirectory.toLocal8Bit().data()); + this->CMakeInstance->SetGlobalGenerator( + this->CMakeInstance->CreateGlobalGenerator( + this->Generator.toLocal8Bit().data())); + this->CMakeInstance->SetGeneratorPlatform( + this->Platform.toLocal8Bit().data()); + this->CMakeInstance->SetGeneratorToolset(this->Toolset.toLocal8Bit().data()); + this->CMakeInstance->LoadCache(); + this->CMakeInstance->SetWarnUninitialized(this->WarnUninitializedMode); + this->CMakeInstance->SetWarnUnused(this->WarnUnusedMode); + this->CMakeInstance->PreLoadCMakeFiles(); + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + int err = this->CMakeInstance->Configure(); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->propertiesChanged(this->properties()); + emit this->configureDone(err); +} + +void QCMake::generate() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + int err = this->CMakeInstance->Generate(); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->generateDone(err); + checkOpenPossible(); +} + +void QCMake::open() +{ +#ifdef Q_OS_WIN + UINT lastErrorMode = SetErrorMode(0); +#endif + + InterruptFlag = 0; + cmSystemTools::ResetErrorOccuredFlag(); + + auto successful = this->CMakeInstance->Open( + this->BinaryDirectory.toLocal8Bit().data(), false); + +#ifdef Q_OS_WIN + SetErrorMode(lastErrorMode); +#endif + + emit this->openDone(successful); +} + +void QCMake::setProperties(const QCMakePropertyList& newProps) +{ + QCMakePropertyList props = newProps; + + QStringList toremove; + + // set the value of properties + cmState* state = this->CMakeInstance->GetState(); + std::vector<std::string> cacheKeys = state->GetCacheEntryKeys(); + for (std::string const& key : cacheKeys) { + cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key); + if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC) { + continue; + } + + QCMakeProperty prop; + prop.Key = QString::fromLocal8Bit(key.c_str()); + int idx = props.indexOf(prop); + if (idx == -1) { + toremove.append(QString::fromLocal8Bit(key.c_str())); + } else { + prop = props[idx]; + if (prop.Value.type() == QVariant::Bool) { + state->SetCacheEntryValue(key, prop.Value.toBool() ? "ON" : "OFF"); + } else { + state->SetCacheEntryValue(key, + prop.Value.toString().toLocal8Bit().data()); + } + props.removeAt(idx); + } + } + + // remove some properites + foreach (QString const& s, toremove) { + this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data()); + + state->RemoveCacheEntry(s.toLocal8Bit().data()); + } + + // add some new properites + foreach (QCMakeProperty const& s, props) { + this->CMakeInstance->WatchUnusedCli(s.Key.toLocal8Bit().data()); + + if (s.Type == QCMakeProperty::BOOL) { + this->CMakeInstance->AddCacheEntry( + s.Key.toLocal8Bit().data(), s.Value.toBool() ? "ON" : "OFF", + s.Help.toLocal8Bit().data(), cmStateEnums::BOOL); + } else if (s.Type == QCMakeProperty::STRING) { + this->CMakeInstance->AddCacheEntry( + s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), cmStateEnums::STRING); + } else if (s.Type == QCMakeProperty::PATH) { + this->CMakeInstance->AddCacheEntry( + s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), cmStateEnums::PATH); + } else if (s.Type == QCMakeProperty::FILEPATH) { + this->CMakeInstance->AddCacheEntry( + s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(), + s.Help.toLocal8Bit().data(), cmStateEnums::FILEPATH); + } + } + + this->CMakeInstance->SaveCache(this->BinaryDirectory.toLocal8Bit().data()); +} + +QCMakePropertyList QCMake::properties() const +{ + QCMakePropertyList ret; + + cmState* state = this->CMakeInstance->GetState(); + std::vector<std::string> cacheKeys = state->GetCacheEntryKeys(); + for (std::string const& key : cacheKeys) { + cmStateEnums::CacheEntryType t = state->GetCacheEntryType(key); + if (t == cmStateEnums::INTERNAL || t == cmStateEnums::STATIC || + t == cmStateEnums::UNINITIALIZED) { + continue; + } + + const char* cachedValue = state->GetCacheEntryValue(key); + + QCMakeProperty prop; + prop.Key = QString::fromLocal8Bit(key.c_str()); + prop.Help = + QString::fromLocal8Bit(state->GetCacheEntryProperty(key, "HELPSTRING")); + prop.Value = QString::fromLocal8Bit(cachedValue); + prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED"); + if (t == cmStateEnums::BOOL) { + prop.Type = QCMakeProperty::BOOL; + prop.Value = cmSystemTools::IsOn(cachedValue); + } else if (t == cmStateEnums::PATH) { + prop.Type = QCMakeProperty::PATH; + } else if (t == cmStateEnums::FILEPATH) { + prop.Type = QCMakeProperty::FILEPATH; + } else if (t == cmStateEnums::STRING) { + prop.Type = QCMakeProperty::STRING; + const char* stringsProperty = + state->GetCacheEntryProperty(key, "STRINGS"); + if (stringsProperty) { + prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";"); + } + } + + ret.append(prop); + } + + return ret; +} + +void QCMake::interrupt() +{ + this->InterruptFlag.ref(); +} + +bool QCMake::interruptCallback() +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + return this->InterruptFlag; +#else + return this->InterruptFlag.load(); +#endif +} + +void QCMake::progressCallback(const std::string& msg, float percent) +{ + if (percent >= 0) { + emit this->progressChanged(QString::fromStdString(msg), percent); + } else { + emit this->outputMessage(QString::fromStdString(msg)); + } + QCoreApplication::processEvents(); +} + +void QCMake::messageCallback(std::string const& msg, const char* /*title*/) +{ + emit this->errorMessage(QString::fromStdString(msg)); + QCoreApplication::processEvents(); +} + +void QCMake::stdoutCallback(std::string const& msg) +{ + emit this->outputMessage(QString::fromStdString(msg)); + QCoreApplication::processEvents(); +} + +void QCMake::stderrCallback(std::string const& msg) +{ + emit this->outputMessage(QString::fromStdString(msg)); + QCoreApplication::processEvents(); +} + +QString QCMake::binaryDirectory() const +{ + return this->BinaryDirectory; +} + +QString QCMake::sourceDirectory() const +{ + return this->SourceDirectory; +} + +QString QCMake::generator() const +{ + return this->Generator; +} + +std::vector<cmake::GeneratorInfo> const& QCMake::availableGenerators() const +{ + return AvailableGenerators; +} + +void QCMake::deleteCache() +{ + // delete cache + this->CMakeInstance->DeleteCache(this->BinaryDirectory.toLocal8Bit().data()); + // reload to make our cache empty + this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data()); + // emit no generator and no properties + this->setGenerator(QString()); + this->setToolset(QString()); + QCMakePropertyList props = this->properties(); + emit this->propertiesChanged(props); +} + +void QCMake::reloadCache() +{ + // emit that the cache was cleaned out + QCMakePropertyList props; + emit this->propertiesChanged(props); + // reload + this->CMakeInstance->LoadCache(this->BinaryDirectory.toLocal8Bit().data()); + // emit new cache properties + props = this->properties(); + emit this->propertiesChanged(props); +} + +void QCMake::setDebugOutput(bool flag) +{ + if (flag != this->CMakeInstance->GetDebugOutput()) { + this->CMakeInstance->SetDebugOutputOn(flag); + emit this->debugOutputChanged(flag); + } +} + +bool QCMake::getDebugOutput() const +{ + return this->CMakeInstance->GetDebugOutput(); +} + +bool QCMake::getSuppressDevWarnings() +{ + return this->CMakeInstance->GetSuppressDevWarnings(); +} + +void QCMake::setSuppressDevWarnings(bool value) +{ + this->CMakeInstance->SetSuppressDevWarnings(value); +} + +bool QCMake::getSuppressDeprecatedWarnings() +{ + return this->CMakeInstance->GetSuppressDeprecatedWarnings(); +} + +void QCMake::setSuppressDeprecatedWarnings(bool value) +{ + this->CMakeInstance->SetSuppressDeprecatedWarnings(value); +} + +bool QCMake::getDevWarningsAsErrors() +{ + return this->CMakeInstance->GetDevWarningsAsErrors(); +} + +void QCMake::setDevWarningsAsErrors(bool value) +{ + this->CMakeInstance->SetDevWarningsAsErrors(value); +} + +bool QCMake::getDeprecatedWarningsAsErrors() +{ + return this->CMakeInstance->GetDeprecatedWarningsAsErrors(); +} + +void QCMake::setDeprecatedWarningsAsErrors(bool value) +{ + this->CMakeInstance->SetDeprecatedWarningsAsErrors(value); +} + +void QCMake::setWarnUninitializedMode(bool value) +{ + this->WarnUninitializedMode = value; +} + +void QCMake::setWarnUnusedMode(bool value) +{ + this->WarnUnusedMode = value; +} + +void QCMake::checkOpenPossible() +{ + auto data = this->BinaryDirectory.toLocal8Bit().data(); + auto possible = this->CMakeInstance->Open(data, true); + emit openPossible(possible); +} |