forked from qt-creator/qt-creator
CMake: Keep cmake state in a temporary directory till first build
This avoids creating lots of build directories as the user types in something into the builddirectory line of the build settings. Change-Id: Ib08a0f65e08bce104e4baf9e19fb01730d2f5f08 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
This commit is contained in:
@@ -100,7 +100,7 @@ BuildDirManager::BuildDirManager(const CMakeBuildConfiguration *bc) :
|
|||||||
|
|
||||||
m_reparseTimer.setSingleShot(true);
|
m_reparseTimer.setSingleShot(true);
|
||||||
m_reparseTimer.setInterval(500);
|
m_reparseTimer.setInterval(500);
|
||||||
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::forceReparse);
|
connect(&m_reparseTimer, &QTimer::timeout, this, &BuildDirManager::parse);
|
||||||
|
|
||||||
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
|
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
|
||||||
if (!isParsing())
|
if (!isParsing())
|
||||||
@@ -111,6 +111,7 @@ BuildDirManager::BuildDirManager(const CMakeBuildConfiguration *bc) :
|
|||||||
BuildDirManager::~BuildDirManager()
|
BuildDirManager::~BuildDirManager()
|
||||||
{
|
{
|
||||||
resetData();
|
resetData();
|
||||||
|
delete m_tempDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectExplorer::Kit *BuildDirManager::kit() const
|
const ProjectExplorer::Kit *BuildDirManager::kit() const
|
||||||
@@ -123,6 +124,16 @@ const Utils::FileName BuildDirManager::buildDirectory() const
|
|||||||
return m_buildConfiguration->buildDirectory();
|
return m_buildConfiguration->buildDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Utils::FileName BuildDirManager::workDirectory() const
|
||||||
|
{
|
||||||
|
const Utils::FileName bdir = buildDirectory();
|
||||||
|
if (bdir.exists())
|
||||||
|
return bdir;
|
||||||
|
if (m_tempDir)
|
||||||
|
return Utils::FileName::fromString(m_tempDir->path());
|
||||||
|
return bdir;
|
||||||
|
}
|
||||||
|
|
||||||
const Utils::FileName BuildDirManager::sourceDirectory() const
|
const Utils::FileName BuildDirManager::sourceDirectory() const
|
||||||
{
|
{
|
||||||
return m_buildConfiguration->target()->project()->projectDirectory();
|
return m_buildConfiguration->target()->project()->projectDirectory();
|
||||||
@@ -168,6 +179,21 @@ void BuildDirManager::resetData()
|
|||||||
m_watcher->removePaths(watchedFiles);
|
m_watcher->removePaths(watchedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BuildDirManager::persistCMakeState()
|
||||||
|
{
|
||||||
|
if (!m_tempDir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QDir dir(buildDirectory().toString());
|
||||||
|
dir.mkpath(buildDirectory().toString());
|
||||||
|
|
||||||
|
delete m_tempDir;
|
||||||
|
m_tempDir = nullptr;
|
||||||
|
|
||||||
|
parse();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void BuildDirManager::parse()
|
void BuildDirManager::parse()
|
||||||
{
|
{
|
||||||
CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
|
CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
|
||||||
@@ -177,7 +203,7 @@ void BuildDirManager::parse()
|
|||||||
QTC_ASSERT(!generator.isEmpty(), return);
|
QTC_ASSERT(!generator.isEmpty(), return);
|
||||||
|
|
||||||
// Pop up a dialog asking the user to rerun cmake
|
// Pop up a dialog asking the user to rerun cmake
|
||||||
QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory().toString()));
|
QString cbpFile = CMakeManager::findCbpFile(QDir(workDirectory().toString()));
|
||||||
QFileInfo cbpFileFi(cbpFile);
|
QFileInfo cbpFileFi(cbpFile);
|
||||||
|
|
||||||
if (!cbpFileFi.exists()) {
|
if (!cbpFileFi.exists()) {
|
||||||
@@ -234,7 +260,32 @@ CMakeConfig BuildDirManager::configuration() const
|
|||||||
|
|
||||||
void BuildDirManager::stopProcess()
|
void BuildDirManager::stopProcess()
|
||||||
{
|
{
|
||||||
if (m_cmakeProcess) {
|
if (!m_cmakeProcess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_cmakeProcess->disconnect();
|
||||||
|
|
||||||
|
if (m_cmakeProcess->state() == QProcess::Running) {
|
||||||
|
m_cmakeProcess->terminate();
|
||||||
|
if (!m_cmakeProcess->waitForFinished(500))
|
||||||
|
m_cmakeProcess->kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanUpProcess();
|
||||||
|
|
||||||
|
m_future->reportCanceled();
|
||||||
|
m_future->reportFinished();
|
||||||
|
delete m_future;
|
||||||
|
m_future = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildDirManager::cleanUpProcess()
|
||||||
|
{
|
||||||
|
if (!m_cmakeProcess)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTC_ASSERT(m_cmakeProcess->state() == QProcess::NotRunning, return);
|
||||||
|
|
||||||
m_cmakeProcess->disconnect();
|
m_cmakeProcess->disconnect();
|
||||||
|
|
||||||
if (m_cmakeProcess->state() == QProcess::Running) {
|
if (m_cmakeProcess->state() == QProcess::Running) {
|
||||||
@@ -250,7 +301,6 @@ void BuildDirManager::stopProcess()
|
|||||||
delete m_parser;
|
delete m_parser;
|
||||||
m_parser = nullptr;
|
m_parser = nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void BuildDirManager::extractData()
|
void BuildDirManager::extractData()
|
||||||
{
|
{
|
||||||
@@ -264,7 +314,7 @@ void BuildDirManager::extractData()
|
|||||||
m_watchedFiles.insert(topCMake);
|
m_watchedFiles.insert(topCMake);
|
||||||
|
|
||||||
// Find cbp file
|
// Find cbp file
|
||||||
QString cbpFile = CMakeManager::findCbpFile(buildDirectory().toString());
|
QString cbpFile = CMakeManager::findCbpFile(workDirectory().toString());
|
||||||
if (cbpFile.isEmpty())
|
if (cbpFile.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -301,14 +351,20 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
|
|||||||
const CMakeConfig &config)
|
const CMakeConfig &config)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(tool && tool->isValid(), return);
|
QTC_ASSERT(tool && tool->isValid(), return);
|
||||||
|
|
||||||
QTC_ASSERT(!m_cmakeProcess, return);
|
QTC_ASSERT(!m_cmakeProcess, return);
|
||||||
QTC_ASSERT(!m_parser, return);
|
QTC_ASSERT(!m_parser, return);
|
||||||
QTC_ASSERT(!m_future, return);
|
QTC_ASSERT(!m_future, return);
|
||||||
|
|
||||||
// Make sure m_buildDir exists:
|
// Find a directory to set up into:
|
||||||
const QString buildDirStr = buildDirectory().toString();
|
if (!buildDirectory().exists()) {
|
||||||
QDir bDir = QDir(buildDirStr);
|
if (!m_tempDir)
|
||||||
bDir.mkpath(buildDirStr);
|
m_tempDir = new QTemporaryDir(QDir::tempPath() + QLatin1String("/qtc-cmake-XXXXXX"));
|
||||||
|
QTC_ASSERT(m_tempDir->isValid(), return);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure work directory exists:
|
||||||
|
QTC_ASSERT(workDirectory().exists(), return);
|
||||||
|
|
||||||
m_parser = new CMakeParser;
|
m_parser = new CMakeParser;
|
||||||
QDir source = QDir(sourceDirectory().toString());
|
QDir source = QDir(sourceDirectory().toString());
|
||||||
@@ -328,7 +384,7 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
|
|||||||
const QString srcDir = sourceDirectory().toString();
|
const QString srcDir = sourceDirectory().toString();
|
||||||
|
|
||||||
m_cmakeProcess = new Utils::QtcProcess(this);
|
m_cmakeProcess = new Utils::QtcProcess(this);
|
||||||
m_cmakeProcess->setWorkingDirectory(buildDirStr);
|
m_cmakeProcess->setWorkingDirectory(workDirectory().toString());
|
||||||
m_cmakeProcess->setEnvironment(m_buildConfiguration->environment());
|
m_cmakeProcess->setEnvironment(m_buildConfiguration->environment());
|
||||||
|
|
||||||
connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
|
connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
|
||||||
@@ -349,7 +405,7 @@ void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
|
|||||||
Core::MessageManager::write(tr("Running '%1 %2' in %3.")
|
Core::MessageManager::write(tr("Running '%1 %2' in %3.")
|
||||||
.arg(tool->cmakeExecutable().toUserOutput())
|
.arg(tool->cmakeExecutable().toUserOutput())
|
||||||
.arg(args)
|
.arg(args)
|
||||||
.arg(buildDirectory().toUserOutput()));
|
.arg(workDirectory().toUserOutput()));
|
||||||
|
|
||||||
m_future = new QFutureInterface<void>();
|
m_future = new QFutureInterface<void>();
|
||||||
m_future->setProgressRange(0, 1);
|
m_future->setProgressRange(0, 1);
|
||||||
@@ -370,7 +426,7 @@ void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
|
|||||||
processCMakeOutput();
|
processCMakeOutput();
|
||||||
processCMakeError();
|
processCMakeError();
|
||||||
|
|
||||||
stopProcess();
|
cleanUpProcess();
|
||||||
|
|
||||||
extractData(); // try even if cmake failed...
|
extractData(); // try even if cmake failed...
|
||||||
|
|
||||||
@@ -391,7 +447,7 @@ void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
|
|||||||
|
|
||||||
m_future->reportFinished();
|
m_future->reportFinished();
|
||||||
delete m_future;
|
delete m_future;
|
||||||
m_future = 0;
|
m_future = nullptr;
|
||||||
|
|
||||||
m_hasData = true;
|
m_hasData = true;
|
||||||
emit dataAvailable();
|
emit dataAvailable();
|
||||||
@@ -464,7 +520,7 @@ static CMakeConfigItem::Type fromByteArray(const QByteArray &type) {
|
|||||||
CMakeConfig BuildDirManager::parseConfiguration() const
|
CMakeConfig BuildDirManager::parseConfiguration() const
|
||||||
{
|
{
|
||||||
CMakeConfig result;
|
CMakeConfig result;
|
||||||
const QString cacheFile = QDir(buildDirectory().toString()).absoluteFilePath(QLatin1String("CMakeCache.txt"));
|
const QString cacheFile = QDir(workDirectory().toString()).absoluteFilePath(QLatin1String("CMakeCache.txt"));
|
||||||
QFile cache(cacheFile);
|
QFile cache(cacheFile);
|
||||||
if (!cache.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!cache.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
return CMakeConfig();
|
return CMakeConfig();
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public:
|
|||||||
|
|
||||||
const ProjectExplorer::Kit *kit() const;
|
const ProjectExplorer::Kit *kit() const;
|
||||||
const Utils::FileName buildDirectory() const;
|
const Utils::FileName buildDirectory() const;
|
||||||
|
const Utils::FileName workDirectory() const;
|
||||||
const Utils::FileName sourceDirectory() const;
|
const Utils::FileName sourceDirectory() const;
|
||||||
const CMakeConfig cmakeConfiguration() const;
|
const CMakeConfig cmakeConfiguration() const;
|
||||||
bool isParsing() const;
|
bool isParsing() const;
|
||||||
@@ -76,6 +77,7 @@ public:
|
|||||||
void parse();
|
void parse();
|
||||||
void forceReparse();
|
void forceReparse();
|
||||||
void resetData();
|
void resetData();
|
||||||
|
bool persistCMakeState();
|
||||||
|
|
||||||
bool isProjectFile(const Utils::FileName &fileName) const;
|
bool isProjectFile(const Utils::FileName &fileName) const;
|
||||||
QString projectName() const;
|
QString projectName() const;
|
||||||
@@ -91,6 +93,7 @@ signals:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void stopProcess();
|
void stopProcess();
|
||||||
|
void cleanUpProcess();
|
||||||
void extractData();
|
void extractData();
|
||||||
|
|
||||||
void startCMake(CMakeTool *tool, const QString &generator, const CMakeConfig &config);
|
void startCMake(CMakeTool *tool, const QString &generator, const CMakeConfig &config);
|
||||||
@@ -105,6 +108,7 @@ private:
|
|||||||
|
|
||||||
const CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
const CMakeBuildConfiguration *m_buildConfiguration = nullptr;
|
||||||
Utils::QtcProcess *m_cmakeProcess = nullptr;
|
Utils::QtcProcess *m_cmakeProcess = nullptr;
|
||||||
|
QTemporaryDir *m_tempDir = nullptr;
|
||||||
|
|
||||||
QSet<Utils::FileName> m_watchedFiles;
|
QSet<Utils::FileName> m_watchedFiles;
|
||||||
QString m_projectName;
|
QString m_projectName;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(ProjectExplorer::Target *parent
|
|||||||
connect(this, &CMakeBuildConfiguration::environmentChanged,
|
connect(this, &CMakeBuildConfiguration::environmentChanged,
|
||||||
m_buildDirManager, &BuildDirManager::forceReparse);
|
m_buildDirManager, &BuildDirManager::forceReparse);
|
||||||
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
|
connect(this, &CMakeBuildConfiguration::buildDirectoryChanged,
|
||||||
m_buildDirManager, &BuildDirManager::parse);
|
m_buildDirManager, &BuildDirManager::forceReparse);
|
||||||
connect(target(), &Target::kitChanged, m_buildDirManager, &BuildDirManager::forceReparse);
|
connect(target(), &Target::kitChanged, m_buildDirManager, &BuildDirManager::forceReparse);
|
||||||
|
|
||||||
connect(this, &CMakeBuildConfiguration::parsingStarted, project, &CMakeProject::handleParsingStarted);
|
connect(this, &CMakeBuildConfiguration::parsingStarted, project, &CMakeProject::handleParsingStarted);
|
||||||
@@ -182,6 +182,11 @@ void CMakeBuildConfiguration::resetData()
|
|||||||
m_buildDirManager->resetData();
|
m_buildDirManager->resetData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CMakeBuildConfiguration::persistCMakeState()
|
||||||
|
{
|
||||||
|
return m_buildDirManager->persistCMakeState();
|
||||||
|
}
|
||||||
|
|
||||||
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const
|
QList<ConfigModel::DataItem> CMakeBuildConfiguration::completeCMakeConfiguration() const
|
||||||
{
|
{
|
||||||
if (m_buildDirManager->isParsing())
|
if (m_buildDirManager->isParsing())
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public:
|
|||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
void resetData();
|
void resetData();
|
||||||
|
bool persistCMakeState();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccured(const QString &message);
|
void errorOccured(const QString &message);
|
||||||
|
|||||||
@@ -222,6 +222,37 @@ bool CMakeBuildStep::init(QList<const BuildStep *> &earlierSteps)
|
|||||||
return AbstractProcessStep::init(earlierSteps);
|
return AbstractProcessStep::init(earlierSteps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMakeBuildStep::run(QFutureInterface<bool> &fi)
|
||||||
|
{
|
||||||
|
// Make sure CMake state was written to disk before trying to build:
|
||||||
|
CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
|
||||||
|
if (!bc)
|
||||||
|
bc = qobject_cast<CMakeBuildConfiguration *>(target()->activeBuildConfiguration());
|
||||||
|
QTC_ASSERT(bc, return);
|
||||||
|
|
||||||
|
if (bc->persistCMakeState()) {
|
||||||
|
emit addOutput(tr("Persisting CMake state..."), BuildStep::MessageOutput);
|
||||||
|
|
||||||
|
m_runTrigger = connect(bc, &CMakeBuildConfiguration::dataAvailable,
|
||||||
|
this, [this, &fi]() { runImpl(fi); });
|
||||||
|
m_errorTrigger = connect(bc, &CMakeBuildConfiguration::errorOccured,
|
||||||
|
this, [this, &fi]() {
|
||||||
|
fi.reportResult(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
runImpl(fi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMakeBuildStep::runImpl(QFutureInterface<bool> &fi)
|
||||||
|
{
|
||||||
|
// Do the actual build:
|
||||||
|
disconnect(m_runTrigger);
|
||||||
|
disconnect(m_errorTrigger);
|
||||||
|
|
||||||
|
AbstractProcessStep::run(fi);
|
||||||
|
}
|
||||||
|
|
||||||
BuildStepConfigWidget *CMakeBuildStep::createConfigWidget()
|
BuildStepConfigWidget *CMakeBuildStep::createConfigWidget()
|
||||||
{
|
{
|
||||||
return new CMakeBuildStepConfigWidget(this);
|
return new CMakeBuildStepConfigWidget(this);
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public:
|
|||||||
CMakeBuildConfiguration *targetsActiveBuildConfiguration() const;
|
CMakeBuildConfiguration *targetsActiveBuildConfiguration() const;
|
||||||
|
|
||||||
bool init(QList<const BuildStep *> &earlierSteps) override;
|
bool init(QList<const BuildStep *> &earlierSteps) override;
|
||||||
|
void run(QFutureInterface<bool> &fi) override;
|
||||||
|
|
||||||
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
|
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
|
||||||
bool immutable() const override;
|
bool immutable() const override;
|
||||||
@@ -100,9 +101,14 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void ctor(ProjectExplorer::BuildStepList *bsl);
|
void ctor(ProjectExplorer::BuildStepList *bsl);
|
||||||
|
|
||||||
|
void runImpl(QFutureInterface<bool> &fi);
|
||||||
|
|
||||||
void handleBuildTargetChanges();
|
void handleBuildTargetChanges();
|
||||||
CMakeRunConfiguration *targetsActiveRunConfiguration() const;
|
CMakeRunConfiguration *targetsActiveRunConfiguration() const;
|
||||||
|
|
||||||
|
QMetaObject::Connection m_runTrigger;
|
||||||
|
QMetaObject::Connection m_errorTrigger;
|
||||||
|
|
||||||
QRegExp m_percentProgress;
|
QRegExp m_percentProgress;
|
||||||
QRegExp m_ninjaProgress;
|
QRegExp m_ninjaProgress;
|
||||||
QString m_ninjaProgressString;
|
QString m_ninjaProgressString;
|
||||||
|
|||||||
Reference in New Issue
Block a user