mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00

This option has been broken since commit b9f9915516
(cmMakefile: Remove
VarUsageStack., 2015-05-17, v3.3.0-rc1~52^2). That commit removed the
check that an initialized variable has actually been used and caused the
option to warn on every variable ever set. This was not caught by the
test suite because the test for the feature only checked that warnings
appear when needed and not that they do not appear when not needed.
The option was never very practical to use. Remove it to avoid the
runtime cost of usage tracking and checks for every variable (which we
were doing even when the option was not used).
485 lines
13 KiB
C++
485 lines
13 KiB
C++
/* 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 <cm/memory>
|
|
|
|
#include <QCoreApplication>
|
|
#include <QDir>
|
|
|
|
#include "cmExternalMakefileProjectGenerator.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmState.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
#ifdef Q_OS_WIN
|
|
# include "qt_windows.h" // For SetErrorMode
|
|
#endif
|
|
|
|
QCMake::QCMake(QObject* p)
|
|
: QObject(p)
|
|
{
|
|
this->WarnUninitializedMode = 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 =
|
|
cm::make_unique<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() = default;
|
|
|
|
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);
|
|
cmProp homeDir = state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
|
|
if (homeDir) {
|
|
setSourceDirectory(QString::fromLocal8Bit(homeDir->c_str()));
|
|
}
|
|
cmProp 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()));
|
|
}
|
|
|
|
cmProp platform = state->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
|
|
if (platform) {
|
|
this->setPlatform(QString::fromLocal8Bit(platform->c_str()));
|
|
}
|
|
|
|
cmProp toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
|
|
if (toolset) {
|
|
this->setToolset(QString::fromLocal8Bit(toolset->c_str()));
|
|
}
|
|
|
|
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->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 properties
|
|
foreach (QString const& s, toremove) {
|
|
this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data());
|
|
|
|
state->RemoveCacheEntry(s.toLocal8Bit().data());
|
|
}
|
|
|
|
// add some new properties
|
|
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;
|
|
}
|
|
|
|
cmProp cachedValue = state->GetCacheEntryValue(key);
|
|
|
|
QCMakeProperty prop;
|
|
prop.Key = QString::fromLocal8Bit(key.c_str());
|
|
if (cmProp hs = state->GetCacheEntryProperty(key, "HELPSTRING")) {
|
|
prop.Help = QString::fromLocal8Bit(hs->c_str());
|
|
}
|
|
prop.Value = QString::fromLocal8Bit(cachedValue->c_str());
|
|
prop.Advanced = state->GetCacheEntryPropertyAsBool(key, "ADVANCED");
|
|
if (t == cmStateEnums::BOOL) {
|
|
prop.Type = QCMakeProperty::BOOL;
|
|
prop.Value = cmIsOn(*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;
|
|
cmProp stringsProperty = state->GetCacheEntryProperty(key, "STRINGS");
|
|
if (stringsProperty) {
|
|
prop.Strings =
|
|
QString::fromLocal8Bit(stringsProperty->c_str()).split(";");
|
|
}
|
|
}
|
|
|
|
ret.append(prop);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void QCMake::interrupt()
|
|
{
|
|
this->InterruptFlag.ref();
|
|
}
|
|
|
|
bool QCMake::interruptCallback()
|
|
{
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
|
return this->InterruptFlag.load();
|
|
#else
|
|
return this->InterruptFlag.loadRelaxed();
|
|
#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::checkOpenPossible()
|
|
{
|
|
std::string data = this->BinaryDirectory.toLocal8Bit().data();
|
|
auto possible = this->CMakeInstance->Open(data, true);
|
|
emit openPossible(possible);
|
|
}
|