CMake: Do not run a cmake wizard all the time

Do not push the cmake running straight into the face of the user. Do it
in the background instead.

This needs some follow-up patches to become really useful.

Change-Id: I3457178b33e3f14bdeac25005a773d17abb73b65
Reviewed-by: Tim Jenssen <tim.jenssen@theqtcompany.com>
This commit is contained in:
Tobias Hunger
2016-01-20 12:19:16 +01:00
parent d7caae5fa6
commit 859bf2c5ce
22 changed files with 598 additions and 1629 deletions

View File

@@ -0,0 +1,332 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "builddirmanager.h"
#include "cmakekitinformation.h"
#include "cmakeprojectmanager.h"
#include "cmaketool.h"
#include <coreplugin/messagemanager.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/taskhub.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/synchronousprocess.h>
#include <QDateTime>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QRegularExpression>
#include <QSet>
#include <QTemporaryDir>
#include <QTimer>
// --------------------------------------------------------------------
// Helper:
// --------------------------------------------------------------------
namespace CMakeProjectManager {
namespace Internal {
static QStringList toArguments(const CMakeConfig &config) {
return Utils::transform(config, [](const CMakeConfigItem &i) -> QString {
QString a = QString::fromLatin1("-D");
a.append(QString::fromUtf8(i.key));
switch (i.type) {
case CMakeConfigItem::FILEPATH:
a.append(QLatin1String(":FILEPATH="));
break;
case CMakeConfigItem::PATH:
a.append(QLatin1String(":PATH="));
break;
case CMakeConfigItem::BOOL:
a.append(QLatin1String(":BOOL="));
break;
case CMakeConfigItem::STRING:
a.append(QLatin1String(":STRING="));
break;
case CMakeConfigItem::INTERNAL:
a.append(QLatin1String(":INTERNAL="));
break;
}
a.append(QString::fromUtf8(i.value));
return a;
});
}
// --------------------------------------------------------------------
// BuildDirManager:
// --------------------------------------------------------------------
BuildDirManager::BuildDirManager(const Utils::FileName &sourceDir, const ProjectExplorer::Kit *k,
const CMakeConfig &inputConfig, const Utils::Environment &env,
const Utils::FileName &buildDir) :
m_sourceDir(sourceDir),
m_buildDir(buildDir),
m_kit(k),
m_environment(env),
m_inputConfig(inputConfig),
m_watcher(new QFileSystemWatcher(this))
{
QTC_CHECK(!sourceDir.isEmpty());
m_projectName = m_sourceDir.fileName();
if (m_buildDir.isEmpty()) {
m_tempDir = new QTemporaryDir(QLatin1String("cmake-tmp-XXXXXX"));
m_buildDir = Utils::FileName::fromString(m_tempDir->path());
}
QTC_CHECK(!m_buildDir.isEmpty());
QTC_CHECK(k);
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this]() {
if (!isBusy())
forceReparse();
});
QTimer::singleShot(0, this, &BuildDirManager::parse);
}
BuildDirManager::~BuildDirManager()
{
delete m_tempDir;
}
bool BuildDirManager::isBusy() const
{
if (m_cmakeProcess)
return m_cmakeProcess->state() != QProcess::NotRunning;
return false;
}
void BuildDirManager::forceReparse()
{
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
const QString generator = CMakeGeneratorKitInformation::generator(m_kit);
QTC_ASSERT(tool, return);
QTC_ASSERT(!generator.isEmpty(), return);
startCMake(tool, generator, m_inputConfig);
}
void BuildDirManager::parse()
{
CMakeTool *tool = CMakeKitInformation::cmakeTool(m_kit);
const QString generator = CMakeGeneratorKitInformation::generator(m_kit);
QTC_ASSERT(tool, return);
QTC_ASSERT(!generator.isEmpty(), return);
// Pop up a dialog asking the user to rerun cmake
QString cbpFile = CMakeManager::findCbpFile(QDir(m_buildDir.toString()));
QFileInfo cbpFileFi(cbpFile);
if (!cbpFileFi.exists()) {
// Initial create:
startCMake(tool, generator, m_inputConfig);
return;
}
const bool mustUpdate
= Utils::anyOf(m_watchedFiles, [&cbpFileFi](const Utils::FileName &f) {
return f.toFileInfo().lastModified() > cbpFileFi.lastModified();
});
if (mustUpdate) {
startCMake(tool, generator, CMakeConfig());
} else {
extractData();
emit dataAvailable();
}
}
bool BuildDirManager::isProjectFile(const Utils::FileName &fileName) const
{
return m_watchedFiles.contains(fileName);
}
QString BuildDirManager::projectName() const
{
return m_projectName;
}
QList<CMakeBuildTarget> BuildDirManager::buildTargets() const
{
return m_buildTargets;
}
QList<ProjectExplorer::FileNode *> BuildDirManager::files() const
{
return m_files;
}
void BuildDirManager::extractData()
{
const Utils::FileName topCMake
= Utils::FileName::fromString(m_sourceDir.toString() + QLatin1String("/CMakeLists.txt"));
m_projectName = m_sourceDir.fileName();
m_buildTargets.clear();
m_watchedFiles.clear();
m_files.clear();
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
m_watchedFiles.insert(topCMake);
foreach (const QString &file, m_watcher->files())
m_watcher->removePath(file);
// Find cbp file
QString cbpFile = CMakeManager::findCbpFile(m_buildDir.toString());
if (cbpFile.isEmpty())
return;
m_watcher->addPath(cbpFile);
// setFolderName
CMakeCbpParser cbpparser;
// Parsing
if (!cbpparser.parseCbpFile(m_kit, cbpFile, m_sourceDir.toString()))
return;
m_projectName = cbpparser.projectName();
m_files = cbpparser.fileList();
QSet<Utils::FileName> projectFiles;
if (cbpparser.hasCMakeFiles()) {
m_files.append(cbpparser.cmakeFileList());
foreach (const ProjectExplorer::FileNode *node, cbpparser.cmakeFileList())
projectFiles.insert(node->filePath());
} else {
m_files.append(new ProjectExplorer::FileNode(topCMake, ProjectExplorer::ProjectFileType, false));
projectFiles.insert(topCMake);
}
m_watchedFiles = projectFiles;
foreach (const Utils::FileName &f, m_watchedFiles)
m_watcher->addPath(f.toString());
m_buildTargets = cbpparser.buildTargets();
}
void BuildDirManager::startCMake(CMakeTool *tool, const QString &generator,
const CMakeConfig &config)
{
QTC_ASSERT(tool && tool->isValid(), return);
QTC_ASSERT(!m_cmakeProcess, return);
// Make sure m_buildDir exists:
const QString buildDirStr = m_buildDir.toString();
QDir bDir = QDir(buildDirStr);
bDir.mkpath(buildDirStr);
// Always use the sourceDir: If we are triggered because the build directory is getting deleted
// then we are racing against CMakeCache.txt also getting deleted.
const QString srcDir = m_sourceDir.toString();
m_cmakeProcess = new Utils::QtcProcess(this);
m_cmakeProcess->setProcessChannelMode(QProcess::MergedChannels);
m_cmakeProcess->setWorkingDirectory(buildDirStr);
m_cmakeProcess->setEnvironment(m_environment);
connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
this, &BuildDirManager::processCMakeOutput);
connect(m_cmakeProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, &BuildDirManager::cmakeFinished);
QString args;
Utils::QtcProcess::addArg(&args, srcDir);
if (!generator.isEmpty())
Utils::QtcProcess::addArg(&args, QString::fromLatin1("-G%1").arg(generator));
Utils::QtcProcess::addArgs(&args, toArguments(config));
// Clear task cache:
ProjectExplorer::TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
m_toReport.clear();
m_cmakeProcess->setCommand(tool->cmakeExecutable().toString(), args);
m_cmakeProcess->start();
emit parsingStarted();
}
void BuildDirManager::cmakeFinished(int code, QProcess::ExitStatus status)
{
QTC_ASSERT(m_cmakeProcess, return);
// process rest of the output:
while (m_cmakeProcess->canReadLine())
processOutputLine(Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(m_cmakeProcess->readLine())));
QString rest = Utils::SynchronousProcess::normalizeNewlines(QString::fromLocal8Bit(m_cmakeProcess->readAllStandardOutput()));
if (!rest.isEmpty())
processOutputLine(rest);
QTC_CHECK(m_cmakeProcess->readAllStandardOutput().isEmpty());
if (!m_toReport.description.isEmpty())
ProjectExplorer::TaskHub::addTask(m_toReport);
m_toReport.clear();
m_cmakeProcess->deleteLater();
m_cmakeProcess = nullptr;
extractData(); // try even if cmake failed...
if (status != QProcess::NormalExit)
Core::MessageManager::write(tr("*** cmake process crashed!"));
else if (code != 0)
Core::MessageManager::write(tr("*** cmake process exited with exit code %s.").arg(code));
emit dataAvailable();
}
void BuildDirManager::processCMakeOutput()
{
QTC_ASSERT(m_cmakeProcess, return);
while (m_cmakeProcess->canReadLine())
processOutputLine(QString::fromLocal8Bit(m_cmakeProcess->readLine()));
}
void BuildDirManager::processOutputLine(const QString &l)
{
QString line = Utils::SynchronousProcess::normalizeNewlines(l);
while (line.endsWith(QLatin1Char('\n')))
line.chop(1);
Core::MessageManager::write(line);
// Check for errors:
if (m_toReport.type == ProjectExplorer::Task::Unknown) {
m_toReport.category = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM;
} else {
if (line.startsWith(QStringLiteral(" ")) || line.isEmpty()) {
m_toReport.description.append(QStringLiteral("\n") + line);
} else {
ProjectExplorer::TaskHub::addTask(m_toReport);
m_toReport.clear();
}
}
}
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -0,0 +1,116 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#ifndef CMAKE_BUILDDIRMANAGER_H
#define CMAKE_BUILDDIRMANAGER_H
#include "cmakecbpparser.h"
#include "cmakeconfigitem.h"
#include <projectexplorer/task.h>
#include <utils/environment.h>
#include <utils/qtcprocess.h>
#include <utils/fileutils.h>
#include <QByteArray>
#include <QObject>
#include <QSet>
QT_FORWARD_DECLARE_CLASS(QTemporaryDir);
QT_FORWARD_DECLARE_CLASS(QFileSystemWatcher);
namespace ProjectExplorer {
class FileNode;
class Kit;
} // namespace ProjectExplorer
namespace CMakeProjectManager {
class CMakeTool;
namespace Internal {
class BuildDirManager : public QObject
{
Q_OBJECT
public:
BuildDirManager(const Utils::FileName &sourceDir, const ProjectExplorer::Kit *k,
const CMakeConfig &inputConfig, const Utils::Environment &env,
const Utils::FileName &buildDir);
~BuildDirManager() override;
const ProjectExplorer::Kit *kit() const { return m_kit; }
const Utils::FileName buildDirectory() const { return m_buildDir; }
const Utils::FileName sourceDirectory() const { return m_sourceDir; }
bool isBusy() const;
void parse();
void forceReparse();
bool isProjectFile(const Utils::FileName &fileName) const;
QString projectName() const;
QList<CMakeBuildTarget> buildTargets() const;
QList<ProjectExplorer::FileNode *> files() const;
signals:
void parsingStarted() const;
void dataAvailable() const;
void errorOccured(const QString &err) const;
private:
void extractData();
void startCMake(CMakeTool *tool, const QString &generator, const CMakeConfig &config);
void cmakeFinished(int code, QProcess::ExitStatus status);
void processCMakeOutput();
void processOutputLine(const QString &line);
const Utils::FileName m_sourceDir;
Utils::FileName m_buildDir;
const ProjectExplorer::Kit *const m_kit;
Utils::Environment m_environment;
CMakeConfig m_inputConfig;
QTemporaryDir *m_tempDir = nullptr;
Utils::QtcProcess *m_cmakeProcess = nullptr;
QSet<Utils::FileName> m_watchedFiles;
QString m_projectName;
QList<CMakeBuildTarget> m_buildTargets;
QFileSystemWatcher *m_watcher;
QList<ProjectExplorer::FileNode *> m_files;
// For error reporting:
ProjectExplorer::Task m_toReport;
};
} // namespace Internal
} // namespace CMakeProjectManager
#endif // CMAKE_BUILDDIRMANAGER_H

