453 lines
13 KiB
C++
453 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 <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(QCMake::messageCallback, this);
|
|
cmSystemTools::SetStdoutCallback(QCMake::stdoutCallback, this);
|
|
cmSystemTools::SetStderrCallback(QCMake::stderrCallback, this);
|
|
|
|
this->CMakeInstance = new cmake;
|
|
this->CMakeInstance->SetCMakeEditCommand(
|
|
cmSystemTools::GetCMakeGUICommand());
|
|
this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this);
|
|
|
|
cmSystemTools::SetInterruptCallback(QCMake::interruptCallback, this);
|
|
|
|
std::vector<cmake::GeneratorInfo> generators;
|
|
this->CMakeInstance->GetRegisteredGenerators(generators);
|
|
|
|
std::vector<cmake::GeneratorInfo>::const_iterator it;
|
|
for (it = generators.begin(); it != generators.end(); ++it) {
|
|
// Skip the generator "KDevelop3", since there is also
|
|
// "KDevelop3 - Unix Makefiles", which is the full and official name.
|
|
// The short name is actually only still there since this was the name
|
|
// in CMake 2.4, to keep "command line argument compatibility", but
|
|
// this is not necessary in the GUI.
|
|
if (it->name == "KDevelop3") {
|
|
continue;
|
|
}
|
|
|
|
this->AvailableGenerators.push_back(*it);
|
|
}
|
|
}
|
|
|
|
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());
|
|
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 char* extraGen =
|
|
state->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
|
|
std::string curGen =
|
|
cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
|
|
gen, extraGen ? extraGen : "");
|
|
this->setGenerator(QString::fromLocal8Bit(curGen.c_str()));
|
|
}
|
|
|
|
const char* toolset = state->GetCacheEntryValue("CMAKE_GENERATOR_TOOLSET");
|
|
if (toolset) {
|
|
this->setToolset(QString::fromLocal8Bit(toolset));
|
|
}
|
|
}
|
|
}
|
|
|
|
void QCMake::setGenerator(const QString& gen)
|
|
{
|
|
if (this->Generator != gen) {
|
|
this->Generator = gen;
|
|
emit this->generatorChanged(this->Generator);
|
|
}
|
|
}
|
|
|
|
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->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);
|
|
}
|
|
|
|
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::vector<std::string>::const_iterator it = cacheKeys.begin();
|
|
it != cacheKeys.end(); ++it) {
|
|
cmState::CacheEntryType t = state->GetCacheEntryType(*it);
|
|
if (t == cmState::INTERNAL || t == cmState::STATIC) {
|
|
continue;
|
|
}
|
|
|
|
QCMakeProperty prop;
|
|
prop.Key = QString::fromLocal8Bit(it->c_str());
|
|
int idx = props.indexOf(prop);
|
|
if (idx == -1) {
|
|
toremove.append(QString::fromLocal8Bit(it->c_str()));
|
|
} else {
|
|
prop = props[idx];
|
|
if (prop.Value.type() == QVariant::Bool) {
|
|
state->SetCacheEntryValue(*it, prop.Value.toBool() ? "ON" : "OFF");
|
|
} else {
|
|
state->SetCacheEntryValue(*it,
|
|
prop.Value.toString().toLocal8Bit().data());
|
|
}
|
|
props.removeAt(idx);
|
|
}
|
|
}
|
|
|
|
// remove some properites
|
|
foreach (QString s, toremove) {
|
|
this->CMakeInstance->UnwatchUnusedCli(s.toLocal8Bit().data());
|
|
|
|
state->RemoveCacheEntry(s.toLocal8Bit().data());
|
|
}
|
|
|
|
// add some new properites
|
|
foreach (QCMakeProperty 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(), cmState::BOOL);
|
|
} else if (s.Type == QCMakeProperty::STRING) {
|
|
this->CMakeInstance->AddCacheEntry(
|
|
s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
|
|
s.Help.toLocal8Bit().data(), cmState::STRING);
|
|
} else if (s.Type == QCMakeProperty::PATH) {
|
|
this->CMakeInstance->AddCacheEntry(
|
|
s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
|
|
s.Help.toLocal8Bit().data(), cmState::PATH);
|
|
} else if (s.Type == QCMakeProperty::FILEPATH) {
|
|
this->CMakeInstance->AddCacheEntry(
|
|
s.Key.toLocal8Bit().data(), s.Value.toString().toLocal8Bit().data(),
|
|
s.Help.toLocal8Bit().data(), cmState::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::vector<std::string>::const_iterator i = cacheKeys.begin();
|
|
i != cacheKeys.end(); ++i) {
|
|
cmState::CacheEntryType t = state->GetCacheEntryType(*i);
|
|
if (t == cmState::INTERNAL || t == cmState::STATIC ||
|
|
t == cmState::UNINITIALIZED) {
|
|
continue;
|
|
}
|
|
|
|
const char* cachedValue = state->GetCacheEntryValue(*i);
|
|
|
|
QCMakeProperty prop;
|
|
prop.Key = QString::fromLocal8Bit(i->c_str());
|
|
prop.Help =
|
|
QString::fromLocal8Bit(state->GetCacheEntryProperty(*i, "HELPSTRING"));
|
|
prop.Value = QString::fromLocal8Bit(cachedValue);
|
|
prop.Advanced = state->GetCacheEntryPropertyAsBool(*i, "ADVANCED");
|
|
if (t == cmState::BOOL) {
|
|
prop.Type = QCMakeProperty::BOOL;
|
|
prop.Value = cmSystemTools::IsOn(cachedValue);
|
|
} else if (t == cmState::PATH) {
|
|
prop.Type = QCMakeProperty::PATH;
|
|
} else if (t == cmState::FILEPATH) {
|
|
prop.Type = QCMakeProperty::FILEPATH;
|
|
} else if (t == cmState::STRING) {
|
|
prop.Type = QCMakeProperty::STRING;
|
|
const char* stringsProperty =
|
|
state->GetCacheEntryProperty(*i, "STRINGS");
|
|
if (stringsProperty) {
|
|
prop.Strings = QString::fromLocal8Bit(stringsProperty).split(";");
|
|
}
|
|
}
|
|
|
|
ret.append(prop);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void QCMake::interrupt()
|
|
{
|
|
this->InterruptFlag.ref();
|
|
}
|
|
|
|
bool QCMake::interruptCallback(void* cd)
|
|
{
|
|
QCMake* self = reinterpret_cast<QCMake*>(cd);
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
|
return self->InterruptFlag;
|
|
#else
|
|
return self->InterruptFlag.load();
|
|
#endif
|
|
}
|
|
|
|
void QCMake::progressCallback(const char* msg, float percent, void* cd)
|
|
{
|
|
QCMake* self = reinterpret_cast<QCMake*>(cd);
|
|
if (percent >= 0) {
|
|
emit self->progressChanged(QString::fromLocal8Bit(msg), percent);
|
|
} else {
|
|
emit self->outputMessage(QString::fromLocal8Bit(msg));
|
|
}
|
|
QCoreApplication::processEvents();
|
|
}
|
|
|
|
void QCMake::messageCallback(const char* msg, const char* /*title*/,
|
|
bool& /*stop*/, void* cd)
|
|
{
|
|
QCMake* self = reinterpret_cast<QCMake*>(cd);
|
|
emit self->errorMessage(QString::fromLocal8Bit(msg));
|
|
QCoreApplication::processEvents();
|
|
}
|
|
|
|
void QCMake::stdoutCallback(const char* msg, size_t len, void* cd)
|
|
{
|
|
QCMake* self = reinterpret_cast<QCMake*>(cd);
|
|
emit self->outputMessage(QString::fromLocal8Bit(msg, int(len)));
|
|
QCoreApplication::processEvents();
|
|
}
|
|
|
|
void QCMake::stderrCallback(const char* msg, size_t len, void* cd)
|
|
{
|
|
QCMake* self = reinterpret_cast<QCMake*>(cd);
|
|
emit self->outputMessage(QString::fromLocal8Bit(msg, int(len)));
|
|
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;
|
|
}
|