View File

@@ -27,7 +27,6 @@
#include "cmakebuildinfo.h"
#include "cmakebuildstep.h"
#include "cmakeopenprojectwizard.h"
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include "cmakebuildsettingswidget.h"
@@ -230,7 +229,7 @@ CMakeBuildConfiguration *CMakeBuildConfigurationFactory::clone(ProjectExplorer::
{
if (!canClone(parent, source))
return 0;
CMakeBuildConfiguration *old = static_cast<CMakeBuildConfiguration *>(source);
auto old = static_cast<CMakeBuildConfiguration *>(source);
return new CMakeBuildConfiguration(parent, old);
}
@@ -264,7 +263,7 @@ CMakeBuildInfo *CMakeBuildConfigurationFactory::createBuildInfo(const ProjectExp
const QString &sourceDir,
BuildType buildType) const
{
CMakeBuildInfo *info = new CMakeBuildInfo(this);
auto info = new CMakeBuildInfo(this);
info->kitId = k->id();
info->environment = Environment::systemEnvironment();
k->addToEnvironment(info->environment);

View File

@@ -26,15 +26,13 @@
#include "cmakebuildsettingswidget.h"
#include "cmakeproject.h"
#include "cmakebuildconfiguration.h"
#include "cmakebuildinfo.h"
#include "cmakeopenprojectwizard.h"
#include "cmakeprojectmanager.h"
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/target.h>
#include <utils/detailswidget.h>
#include <utils/pathchooser.h>
#include <QFormLayout>
@@ -42,8 +40,7 @@ namespace CMakeProjectManager {
namespace Internal {
CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) :
m_pathLineEdit(new QLineEdit),
m_changeButton(new QPushButton)
m_buildConfiguration(bc)
{
auto vbox = new QVBoxLayout(this);
vbox->setMargin(0);
@@ -58,55 +55,19 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc)
fl->setMargin(0);
fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
auto runCmakeButton = new QPushButton(tr("Run CMake..."));
connect(runCmakeButton, &QAbstractButton::clicked, this, &CMakeBuildSettingsWidget::runCMake);
fl->addRow(tr("Reconfigure project:"), runCmakeButton);
auto project = static_cast<CMakeProject *>(bc->target()->project());
auto buildDirChooser = new Utils::PathChooser;
buildDirChooser->setBaseFileName(project->projectDirectory());
buildDirChooser->setFileName(bc->buildDirectory());
connect(buildDirChooser, &Utils::PathChooser::rawPathChanged, this,
[this, project](const QString &path) {
project->changeBuildDirectory(m_buildConfiguration, path);
});
m_pathLineEdit->setReadOnly(true);
auto hbox = new QHBoxLayout();
hbox->addWidget(m_pathLineEdit);
m_changeButton->setText(tr("&Change"));
connect(m_changeButton, &QAbstractButton::clicked, this,
&CMakeBuildSettingsWidget::openChangeBuildDirectoryDialog);
hbox->addWidget(m_changeButton);
fl->addRow(tr("Build directory:"), hbox);
m_buildConfiguration = bc;
m_pathLineEdit->setText(m_buildConfiguration->rawBuildDirectory().toString());
if (m_buildConfiguration->buildDirectory() == bc->target()->project()->projectDirectory())
m_changeButton->setEnabled(false);
else
m_changeButton->setEnabled(true);
fl->addRow(tr("Build directory:"), buildDirChooser);
setDisplayName(tr("CMake"));
}
void CMakeBuildSettingsWidget::openChangeBuildDirectoryDialog()
{
CMakeBuildInfo info(m_buildConfiguration);
CMakeOpenProjectWizard copw(Core::ICore::mainWindow(), CMakeOpenProjectWizard::ChangeDirectory,
&info);
if (copw.exec() == QDialog::Accepted) {
auto project = static_cast<CMakeProject *>(m_buildConfiguration->target()->project());
project->changeBuildDirectory(m_buildConfiguration, copw.buildDirectory());
m_pathLineEdit->setText(m_buildConfiguration->rawBuildDirectory().toString());
}
}
void CMakeBuildSettingsWidget::runCMake()
{
if (!ProjectExplorer::ProjectExplorerPlugin::saveModifiedFiles())
return;
CMakeBuildInfo info(m_buildConfiguration);
CMakeOpenProjectWizard copw(Core::ICore::mainWindow(), CMakeOpenProjectWizard::WantToUpdate,
&info);
if (copw.exec() == QDialog::Accepted) {
auto project = static_cast<CMakeProject *>(m_buildConfiguration->target()->project());
project->parseCMakeLists();
}
}
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -27,9 +27,6 @@
#include <projectexplorer/namedwidget.h>
QT_FORWARD_DECLARE_CLASS(QLineEdit)
QT_FORWARD_DECLARE_CLASS(QPushButton)
namespace CMakeProjectManager {
namespace Internal {
@@ -42,11 +39,6 @@ public:
CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc);
private:
void openChangeBuildDirectoryDialog();
void runCMake();
QLineEdit *m_pathLineEdit;
QPushButton *m_changeButton;
CMakeBuildConfiguration *m_buildConfiguration = 0;
};

View File

@@ -98,7 +98,7 @@ void CMakeBuildStep::ctor()
setDefaultDisplayName(tr("Make"));
connect(target(), &Target::kitChanged, this, &CMakeBuildStep::cmakeCommandChanged);
connect(static_cast<CMakeProject *>(project()), &CMakeProject::buildTargetsChanged,
connect(static_cast<CMakeProject *>(project()), &CMakeProject::buildDirectoryDataAvailable,
this, &CMakeBuildStep::buildTargetsChanged);
}
@@ -401,7 +401,7 @@ CMakeBuildStepConfigWidget::CMakeBuildStepConfigWidget(CMakeBuildStep *buildStep
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
this, &CMakeBuildStepConfigWidget::updateDetails);
connect(pro, &CMakeProject::buildTargetsChanged, this, &CMakeBuildStepConfigWidget::buildTargetsChanged);
connect(pro, &CMakeProject::buildDirectoryDataAvailable, this, &CMakeBuildStepConfigWidget::buildTargetsChanged);
connect(m_buildStep, &CMakeBuildStep::targetsToBuildChanged, this, &CMakeBuildStepConfigWidget::selectedBuildTargetsChanged);
connect(pro, &CMakeProject::environmentChanged, this, &CMakeBuildStepConfigWidget::updateDetails);
}

View File

@@ -73,10 +73,10 @@ void CMakeEditor::finalizeInitialization()
if (!document->isModified())
return;
InfoBar *infoBar = document->infoBar();
Id infoRunCmake("CMakeEditor.RunCMake");
if (!infoBar->canInfoBeAdded(infoRunCmake))
Id infoRunCMake("CMakeEditor.RunCMake");
if (!infoBar->canInfoBeAdded(infoRunCMake))
return;
InfoBarEntry info(infoRunCmake,
InfoBarEntry info(infoRunCMake,
tr("Changes to cmake files are shown in the project tree after building."),
InfoBarEntry::GlobalSuppressionEnabled);
info.setCustomButtonInfo(tr("Build now"), [document]() {

View File

@@ -1,630 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cmakeprojectconstants.h"
#include "cmakeopenprojectwizard.h"
#include "cmakeprojectmanager.h"
#include "cmaketoolmanager.h"
#include "cmakebuildconfiguration.h"
#include "cmakebuildinfo.h"
#include "cmakekitinformation.h"
#include "cmaketool.h"
#include "generatorinfo.h"
#include <coreplugin/icore.h>
#include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/fancylineedit.h>
#include <utils/historycompleter.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/abi.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <texteditor/fontsettings.h>
#include <remotelinux/remotelinux_constants.h>
#include <QVBoxLayout>
#include <QFormLayout>
#include <QLabel>
#include <QPushButton>
#include <QPlainTextEdit>
#include <QDateTime>
#include <QSettings>
#include <QStringList>
#include <QApplication>
#include <QCheckBox>
#include <QDir>
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
using namespace ProjectExplorer;
///////
// Page Flow:
// Start (No .user file)
// |
// |---> In Source Build --> Page: Tell the user about that
// |--> Already existing cbp file (and new enough) --> Page: Ready to load the project
// |--> Page: Ask for cmd options, run generator
// |---> No in source Build --> Page: Ask the user for the build directory
// |--> Already existing cbp file (and new enough) --> Page: Ready to load the project
// |--> Page: Ask for cmd options, run generator
//////////////
/// CMakeOpenProjectWizard
//////////////
CMakeOpenProjectWizard::CMakeOpenProjectWizard(QWidget *parent,
CMakeOpenProjectWizard::Mode mode,
const CMakeBuildInfo *info) :
Utils::Wizard(parent),
m_sourceDirectory(info->sourceDirectory),
m_environment(info->environment),
m_kit(KitManager::find(info->kitId))
{
CMakeRunPage::Mode rmode;
if (mode == CMakeOpenProjectWizard::NeedToCreate)
rmode = CMakeRunPage::Recreate;
else if (mode == CMakeOpenProjectWizard::WantToUpdate)
rmode = CMakeRunPage::WantToUpdate;
else if (mode == CMakeOpenProjectWizard::NeedToUpdate)
rmode = CMakeRunPage::NeedToUpdate;
else
rmode = CMakeRunPage::ChangeDirectory;
if (mode == CMakeOpenProjectWizard::ChangeDirectory) {
m_buildDirectory = info->buildDirectory.toString();
addPage(new ShadowBuildPage(this, true));
}
if (CMakeToolManager::cmakeTools().isEmpty())
addPage(new NoCMakePage(this));
addPage(new CMakeRunPage(this, rmode, info->buildDirectory.toString(), info->arguments,
m_kit->displayName(), info->displayName));
setWindowTitle(tr("CMake Wizard"));
}
bool CMakeOpenProjectWizard::hasInSourceBuild() const
{
return QFileInfo::exists(m_sourceDirectory + QLatin1String("/CMakeCache.txt"));
}
bool CMakeOpenProjectWizard::compatibleKitExist() const
{
bool preferNinja = CMakeManager::preferNinja();
const QList<Kit *> kitList = KitManager::kits();
foreach (Kit *k, kitList) {
CMakeTool *cmake = CMakeKitInformation::cmakeTool(k);
if (!cmake)
continue;
bool hasCodeBlocksGenerator = cmake->hasCodeBlocksMsvcGenerator();
bool hasNinjaGenerator = cmake->hasCodeBlocksNinjaGenerator();
// OfferNinja and ForceNinja differ in what they return
// but not whether the list is empty or not, which is what we
// are interested in here
QList<GeneratorInfo> infos = GeneratorInfo::generatorInfosFor(k, hasNinjaGenerator,
preferNinja,
hasCodeBlocksGenerator);
if (!infos.isEmpty())
return true;
}
return false;
}
bool CMakeOpenProjectWizard::existsUpToDateXmlFile() const
{
QString cbpFile = CMakeManager::findCbpFile(QDir(buildDirectory()));
if (!cbpFile.isEmpty()) {
// We already have a cbp file
QFileInfo cbpFileInfo(cbpFile);
QFileInfo cmakeListsFileInfo(sourceDirectory() + QLatin1String("/CMakeLists.txt"));
if (cbpFileInfo.lastModified() > cmakeListsFileInfo.lastModified())
return true;
}
return false;
}
QString CMakeOpenProjectWizard::buildDirectory() const
{
return m_buildDirectory;
}
QString CMakeOpenProjectWizard::sourceDirectory() const
{
return m_sourceDirectory;
}
void CMakeOpenProjectWizard::setBuildDirectory(const QString &directory)
{
m_buildDirectory = directory;
}
QString CMakeOpenProjectWizard::arguments() const
{
return m_arguments;
}
void CMakeOpenProjectWizard::setArguments(const QString &args)
{
m_arguments = args;
}
Utils::Environment CMakeOpenProjectWizard::environment() const
{
return m_environment;
}
Kit *CMakeOpenProjectWizard::kit() const
{
return m_kit;
}
void CMakeOpenProjectWizard::setKit(Kit *kit)
{
m_kit = kit;
}
//////
// NoKitPage
/////
NoKitPage::NoKitPage(CMakeOpenProjectWizard *cmakeWizard)
: QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
{
auto layout = new QVBoxLayout;
setLayout(layout);
m_descriptionLabel = new QLabel(this);
m_descriptionLabel->setWordWrap(true);
layout->addWidget(m_descriptionLabel);
m_optionsButton = new QPushButton;
m_optionsButton->setText(Core::ICore::msgShowOptionsDialog());
connect(m_optionsButton, &QAbstractButton::clicked, this, &NoKitPage::showOptions);
auto hbox = new QHBoxLayout;
hbox->addWidget(m_optionsButton);
hbox->addStretch();
layout->addLayout(hbox);
setTitle(tr("Check Kits"));
connect(KitManager::instance(), &KitManager::kitsChanged, this, &NoKitPage::kitsChanged);
kitsChanged();
}
void NoKitPage::kitsChanged()
{
if (isComplete()) {
m_descriptionLabel->setText(tr("There are compatible kits."));
m_optionsButton->setVisible(false);
} else {
m_descriptionLabel->setText(tr("Qt Creator has no kits that are suitable for CMake projects. Please configure a kit."));
m_optionsButton->setVisible(true);
}
emit completeChanged();
}
bool NoKitPage::isComplete() const
{
return m_cmakeWizard->compatibleKitExist();
}
void NoKitPage::initializePage()
{
//if the NoCMakePage was added, we need to recheck if kits exist
kitsChanged();
}
void NoKitPage::showOptions()
{
Core::ICore::showOptionsDialog(ProjectExplorer::Constants::KITS_SETTINGS_PAGE_ID, this);
}
InSourceBuildPage::InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard)
: QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
{
setLayout(new QVBoxLayout);
auto label = new QLabel(this);
label->setWordWrap(true);
label->setText(tr("Qt Creator has detected an <b>in-source-build in %1</b> "
"which prevents shadow builds. Qt Creator will not allow you to change the build directory. "
"If you want a shadow build, clean your source directory and re-open the project.")
.arg(m_cmakeWizard->buildDirectory()));
layout()->addWidget(label);
setTitle(tr("Build Location"));
}
ShadowBuildPage::ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard, bool change)
: QWizardPage(cmakeWizard), m_cmakeWizard(cmakeWizard)
{
auto fl = new QFormLayout;
this->setLayout(fl);
auto label = new QLabel(this);
label->setWordWrap(true);
if (change)
label->setText(tr("Please enter the directory in which you want to build your project.") + QLatin1Char(' '));
else
label->setText(tr("Please enter the directory in which you want to build your project. "
"Qt Creator recommends to not use the source directory for building. "
"This ensures that the source directory remains clean and enables multiple builds "
"with different settings."));
fl->addRow(label);
m_pc = new Utils::PathChooser(this);
m_pc->setBaseDirectory(m_cmakeWizard->sourceDirectory());
m_pc->setPath(m_cmakeWizard->buildDirectory());
m_pc->setExpectedKind(Utils::PathChooser::Directory);
m_pc->setHistoryCompleter(QLatin1String("Cmake.BuildDir.History"));
connect(m_pc, &Utils::PathChooser::rawPathChanged, this, &ShadowBuildPage::buildDirectoryChanged);
fl->addRow(tr("Build directory:"), m_pc);
setTitle(tr("Build Location"));
}
void ShadowBuildPage::buildDirectoryChanged()
{
m_cmakeWizard->setBuildDirectory(m_pc->path());
}
//////
// NoCMakePage
/////
NoCMakePage::NoCMakePage(CMakeOpenProjectWizard *cmakeWizard) : QWizardPage(cmakeWizard)
{
auto layout = new QVBoxLayout;
setLayout(layout);
m_descriptionLabel = new QLabel(this);
m_descriptionLabel->setWordWrap(true);
layout->addWidget(m_descriptionLabel);
m_optionsButton = new QPushButton;
m_optionsButton->setText(Core::ICore::msgShowOptionsDialog());
connect(m_optionsButton, &QAbstractButton::clicked, this, &NoCMakePage::showOptions);
auto hbox = new QHBoxLayout;
hbox->addWidget(m_optionsButton);
hbox->addStretch();
layout->addLayout(hbox);
setTitle(tr("Check CMake Tools"));
connect(CMakeToolManager::instance(), &CMakeToolManager::cmakeToolsChanged,
this, &NoCMakePage::cmakeToolsChanged);
cmakeToolsChanged();
}
void NoCMakePage::cmakeToolsChanged()
{
if (isComplete()) {
m_descriptionLabel->setText(tr("There are CMake Tools registered."));
m_optionsButton->setVisible(false);
} else {
m_descriptionLabel->setText(tr("Qt Creator has no CMake Tools that are required for CMake projects. Please configure at least one."));
m_optionsButton->setVisible(true);
}
emit completeChanged();
}
bool NoCMakePage::isComplete() const
{
return !CMakeToolManager::cmakeTools().isEmpty();
}
void NoCMakePage::showOptions()
{
Core::ICore::showOptionsDialog(Constants::CMAKE_SETTINGSPAGE_ID, this);
}
CMakeRunPage::CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard, Mode mode,
const QString &buildDirectory, const QString &initialArguments,
const QString &kitName, const QString &buildConfigurationName) :
QWizardPage(cmakeWizard),
m_cmakeWizard(cmakeWizard),
m_descriptionLabel(new QLabel(this)),
m_argumentsLineEdit(new Utils::FancyLineEdit(this)),
m_generatorComboBox(new QComboBox(this)),
m_generatorExtraText(new QLabel(this)),
m_runCMake(new QPushButton(this)),
m_output(new QPlainTextEdit(this)),
m_exitCodeLabel(new QLabel(this)),
m_continueCheckBox(new QCheckBox(this)),
m_mode(mode),
m_buildDirectory(buildDirectory),
m_kitName(kitName),
m_buildConfigurationName(buildConfigurationName)
{
auto fl = new QFormLayout;
fl->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
setLayout(fl);
// Description Label
m_descriptionLabel->setWordWrap(true);
fl->addRow(m_descriptionLabel);
// Run CMake Line (with arguments)
m_argumentsLineEdit->setHistoryCompleter(QLatin1String("CMakeArgumentsLineEdit"));
m_argumentsLineEdit->selectAll();
connect(m_argumentsLineEdit, &QLineEdit::returnPressed, this, &CMakeRunPage::runCMake);
fl->addRow(tr("Arguments:"), m_argumentsLineEdit);
fl->addRow(tr("Generator:"), m_generatorComboBox);
fl->addRow(m_generatorExtraText);
m_runCMake->setText(tr("Run CMake"));
connect(m_runCMake, &QAbstractButton::clicked, this, &CMakeRunPage::runCMake);
auto hbox2 = new QHBoxLayout;
hbox2->addStretch(10);
hbox2->addWidget(m_runCMake);
fl->addRow(hbox2);
// Bottom output window
m_output->setReadOnly(true);
// set smaller minimum size to avoid vanishing descriptions if all of the
// above is shown and the dialog not vertically resizing to fit stuff in (Mac)
m_output->setMinimumHeight(15);
QFont f(TextEditor::FontSettings::defaultFixedFontFamily());
f.setStyleHint(QFont::TypeWriter);
m_output->setFont(f);
QSizePolicy pl = m_output->sizePolicy();
pl.setVerticalStretch(1);
m_output->setSizePolicy(pl);
fl->addRow(m_output);
m_exitCodeLabel->setVisible(false);
fl->addRow(m_exitCodeLabel);
m_continueCheckBox->setVisible(false);
m_continueCheckBox->setText(tr("Open project with errors."));
connect(m_continueCheckBox, &QCheckBox::toggled, this, &CMakeRunPage::completeChanged);
fl->addRow(m_continueCheckBox);
setTitle(tr("Run CMake"));
setMinimumSize(600, 400);
m_argumentsLineEdit->setText(initialArguments);
}
QByteArray CMakeRunPage::cachedGeneratorFromFile(const QString &cache)
{
QFile fi(cache);
if (fi.exists()) {
// Cache exists, then read it...
if (fi.open(QIODevice::ReadOnly | QIODevice::Text)) {
while (!fi.atEnd()) {
QByteArray line = fi.readLine();
if (line.startsWith("CMAKE_GENERATOR:INTERNAL=")) {
int splitpos = line.indexOf('=');
if (splitpos != -1) {
QByteArray cachedGenerator = line.mid(splitpos + 1).trimmed();
if (!cachedGenerator.isEmpty())
return cachedGenerator;
}
}
}
}
}
return QByteArray();
}
void CMakeRunPage::initializePage()
{
if (m_mode == CMakeRunPage::NeedToUpdate) {
m_descriptionLabel->setText(tr("The build directory \"%1\" for build configuration \"%2\" "
"for target \"%3\" contains an outdated .cbp file. Qt "
"Creator needs to update this file by running CMake. "
"You can add command line arguments below. Note that "
"CMake remembers command line arguments from the "
"previous runs.")
.arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName)
.arg(m_kitName));
} else if (m_mode == CMakeRunPage::Recreate) {
m_descriptionLabel->setText(tr("The directory \"%1\" specified in build configuration \"%2\", "
"for target \"%3\" does not contain a .cbp file. "
"Qt Creator needs to recreate this file by running CMake. "
"Some projects require command line arguments to "
"the initial CMake call. Note that CMake remembers command "
"line arguments from the previous runs.")
.arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName)
.arg(m_kitName));
} else if (m_mode == CMakeRunPage::ChangeDirectory) {
m_buildDirectory = m_cmakeWizard->buildDirectory();
m_descriptionLabel->setText(tr("Qt Creator needs to run CMake in the new build directory. "
"Some projects require command line arguments to the "
"initial CMake call."));
} else if (m_mode == CMakeRunPage::WantToUpdate) {
m_descriptionLabel->setText(tr("Refreshing the .cbp file in \"%1\" for build configuration \"%2\" "
"for target \"%3\".")
.arg(QDir::toNativeSeparators(m_buildDirectory))
.arg(m_buildConfigurationName)
.arg(m_kitName));
}
// Build the list of generators/toolchains we want to offer
m_generatorComboBox->clear();
bool preferNinja = CMakeManager::preferNinja();
QList<GeneratorInfo> infos;
CMakeTool *cmake = CMakeKitInformation::cmakeTool(m_cmakeWizard->kit());
if (cmake) {
// Note: We don't compare the actually cached generator to what is set in the buildconfiguration
// We assume that the buildconfiguration is correct
infos = GeneratorInfo::generatorInfosFor(m_cmakeWizard->kit(), true, preferNinja, true);
}
foreach (const GeneratorInfo &info, infos)
m_generatorComboBox->addItem(info.displayName(), qVariantFromValue(info));
}
bool CMakeRunPage::validatePage()
{
int index = m_generatorComboBox->currentIndex();
if (index == -1)
return false;
GeneratorInfo generatorInfo = m_generatorComboBox->itemData(index).value<GeneratorInfo>();
m_cmakeWizard->setKit(generatorInfo.kit());
return QWizardPage::validatePage();
}
void CMakeRunPage::runCMake()
{
QTC_ASSERT(!m_cmakeProcess, return);
m_haveCbpFile = false;
Utils::Environment env = m_cmakeWizard->environment();
int index = m_generatorComboBox->currentIndex();
if (index == -1) {
m_output->appendPlainText(tr("No generator selected."));
return;
}
GeneratorInfo generatorInfo = m_generatorComboBox->itemData(index).value<GeneratorInfo>();
m_cmakeWizard->setKit(generatorInfo.kit());
m_runCMake->setEnabled(false);
m_argumentsLineEdit->setEnabled(false);
m_generatorComboBox->setEnabled(false);
m_output->clear();
CMakeTool *cmake = CMakeKitInformation::cmakeTool(generatorInfo.kit());
if (cmake && cmake->isValid()) {
m_cmakeProcess = new Utils::QtcProcess();
connect(m_cmakeProcess, &QProcess::readyReadStandardOutput,
this, &CMakeRunPage::cmakeReadyReadStandardOutput);
connect(m_cmakeProcess, &QProcess::readyReadStandardError,
this, &CMakeRunPage::cmakeReadyReadStandardError);
connect(m_cmakeProcess, static_cast<void(QProcess::*)(int)>(&QProcess::finished),
this, &CMakeRunPage::cmakeFinished);
QString arguments = m_argumentsLineEdit->text();
Utils::QtcProcess::addArg(&arguments, QString::fromLatin1(generatorInfo.generatorArgument()));
const QString preloadCache = generatorInfo.preLoadCacheFileArgument();
if (!preloadCache.isEmpty())
Utils::QtcProcess::addArg(&arguments, preloadCache);
m_output->appendHtml(tr("<b>Running: '%1' with arguments '%2' in '%3'.</b><br>")
.arg(cmake->cmakeExecutable().toUserOutput())
.arg(arguments)
.arg(QDir::toNativeSeparators(m_buildDirectory)));
CMakeManager::createXmlFile(m_cmakeProcess, cmake->cmakeExecutable().toString(),
arguments, m_cmakeWizard->sourceDirectory(),
m_buildDirectory, env);
} else {
m_runCMake->setEnabled(true);
m_argumentsLineEdit->setEnabled(true);
m_generatorComboBox->setEnabled(true);
m_output->appendPlainText(tr("Selected kit has no valid CMake executable specified."));
}
}
static QColor mix_colors(const QColor &a, const QColor &b)
{
return QColor((a.red() + 2 * b.red()) / 3, (a.green() + 2 * b.green()) / 3,
(a.blue() + 2* b.blue()) / 3, (a.alpha() + 2 * b.alpha()) / 3);
}
void CMakeRunPage::cmakeReadyReadStandardOutput()
{
QTextCursor cursor(m_output->document());
cursor.movePosition(QTextCursor::End);
QTextCharFormat tf;
QFont font = m_output->font();
tf.setFont(font);
tf.setForeground(m_output->palette().color(QPalette::Text));
cursor.insertText(QString::fromLocal8Bit(m_cmakeProcess->readAllStandardOutput()), tf);
}
void CMakeRunPage::cmakeReadyReadStandardError()
{
QTextCursor cursor(m_output->document());
cursor.movePosition(QTextCursor::End);
QTextCharFormat tf;
QFont font = m_output->font();
QFont boldFont = font;
boldFont.setBold(true);
tf.setFont(boldFont);
tf.setForeground(mix_colors(m_output->palette().color(QPalette::Text), QColor(Qt::red)));
cursor.insertText(QString::fromLocal8Bit(m_cmakeProcess->readAllStandardError()), tf);
}
void CMakeRunPage::cmakeFinished()
{
m_runCMake->setEnabled(true);
m_argumentsLineEdit->setEnabled(true);
m_generatorComboBox->setEnabled(true);
if (m_cmakeProcess->exitCode() != 0) {
m_exitCodeLabel->setVisible(true);
m_exitCodeLabel->setText(tr("CMake exited with errors. Please check CMake output."));
static_cast<Utils::HistoryCompleter *>(m_argumentsLineEdit->completer())->removeHistoryItem(0);
m_haveCbpFile = false;
m_continueCheckBox->setVisible(true);
} else {
m_exitCodeLabel->setVisible(false);
m_continueCheckBox->setVisible(false);
m_haveCbpFile = true;
}
m_cmakeProcess->deleteLater();
m_cmakeProcess = 0;
m_cmakeWizard->setArguments(m_argumentsLineEdit->text());
emit completeChanged();
}
void CMakeRunPage::cleanupPage()
{
m_output->clear();
m_haveCbpFile = false;
m_exitCodeLabel->setVisible(false);
emit completeChanged();
}
bool CMakeRunPage::isComplete() const
{
int index = m_generatorComboBox->currentIndex();
return index != -1 && (m_haveCbpFile || m_continueCheckBox->isChecked());
}

View File

@@ -1,194 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmakebuildconfiguration.h"
#include "cmakebuildinfo.h"
#include <utils/environment.h>
#include <utils/wizard.h>
#include <utils/qtcprocess.h>
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <QPushButton>
#include <QComboBox>
#include <QLineEdit>
#include <QLabel>
#include <QPlainTextEdit>
QT_BEGIN_NAMESPACE
class QCheckBox;
QT_END_NAMESPACE
namespace Utils {
class FancyLineEdit;
class PathChooser;
}
namespace ProjectExplorer { class Kit; }
namespace CMakeProjectManager {
namespace Internal {
class CMakeManager;
class CMakeOpenProjectWizard : public Utils::Wizard
{
Q_OBJECT
public:
enum Mode {
Nothing,
NeedToCreate,
NeedToUpdate,
WantToUpdate,
ChangeDirectory
};
/// used to update if we have already a .user file
/// recreates or updates the cbp file
/// Also used to change the build directory of one buildconfiguration or create a new buildconfiguration
CMakeOpenProjectWizard(QWidget *parent, Mode mode, const CMakeBuildInfo *info);
QString buildDirectory() const;
QString sourceDirectory() const;
void setBuildDirectory(const QString &directory);
QString arguments() const;
void setArguments(const QString &args);
Utils::Environment environment() const;
ProjectExplorer::Kit *kit() const;
void setKit(ProjectExplorer::Kit *kit);
bool existsUpToDateXmlFile() const;
bool compatibleKitExist() const;
private:
bool hasInSourceBuild() const;
QString m_buildDirectory;
QString m_sourceDirectory;
QString m_arguments;
Utils::Environment m_environment;
ProjectExplorer::Kit *m_kit;
};
class NoKitPage : public QWizardPage
{
Q_OBJECT
public:
NoKitPage(CMakeOpenProjectWizard *cmakeWizard);
bool isComplete() const override;
void initializePage() override;
private:
void kitsChanged();
void showOptions();
QLabel *m_descriptionLabel;
QPushButton *m_optionsButton;
CMakeOpenProjectWizard *m_cmakeWizard;
};
class InSourceBuildPage : public QWizardPage
{
Q_OBJECT
public:
InSourceBuildPage(CMakeOpenProjectWizard *cmakeWizard);
private:
CMakeOpenProjectWizard *m_cmakeWizard;
};
class ShadowBuildPage : public QWizardPage
{
Q_OBJECT
public:
explicit ShadowBuildPage(CMakeOpenProjectWizard *cmakeWizard, bool change = false);
private:
void buildDirectoryChanged();
CMakeOpenProjectWizard *m_cmakeWizard;
Utils::PathChooser *m_pc;
};
class NoCMakePage : public QWizardPage
{
Q_OBJECT
public:
NoCMakePage(CMakeOpenProjectWizard *cmakeWizard);
bool isComplete() const override;
private:
void cmakeToolsChanged();
void showOptions();
QLabel *m_descriptionLabel;
QPushButton *m_optionsButton;
};
class CMakeRunPage : public QWizardPage
{
Q_OBJECT
public:
enum Mode { NeedToUpdate, Recreate, ChangeDirectory, WantToUpdate };
explicit CMakeRunPage(CMakeOpenProjectWizard *cmakeWizard, Mode mode,
const QString &buildDirectory,
const QString &initialArguments,
const QString &kitName,
const QString &buildConfigurationName);
void initializePage() override;
bool validatePage() override;
void cleanupPage() override;
bool isComplete() const override;
private:
void runCMake();
void cmakeFinished();
void cmakeReadyReadStandardOutput();
void cmakeReadyReadStandardError();
QByteArray cachedGeneratorFromFile(const QString &cache);
CMakeOpenProjectWizard *m_cmakeWizard;
QLabel *m_descriptionLabel;
Utils::FancyLineEdit *m_argumentsLineEdit;
QComboBox *m_generatorComboBox;
QLabel *m_generatorExtraText;
QPushButton *m_runCMake;
QPlainTextEdit *m_output;
QLabel *m_exitCodeLabel;
QCheckBox *m_continueCheckBox;
Utils::QtcProcess *m_cmakeProcess = 0;
bool m_haveCbpFile = false;
Mode m_mode;
QString m_buildDirectory;
QString m_kitName;
QString m_buildConfigurationName;
};
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -1,86 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cmakepreloadcachekitconfigwidget.h"
#include "cmakepreloadcachekitinformation.h"
#include <projectexplorer/kit.h>
#include <QLineEdit>
namespace CMakeProjectManager {
namespace Internal {
CMakePreloadCacheKitConfigWidget::CMakePreloadCacheKitConfigWidget(ProjectExplorer::Kit *k, const ProjectExplorer::KitInformation *ki) :
ProjectExplorer::KitConfigWidget(k, ki),
m_lineEdit(new QLineEdit)
{
refresh();
m_lineEdit->setToolTip(toolTip());
connect(m_lineEdit, &QLineEdit::textEdited,
this, &CMakePreloadCacheKitConfigWidget::preloadFileWasChanged);
}
CMakePreloadCacheKitConfigWidget::~CMakePreloadCacheKitConfigWidget()
{
delete m_lineEdit;
}
QWidget *CMakePreloadCacheKitConfigWidget::mainWidget() const
{
return m_lineEdit;
}
QString CMakePreloadCacheKitConfigWidget::displayName() const
{
return tr("CMake preload file:");
}
QString CMakePreloadCacheKitConfigWidget::toolTip() const
{
return tr("The preload cache file to use when running cmake on the project.<br>"
"This setting is ignored when using other build systems.");
}
void CMakePreloadCacheKitConfigWidget::makeReadOnly()
{
m_lineEdit->setEnabled(false);
}
void CMakePreloadCacheKitConfigWidget::refresh()
{
if (!m_ignoreChange)
m_lineEdit->setText(CMakePreloadCacheKitInformation::preloadCacheFile(m_kit).toUserOutput());
}
void CMakePreloadCacheKitConfigWidget::preloadFileWasChanged(const QString &text)
{
m_ignoreChange = true;
m_kit->setValue(CMakePreloadCacheKitInformation::id(), text);
m_ignoreChange = false;
}
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -1,60 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <projectexplorer/kitconfigwidget.h>
QT_BEGIN_NAMESPACE
class QLineEdit;
QT_END_NAMESPACE
namespace CMakeProjectManager {
namespace Internal {
class CMakePreloadCacheKitConfigWidget : public ProjectExplorer::KitConfigWidget
{
Q_OBJECT
public:
CMakePreloadCacheKitConfigWidget(ProjectExplorer::Kit *k, const ProjectExplorer::KitInformation *ki);
~CMakePreloadCacheKitConfigWidget() override;
QWidget *mainWidget() const override;
QString displayName() const override;
QString toolTip() const override;
void makeReadOnly() override;
void refresh() override;
private:
void preloadFileWasChanged(const QString &text);
QLineEdit *m_lineEdit = nullptr;
bool m_ignoreChange = false;
};
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -1,99 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 Canonical Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "cmakepreloadcachekitinformation.h"
#include "cmakepreloadcachekitconfigwidget.h"
#include "cmaketoolmanager.h"
#include "cmaketool.h"
#include <utils/qtcassert.h>
#include <projectexplorer/task.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <QDebug>
using namespace ProjectExplorer;
namespace CMakeProjectManager {
CMakePreloadCacheKitInformation::CMakePreloadCacheKitInformation()
{
setObjectName(QLatin1String("CMakePreloadCacheKitInformation"));
setId(CMakePreloadCacheKitInformation::id());
setPriority(18000);
}
Core::Id CMakePreloadCacheKitInformation::id()
{
return "CMakeProjectManager.CMakePreloadCacheKitInformation";
}
QVariant CMakePreloadCacheKitInformation::defaultValue(const Kit *) const
{
return QString();
}
QList<Task> CMakePreloadCacheKitInformation::validate(const Kit *k) const
{
Q_UNUSED(k);
return QList<Task>();
}
void CMakePreloadCacheKitInformation::setup(Kit *k)
{
Q_UNUSED(k);
}
void CMakePreloadCacheKitInformation::fix(Kit *k)
{
Q_UNUSED(k);
}
KitInformation::ItemList CMakePreloadCacheKitInformation::toUserOutput(const Kit *k) const
{
return ItemList() << qMakePair(tr("CMake Preload"), k->value(id()).toString());
}
KitConfigWidget *CMakePreloadCacheKitInformation::createConfigWidget(Kit *k) const
{
return new Internal::CMakePreloadCacheKitConfigWidget(k, this);
}
void CMakePreloadCacheKitInformation::setPreloadCacheFile(Kit *k, const Utils::FileName &preload)
{
if (!k)
return;
k->setValue(CMakePreloadCacheKitInformation::id(), preload.toString());
}
Utils::FileName CMakePreloadCacheKitInformation::preloadCacheFile(const Kit *k)
{
if (!k)
return Utils::FileName();
return Utils::FileName::fromString(k->value(CMakePreloadCacheKitInformation::id()).toString());
}
} // namespace CMakeProjectManager

View File

@@ -1,54 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 Canonical Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmake_global.h"
#include <projectexplorer/kitmanager.h>
namespace CMakeProjectManager {
class CMAKE_EXPORT CMakePreloadCacheKitInformation : public ProjectExplorer::KitInformation
{
Q_OBJECT
public:
CMakePreloadCacheKitInformation();
static Core::Id id();
// KitInformation interface
QVariant defaultValue(const ProjectExplorer::Kit *) const override;
QList<ProjectExplorer::Task> validate(const ProjectExplorer::Kit *k) const override;
void setup(ProjectExplorer::Kit *k) override;
void fix(ProjectExplorer::Kit *k) override;
ItemList toUserOutput(const ProjectExplorer::Kit *k) const override;
ProjectExplorer::KitConfigWidget *createConfigWidget(ProjectExplorer::Kit *k) const override;
static void setPreloadCacheFile(ProjectExplorer::Kit *k, const Utils::FileName &preload);
static Utils::FileName preloadCacheFile(const ProjectExplorer::Kit *k);
};
} // namespace CMakeProjectManager

View File

@@ -25,47 +25,45 @@
#include "cmakeproject.h"
#include "builddirmanager.h"
#include "cmakebuildconfiguration.h"
#include "cmakebuildstep.h"
#include "cmakekitinformation.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectnodes.h"
#include "cmakerunconfiguration.h"
#include "cmakeopenprojectwizard.h"
#include "cmakecbpparser.h"
#include "cmakefile.h"
#include "cmakeprojectmanager.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildmanager.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/deployconfiguration.h>
#include <projectexplorer/deploymentdata.h>
#include <qtsupport/customexecutablerunconfiguration.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/uicodemodelsupport.h>
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
#include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppmodelmanager.h>
#include <cpptools/projectinfo.h>
#include <cpptools/projectpartbuilder.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deployconfiguration.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <projectexplorer/toolchain.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/customexecutablerunconfiguration.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/uicodemodelsupport.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <utils/hostosinfo.h>
#include <coreplugin/icore.h>
#include <coreplugin/infobar.h>
#include <coreplugin/editormanager/editormanager.h>
#include <QDebug>
#include <QDir>
#include <QFileSystemWatcher>
#include <QTemporaryDir>
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
@@ -74,7 +72,6 @@ using namespace Utils;
// QtCreator CMake Generator wishlist:
// Which make targets we need to build to get all executables
// What is the make we need to call
// What is the actual compiler executable
// DEFINES
@@ -84,8 +81,7 @@ using namespace Utils;
/*!
\class CMakeProject
*/
CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName) :
m_watcher(new QFileSystemWatcher(this))
CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName)
{
setId(Constants::CMAKEPROJECT_ID);
setProjectManager(manager);
@@ -96,56 +92,59 @@ CMakeProject::CMakeProject(CMakeManager *manager, const FileName &fileName) :
rootProjectNode()->setDisplayName(fileName.parentDir().fileName());
connect(this, &CMakeProject::buildTargetsChanged, this, &CMakeProject::updateRunConfigurations);
connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &CMakeProject::fileChanged);
connect(this, &CMakeProject::buildDirectoryDataAvailable, this, &CMakeProject::updateRunConfigurations);
connect(this, &Project::activeTargetChanged, this, &CMakeProject::activeTargetHasChanged);
connect(this, &CMakeProject::environmentChanged, this, [this]() {
BuildConfiguration *bc = nullptr;
if (activeTarget())
bc = activeTarget()->activeBuildConfiguration();
changeActiveBuildConfiguration(bc); // Does a clean reset of the builddirmanager
});
connect(this, &Project::addedTarget, this, [this](Target *t) {
connect(t, &Target::kitChanged, this, &CMakeProject::handleKitChanges);
});
}
CMakeProject::~CMakeProject()
{
setRootProjectNode(nullptr);
m_codeModelFuture.cancel();
}
void CMakeProject::fileChanged(const QString &fileName)
{
Q_UNUSED(fileName)
parseCMakeLists();
delete m_buildDirManager;
}
void CMakeProject::changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *bc)
{
if (!bc)
return;
if (m_buildDirManager) {
m_buildDirManager->disconnect();
m_buildDirManager->deleteLater();
}
m_buildDirManager = nullptr;
CMakeBuildConfiguration *cmakebc = static_cast<CMakeBuildConfiguration *>(bc);
Kit *k = nullptr;
CMakeConfig config;
Utils::FileName buildDir;
// Pop up a dialog asking the user to rerun cmake
QString cbpFile = CMakeManager::findCbpFile(QDir(bc->buildDirectory().toString()));
QFileInfo cbpFileFi(cbpFile);
CMakeOpenProjectWizard::Mode mode = CMakeOpenProjectWizard::Nothing;
if (!cbpFileFi.exists()) {
mode = CMakeOpenProjectWizard::NeedToCreate;
CMakeBuildConfiguration *cmakebc = qobject_cast<CMakeBuildConfiguration *>(bc);
if (!cmakebc) {
k = KitManager::defaultKit();
config = CMakeConfigurationKitInformation::configuration(k);
} else {
foreach (const FileName &file, m_watchedFiles) {
if (file.toFileInfo().lastModified() > cbpFileFi.lastModified()) {
mode = CMakeOpenProjectWizard::NeedToUpdate;
break;
}
}
k = cmakebc->target()->kit();
// FIXME: Fill config with data from cmakebc!
buildDir = cmakebc->buildDirectory();
}
if (mode != CMakeOpenProjectWizard::Nothing) {
CMakeBuildInfo info(cmakebc);
CMakeOpenProjectWizard copw(Core::ICore::mainWindow(), mode, &info);
if (copw.exec() == QDialog::Accepted)
cmakebc->setInitialArguments(QString());
if (k) {
m_buildDirManager = new Internal::BuildDirManager(projectDirectory(), k, config,
cmakebc->environment(), buildDir);
connect(m_buildDirManager, &BuildDirManager::parsingStarted,
this, &CMakeProject::parsingStarted);
connect(m_buildDirManager, &BuildDirManager::dataAvailable,
this, &CMakeProject::parseCMakeOutput);
}
// reparse
parseCMakeLists();
}
void CMakeProject::activeTargetWasChanged(Target *target)
void CMakeProject::activeTargetHasChanged(Target *target)
{
if (m_activeTarget) {
disconnect(m_activeTarget, &Target::activeBuildConfigurationChanged,
@@ -165,7 +164,16 @@ void CMakeProject::activeTargetWasChanged(Target *target)
void CMakeProject::changeBuildDirectory(CMakeBuildConfiguration *bc, const QString &newBuildDirectory)
{
bc->setBuildDirectory(FileName::fromString(newBuildDirectory));
parseCMakeLists();
if (activeTarget() && activeTarget()->activeBuildConfiguration() == bc)
changeActiveBuildConfiguration(bc);
}
void CMakeProject::handleKitChanges()
{
const Target *t = qobject_cast<Target *>(sender());
if (t && t != activeTarget())
return;
changeActiveBuildConfiguration(t->activeBuildConfiguration()); // force proper refresh
}
QStringList CMakeProject::getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QByteArray *cachedBuildNinja)
@@ -238,88 +246,30 @@ QStringList CMakeProject::getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QB
return QStringList();
}
bool CMakeProject::parseCMakeLists()
void CMakeProject::parseCMakeOutput()
{
QTC_ASSERT(activeTarget() && activeTarget()->activeBuildConfiguration(), return false);
QTC_ASSERT(m_buildDirManager, return);
QTC_ASSERT(activeTarget() && activeTarget()->activeBuildConfiguration(), return);
CMakeBuildConfiguration *activeBC = static_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
foreach (Core::IDocument *document, Core::DocumentModel::openedDocuments())
if (isProjectFile(document->filePath()))
document->infoBar()->removeInfo("CMakeEditor.RunCMake");
// Find cbp file
QString cbpFile = CMakeManager::findCbpFile(activeBC->buildDirectory().toString());
auto activeBC = static_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
if (cbpFile.isEmpty()) {
emit buildTargetsChanged();
return false;
}
rootProjectNode()->setDisplayName(m_buildDirManager->projectName());
Kit *k = activeTarget()->kit();
// setFolderName
rootProjectNode()->setDisplayName(QFileInfo(cbpFile).completeBaseName());
CMakeCbpParser cbpparser;
// Parsing
//qDebug()<<"Parsing file "<<cbpFile;
if (!cbpparser.parseCbpFile(k,cbpFile, projectDirectory().toString())) {
// TODO report error
emit buildTargetsChanged();
return false;
}
foreach (const QString &file, m_watcher->files())
if (file != cbpFile)
m_watcher->removePath(file);
// how can we ensure that it is completely written?
m_watcher->addPath(cbpFile);
rootProjectNode()->setDisplayName(cbpparser.projectName());
//qDebug()<<"Building Tree";
QList<ProjectExplorer::FileNode *> fileList = cbpparser.fileList();
QSet<FileName> projectFiles;
if (cbpparser.hasCMakeFiles()) {
fileList.append(cbpparser.cmakeFileList());
foreach (const ProjectExplorer::FileNode *node, cbpparser.cmakeFileList())
projectFiles.insert(node->filePath());
} else {
// Manually add the CMakeLists.txt file
FileName cmakeListTxt = projectDirectory().appendPath(QLatin1String("CMakeLists.txt"));
bool generated = false;
fileList.append(new ProjectExplorer::FileNode(cmakeListTxt, ProjectExplorer::ProjectFileType, generated));
projectFiles.insert(cmakeListTxt);
}
m_watchedFiles = projectFiles;
m_files.clear();
foreach (ProjectExplorer::FileNode *fn, fileList)
m_files.append(fn->filePath().toString());
m_files.sort();
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), fileList);
//qDebug()<<"Adding Targets";
m_buildTargets = cbpparser.buildTargets();
// qDebug()<<"Printing targets";
// foreach (CMakeBuildTarget ct, m_buildTargets) {
// qDebug()<<ct.title<<" with executable:"<<ct.executable;
// qDebug()<<"WD:"<<ct.workingDirectory;
// qDebug()<<ct.makeCommand<<ct.makeCleanCommand;
// qDebug()<<"";
// }
buildTree(static_cast<CMakeProjectNode *>(rootProjectNode()), m_buildDirManager->files());
updateApplicationAndDeploymentTargets();
createUiCodeModelSupport();
ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(m_buildDirManager->kit());
if (!tc) {
emit buildTargetsChanged();
emit buildDirectoryDataAvailable(activeBC);
emit fileListChanged();
return true;
return;
}
CppTools::CppModelManager *modelmanager = CppTools::CppModelManager::instance();
@@ -327,7 +277,7 @@ bool CMakeProject::parseCMakeLists()
CppTools::ProjectPartBuilder ppBuilder(pinfo);
CppTools::ProjectPart::QtVersion activeQtVersion = CppTools::ProjectPart::NoQt;
if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k)) {
if (QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(m_buildDirManager->kit())) {
if (qtVersion->qtVersion() < QtSupport::QtVersionNumber(5,0,0))
activeQtVersion = CppTools::ProjectPart::Qt4;
else
@@ -337,7 +287,7 @@ bool CMakeProject::parseCMakeLists()
ppBuilder.setQtVersion(activeQtVersion);
QByteArray cachedBuildNinja;
foreach (const CMakeBuildTarget &cbt, m_buildTargets) {
foreach (const CMakeBuildTarget &cbt, buildTargets()) {
// This explicitly adds -I. to the include paths
QStringList includePaths = cbt.includeFiles;
includePaths += projectDirectory().toString();
@@ -358,12 +308,10 @@ bool CMakeProject::parseCMakeLists()
m_codeModelFuture = modelmanager->updateProjectInfo(pinfo);
emit displayNameChanged();
emit buildTargetsChanged();
emit buildDirectoryDataAvailable(activeBC);
emit fileListChanged();
emit activeBC->emitBuildTypeChanged();
return true;
}
bool CMakeProject::needsConfiguration() const
@@ -386,30 +334,45 @@ bool CMakeProject::supportsKit(Kit *k, QString *errorMessage) const
return true;
}
void CMakeProject::runCMake()
{
if (m_buildDirManager && !m_buildDirManager->isBusy())
m_buildDirManager->forceReparse();
}
bool CMakeProject::isParsing() const
{
return m_buildDirManager && m_buildDirManager->isBusy();
}
bool CMakeProject::isProjectFile(const FileName &fileName)
{
return m_watchedFiles.contains(fileName);
if (!m_buildDirManager)
return false;
return m_buildDirManager->isProjectFile(fileName);
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const
{
return m_buildTargets;
if (!m_buildDirManager)
return QList<CMakeBuildTarget>();
return m_buildDirManager->buildTargets();
}
QStringList CMakeProject::buildTargetTitles(bool runnable) const
{
const QList<CMakeBuildTarget> targets
= runnable ? Utils::filtered(m_buildTargets,
= runnable ? Utils::filtered(buildTargets(),
[](const CMakeBuildTarget &ct) {
return !ct.executable.isEmpty() && ct.targetType == ExecutableType;
})
: m_buildTargets;
: buildTargets();
return Utils::transform(targets, [](const CMakeBuildTarget &ct) { return ct.title; });
}
bool CMakeProject::hasBuildTarget(const QString &title) const
{
return Utils::anyOf(m_buildTargets, [title](const CMakeBuildTarget &ct) { return ct.title == title; });
return Utils::anyOf(buildTargets(), [title](const CMakeBuildTarget &ct) { return ct.title == title; });
}
void CMakeProject::gatherFileNodes(ProjectExplorer::FolderNode *parent, QList<ProjectExplorer::FileNode *> &list)
@@ -442,7 +405,6 @@ void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::
// add added nodes
foreach (ProjectExplorer::FileNode *fn, added) {
// qDebug()<<"added"<<fn->path();
// Get relative path to rootNode
QString parentDir = fn->filePath().toFileInfo().absolutePath();
ProjectExplorer::FolderNode *folder = findOrCreateFolder(rootNode, parentDir);
@@ -452,7 +414,6 @@ void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::
// remove old file nodes and check whether folder nodes can be removed
foreach (ProjectExplorer::FileNode *fn, deleted) {
ProjectExplorer::FolderNode *parent = fn->parentFolderNode();
// qDebug()<<"removed"<<fn->path();
parent->removeFileNodes(QList<ProjectExplorer::FileNode *>() << fn);
// Check for empty parent
while (parent->subFolderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
@@ -514,44 +475,13 @@ Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *er
if (result != RestoreResult::Ok)
return result;
bool hasUserFile = activeTarget();
if (!hasUserFile) {
// Nothing to do, the target setup page will show up
} else {
// We have a user file, but we could still be missing the cbp file
// or simply run createXml with the saved settings
CMakeBuildConfiguration *activeBC = qobject_cast<CMakeBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
if (!activeBC) {
*errorMessage = tr("Internal Error: No build configuration found in settings file.");
return RestoreResult::Error;
}
QString cbpFile = CMakeManager::findCbpFile(QDir(activeBC->buildDirectory().toString()));
QFileInfo cbpFileFi(cbpFile);
CMakeOpenProjectWizard::Mode mode = CMakeOpenProjectWizard::Nothing;
if (!cbpFileFi.exists())
mode = CMakeOpenProjectWizard::NeedToCreate;
else if (cbpFileFi.lastModified() < projectFilePath().toFileInfo().lastModified())
mode = CMakeOpenProjectWizard::NeedToUpdate;
if (mode != CMakeOpenProjectWizard::Nothing) {
CMakeBuildInfo info(activeBC);
CMakeOpenProjectWizard copw(Core::ICore::mainWindow(), mode, &info);
if (copw.exec() != QDialog::Accepted)
return RestoreResult::UserAbort;
else
activeBC->setInitialArguments(QString());
}
}
parseCMakeLists();
m_activeTarget = activeTarget();
if (m_activeTarget)
if (m_activeTarget) {
connect(m_activeTarget, &Target::activeBuildConfigurationChanged,
this, &CMakeProject::changeActiveBuildConfiguration);
connect(this, &Project::activeTargetChanged,
this, &CMakeProject::activeTargetWasChanged);
if (BuildConfiguration *bc = m_activeTarget->activeBuildConfiguration())
changeActiveBuildConfiguration(bc);
}
return RestoreResult::Ok;
}
@@ -568,7 +498,7 @@ bool CMakeProject::setupTarget(Target *t)
CMakeBuildTarget CMakeProject::buildTargetForTitle(const QString &title)
{
foreach (const CMakeBuildTarget &ct, m_buildTargets)
foreach (const CMakeBuildTarget &ct, buildTargets())
if (ct.title == title)
return ct;
return CMakeBuildTarget();
@@ -672,7 +602,7 @@ void CMakeProject::updateApplicationAndDeploymentTargets()
BuildTargetInfoList appTargetList;
DeploymentData deploymentData;
foreach (const CMakeBuildTarget &ct, m_buildTargets) {
foreach (const CMakeBuildTarget &ct, buildTargets()) {
if (ct.executable.isEmpty())
continue;

View File

@@ -49,12 +49,13 @@ QT_END_NAMESPACE
namespace CMakeProjectManager {
namespace Internal {
class BuildDirManager;
class CMakeFile;
class CMakeBuildSettingsWidget;
class CMakeBuildConfiguration;
class CMakeProjectNode;
class CMakeManager;
}
} // namespace Internal
enum TargetType {
ExecutableType = 0,
@@ -103,17 +104,19 @@ public:
bool isProjectFile(const Utils::FileName &fileName);
bool parseCMakeLists();
bool needsConfiguration() const override;
bool requiresTargetPanel() const override;
bool supportsKit(ProjectExplorer::Kit *k, QString *errorMessage = 0) const override;
void runCMake();
bool isParsing() const;
signals:
/// emitted when parsing starts:
void parsingStarted();
/// emitted after parsing
void buildTargetsChanged();
void buildDirectoryDataAvailable(ProjectExplorer::BuildConfiguration *bc);
protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
@@ -123,8 +126,10 @@ protected:
void changeBuildDirectory(Internal::CMakeBuildConfiguration *bc, const QString &newBuildDirectory);
private:
void fileChanged(const QString &fileName);
void activeTargetWasChanged(ProjectExplorer::Target *target);
void handleKitChanges();
void parseCMakeOutput();
void activeTargetHasChanged(ProjectExplorer::Target *target);
void changeActiveBuildConfiguration(ProjectExplorer::BuildConfiguration*);
void updateRunConfigurations();
@@ -139,12 +144,11 @@ private:
QStringList getCXXFlagsFor(const CMakeBuildTarget &buildTarget, QByteArray *cachedBuildNinja);
ProjectExplorer::Target *m_activeTarget = 0;
Internal::BuildDirManager *m_buildDirManager = 0;
// TODO probably need a CMake specific node structure
QStringList m_files;
QList<CMakeBuildTarget> m_buildTargets;
QFileSystemWatcher *m_watcher;
QSet<Utils::FileName> m_watchedFiles;
QFuture<void> m_codeModelFuture;
};

View File

@@ -24,7 +24,6 @@
****************************************************************************/
#include "cmakeprojectmanager.h"
#include "cmakeopenprojectwizard.h"
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
#include "cmakesettingspage.h"
@@ -39,11 +38,14 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <QAction>
#include <QDateTime>
#include <QIcon>
using namespace ProjectExplorer;
using namespace CMakeProjectManager::Internal;
@@ -103,14 +105,7 @@ void CMakeManager::runCMake(Project *project)
if (!ProjectExplorerPlugin::saveModifiedFiles())
return;
CMakeBuildConfiguration *bc
= static_cast<CMakeBuildConfiguration *>(cmakeProject->activeTarget()->activeBuildConfiguration());
CMakeBuildInfo info(bc);
CMakeOpenProjectWizard copw(Core::ICore::mainWindow(), CMakeOpenProjectWizard::WantToUpdate, &info);
if (copw.exec() == QDialog::Accepted)
cmakeProject->parseCMakeLists();
cmakeProject->runCMake();
}
Project *CMakeManager::openProject(const QString &fileName, QString *errorString)

View File

@@ -36,7 +36,7 @@ namespace ProjectExplorer { class Node; }
namespace Utils {
class Environment;
class QtcProcess;
}
} // namespace Utils
namespace CMakeProjectManager {
namespace Internal {

View File

@@ -1,7 +1,8 @@
DEFINES += CMAKEPROJECTMANAGER_LIBRARY
include(../../qtcreatorplugin.pri)
HEADERS = cmakebuildinfo.h \
HEADERS = builddirmanager.h \
cmakebuildinfo.h \
cmakebuildstep.h \
cmakeconfigitem.h \
cmakeproject.h \
@@ -10,14 +11,12 @@ HEADERS = cmakebuildinfo.h \
cmakeprojectconstants.h \
cmakeprojectnodes.h \
cmakerunconfiguration.h \
cmakeopenprojectwizard.h \
cmakebuildconfiguration.h \
cmakeeditor.h \
cmakelocatorfilter.h \
cmakefilecompletionassist.h \
cmaketool.h \
cmakeparser.h \
generatorinfo.h \
cmakesettingspage.h \
cmaketoolmanager.h \
cmake_global.h \
@@ -27,25 +26,22 @@ HEADERS = cmakebuildinfo.h \
cmakefile.h \
cmakebuildsettingswidget.h \
cmakeindenter.h \
cmakeautocompleter.h \
cmakepreloadcachekitinformation.h \
cmakepreloadcachekitconfigwidget.h
cmakeautocompleter.h
SOURCES = cmakebuildstep.cpp \
SOURCES = builddirmanager.cpp \
cmakebuildstep.cpp \
cmakeconfigitem.cpp \
cmakeproject.cpp \
cmakeprojectplugin.cpp \
cmakeprojectmanager.cpp \
cmakeprojectnodes.cpp \
cmakerunconfiguration.cpp \
cmakeopenprojectwizard.cpp \
cmakebuildconfiguration.cpp \
cmakeeditor.cpp \
cmakelocatorfilter.cpp \
cmakefilecompletionassist.cpp \
cmaketool.cpp \
cmakeparser.cpp \
generatorinfo.cpp \
cmakesettingspage.cpp \
cmaketoolmanager.cpp \
cmakekitinformation.cpp \
@@ -54,8 +50,6 @@ SOURCES = cmakebuildstep.cpp \
cmakefile.cpp \
cmakebuildsettingswidget.cpp \
cmakeindenter.cpp \
cmakeautocompleter.cpp \
cmakepreloadcachekitinformation.cpp \
cmakepreloadcachekitconfigwidget.cpp
cmakeautocompleter.cpp
RESOURCES += cmakeproject.qrc

View File

@@ -17,6 +17,8 @@ QtcPlugin {
]
files: [
"builddirmanager.cpp",
"builddirmanager.h",
"cmake_global.h",
"cmakebuildconfiguration.cpp",
"cmakebuildconfiguration.h",
@@ -41,14 +43,8 @@ QtcPlugin {
"cmakekitinformation.cpp",
"cmakelocatorfilter.cpp",
"cmakelocatorfilter.h",
"cmakeopenprojectwizard.cpp",
"cmakeopenprojectwizard.h",
"cmakeparser.cpp",
"cmakeparser.h",
"cmakepreloadcachekitconfigwidget.cpp",
"cmakepreloadcachekitconfigwidget.h",
"cmakepreloadcachekitinformation.cpp",
"cmakepreloadcachekitinformation.h",
"cmakeproject.cpp",
"cmakeproject.h",
"cmakeproject.qrc",
@@ -67,8 +63,6 @@ QtcPlugin {
"cmaketoolmanager.h",
"cmakesettingspage.h",
"cmakesettingspage.cpp",
"generatorinfo.h",
"generatorinfo.cpp",
"cmakeindenter.h",
"cmakeindenter.cpp",
"cmakeautocompleter.h",

View File

@@ -35,7 +35,6 @@
#include "cmakesettingspage.h"
#include "cmaketoolmanager.h"
#include "cmakekitinformation.h"
#include "cmakepreloadcachekitinformation.h"
#include <utils/mimetypes/mimedatabase.h>
#include <projectexplorer/kitmanager.h>
@@ -59,7 +58,6 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
ProjectExplorer::KitManager::registerKitInformation(new CMakeKitInformation);
ProjectExplorer::KitManager::registerKitInformation(new CMakeGeneratorKitInformation);
ProjectExplorer::KitManager::registerKitInformation(new CMakePreloadCacheKitInformation);
ProjectExplorer::KitManager::registerKitInformation(new CMakeConfigurationKitInformation);
return true;

View File

@@ -1,159 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "generatorinfo.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/abi.h>
#include <projectexplorer/kitinformation.h>
#include <baremetal/baremetalconstants.h>
#include <remotelinux/remotelinux_constants.h>
#include <qnx/qnxconstants.h>
#include "cmakepreloadcachekitinformation.h"
namespace CMakeProjectManager {
namespace Internal {
static bool isMsvcFlavor(const ProjectExplorer::Abi &abi) {
switch (abi.osFlavor()) {
case ProjectExplorer::Abi::WindowsMsvc2005Flavor:
case ProjectExplorer::Abi::WindowsMsvc2008Flavor:
case ProjectExplorer::Abi::WindowsMsvc2010Flavor:
case ProjectExplorer::Abi::WindowsMsvc2012Flavor:
case ProjectExplorer::Abi::WindowsMsvc2013Flavor:
case ProjectExplorer::Abi::WindowsMsvc2015Flavor:
return true;
default:
return false;
}
}
GeneratorInfo::GeneratorInfo(ProjectExplorer::Kit *kit, bool ninja) : m_kit(kit), m_isNinja(ninja)
{ }
ProjectExplorer::Kit *GeneratorInfo::kit() const
{
return m_kit;
}
QByteArray GeneratorInfo::generator() const
{
if (!m_kit)
return QByteArray();
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(m_kit);
ProjectExplorer::Abi targetAbi = tc->targetAbi();
if (m_isNinja) {
return "Ninja";
} else if (targetAbi.os() == ProjectExplorer::Abi::WindowsOS) {
if (isMsvcFlavor(targetAbi)) {
return "NMake Makefiles";
} else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
if (Utils::HostOsInfo::isWindowsHost())
return "MinGW Makefiles";
else
return "Unix Makefiles";
}
}
return "Unix Makefiles";
}
QByteArray GeneratorInfo::generatorArgument() const
{
QByteArray tmp = generator();
if (tmp.isEmpty())
return tmp;
return QByteArray("-GCodeBlocks - ") + tmp;
}
QString GeneratorInfo::preLoadCacheFileArgument() const
{
const QString tmp = CMakePreloadCacheKitInformation::preloadCacheFile(m_kit).toUserOutput();
return tmp.isEmpty() ? QString() : QString::fromLatin1("-C") + tmp;
}
QString GeneratorInfo::displayName() const
{
if (!m_kit)
return QString();
if (m_isNinja)
return tr("Ninja (%1)").arg(m_kit->displayName());
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(m_kit);
ProjectExplorer::Abi targetAbi = tc->targetAbi();
if (targetAbi.os() == ProjectExplorer::Abi::WindowsOS) {
if (isMsvcFlavor(targetAbi)) {
return tr("NMake Generator (%1)").arg(m_kit->displayName());
} else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
if (Utils::HostOsInfo::isWindowsHost())
return tr("MinGW Generator (%1)").arg(m_kit->displayName());
else
return tr("Unix Generator (%1)").arg(m_kit->displayName());
}
} else {
// Non windows
return tr("Unix Generator (%1)").arg(m_kit->displayName());
}
return QString();
}
QList<GeneratorInfo> GeneratorInfo::generatorInfosFor(ProjectExplorer::Kit *k, bool hasNinja,
bool preferNinja, bool hasCodeBlocks)
{
QList<GeneratorInfo> results;
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
if (!tc)
return results;
Core::Id deviceType = ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(k);
if (deviceType != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE
&& deviceType != BareMetal::Constants::BareMetalOsType
&& deviceType != RemoteLinux::Constants::GenericLinuxOsType
&& deviceType != Qnx::Constants::QNX_QNX_OS_TYPE)
return results;
ProjectExplorer::Abi targetAbi = tc->targetAbi();
if (targetAbi.os() == ProjectExplorer::Abi::WindowsOS) {
if (isMsvcFlavor(targetAbi)) {
if (hasCodeBlocks)
results << GeneratorInfo(k);
} else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
results << GeneratorInfo(k);
}
} else {
// Non windows
results << GeneratorInfo(k);
}
if (hasNinja) {
if (preferNinja)
results.prepend(GeneratorInfo(k, true));
else
results.append(GeneratorInfo(k, true));
}
return results;
}
} // namespace Internal
} // namespace CMakeProjectManager

View File

@@ -1,64 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "cmakeprojectmanager.h"
#include <projectexplorer/kit.h>
#include <QCoreApplication>
#include <QMetaType>
namespace CMakeProjectManager {
namespace Internal {
class GeneratorInfo
{
Q_DECLARE_TR_FUNCTIONS(CMakeProjectManager::Internal::GeneratorInfo)
public:
static QList<GeneratorInfo> generatorInfosFor(ProjectExplorer::Kit *k, bool hasNinja,
bool preferNinja, bool hasCodeBlocks);
GeneratorInfo() = default;
ProjectExplorer::Kit *kit() const;
bool isNinja() const;
QString displayName() const;
QByteArray generatorArgument() const;
QByteArray generator() const;
QString preLoadCacheFileArgument() const;
private:
explicit GeneratorInfo(ProjectExplorer::Kit *kit, bool ninja = false);
ProjectExplorer::Kit *m_kit = 0;
bool m_isNinja = false;
};
} // namespace Internal
} // namespace CMakeProjectManager
Q_DECLARE_METATYPE(CMakeProjectManager::Internal::GeneratorInfo)