Commit e8e2e4f4 authored by dt's avatar dt

Fixes: Progress to the cmake plugin

Details:  Add a dialog asking for command line options and build
directory. This dialog pops up if you don't have a .user file. Note,
though that it also pops up if there is already a in source build.
(The build directory lineedit should be read only then.)
The cmake button in that dialog and the output pane need more polish to
make them better. With those changes you can now build and run marble
from Qt Creator. (For marble you need to pass a few options to cmake.)

Also add a configuration page to the Tools/Options dialog, where you can
specify the cmake executable path.

And add a class which runs cmake in the background to find out which
version and wheter that cmake version has Qt Creator generator. (Which I
did begin to write.)
parent 874922ed
#include "cmakeconfigurewidget.h"
#include "cmakeprojectmanager.h"
#include <projectexplorer/environment.h>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QSpacerItem>
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
CMakeConfigureWidget::CMakeConfigureWidget(QWidget *parent, CMakeManager *manager, const QString &sourceDirectory)
: QWidget(parent), m_configureSucceded(false), m_cmakeManager(manager), m_sourceDirectory(sourceDirectory)
{
m_ui.setupUi(this);
m_ui.buildDirectoryLineEdit->setPath(sourceDirectory + "/qtcreator-build");
connect(m_ui.configureButton, SIGNAL(clicked()), this, SLOT(runCMake()));
// TODO make the configure button do stuff
// TODO set initial settings
// TODO note if there's already a build in that directory
// detect which generators we have
// let the user select generator
}
QString CMakeConfigureWidget::buildDirectory()
{
return m_ui.buildDirectoryLineEdit->path();
}
QStringList CMakeConfigureWidget::arguments()
{
return ProjectExplorer::Environment::parseCombinedArgString(m_ui.cmakeArgumentsLineEdit->text());
}
bool CMakeConfigureWidget::configureSucceded()
{
return m_configureSucceded;
}
void CMakeConfigureWidget::runCMake()
{
// TODO run project createCbp()
// get output and display it
// TODO analyse wheter this worked out
m_ui.cmakeOutput->setPlainText(tr("Waiting for cmake..."));
QString string = m_cmakeManager->createXmlFile(arguments(), m_sourceDirectory, buildDirectory());
m_ui.cmakeOutput->setPlainText(string);
}
//////
// CMakeConfigureDialog
/////
CMakeConfigureDialog::CMakeConfigureDialog(QWidget *parent, CMakeManager *manager, const QString &sourceDirectory)
: QDialog(parent)
{
QVBoxLayout *vbox = new QVBoxLayout(this);
setLayout(vbox);
m_cmakeConfigureWidget = new CMakeConfigureWidget(this, manager, sourceDirectory);
vbox->addWidget(m_cmakeConfigureWidget);
QHBoxLayout *hboxlayout = new QHBoxLayout(this);
hboxlayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Fixed));
QPushButton *okButton = new QPushButton(this);
okButton->setText(tr("Ok"));
okButton->setDefault(true);
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
hboxlayout->addWidget(okButton);
vbox->addLayout(hboxlayout);
}
QString CMakeConfigureDialog::buildDirectory()
{
return m_cmakeConfigureWidget->buildDirectory();
}
QStringList CMakeConfigureDialog::arguments()
{
return m_cmakeConfigureWidget->arguments();
}
bool CMakeConfigureDialog::configureSucceded()
{
return m_cmakeConfigureWidget->configureSucceded();
}
#ifndef CMAKECONFIGUREWIDGET_H
#define CMAKECONFIGUREWIDGET_H
#include "ui_cmakeconfigurewidget.h"
#include <QtGui/QWidget>
#include <QtGui/QDialog>
namespace CMakeProjectManager {
namespace Internal {
class CMakeManager;
class CMakeConfigureWidget : public QWidget
{
Q_OBJECT
public:
CMakeConfigureWidget(QWidget *parent, CMakeManager *manager, const QString &sourceDirectory);
Ui::CMakeConfigureWidget m_ui;
QString buildDirectory();
QStringList arguments();
bool configureSucceded();
private slots:
void runCMake();
private:
bool m_configureSucceded;
CMakeManager *m_cmakeManager;
QString m_sourceDirectory;
};
class CMakeConfigureDialog : public QDialog
{
public:
CMakeConfigureDialog(QWidget *parent, CMakeManager *manager, const QString &sourceDirectory);
QString buildDirectory();
QStringList arguments();
bool configureSucceded();
private:
CMakeConfigureWidget *m_cmakeConfigureWidget;
};
}
}
#endif // CMAKECONFIGUREWIDGET_H
......@@ -32,21 +32,24 @@
***************************************************************************/
#include "cmakeproject.h"
#include "ui_cmakeconfigurewidget.h"
#include "cmakeconfigurewidget.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectnodes.h"
#include "cmakerunconfiguration.h"
#include "cmakestep.h"
#include "makestep.h"
#include <extensionsystem/pluginmanager.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h>
#include <coreplugin/icore.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtGui/QFormLayout>
#include <QtGui/QMainWindow>
using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
......@@ -67,8 +70,6 @@ CMakeProject::CMakeProject(CMakeManager *manager, const QString &fileName)
: m_manager(manager), m_fileName(fileName), m_rootNode(new CMakeProjectNode(m_fileName))
{
m_file = new CMakeFile(this, fileName);
QDir dir = QFileInfo(m_fileName).absoluteDir();
parseCMakeLists(dir);
}
CMakeProject::~CMakeProject()
......@@ -78,12 +79,12 @@ CMakeProject::~CMakeProject()
// TODO also call this method if the CMakeLists.txt file changed, which is also called if the CMakeList.txt is updated
// TODO make this function work even if it is reparsing
void CMakeProject::parseCMakeLists(const QDir &directory)
void CMakeProject::parseCMakeLists()
{
createCbpFile(buildDirectory(QString()));
QString cbpFile = findCbpFile(buildDirectory(QString()));
QString sourceDirectory = QFileInfo(m_fileName).absolutePath();
m_manager->createXmlFile(cmakeStep()->userArguments(activeBuildConfiguration()), sourceDirectory, buildDirectory(activeBuildConfiguration()));
QString cbpFile = findCbpFile(buildDirectory(activeBuildConfiguration()));
CMakeCbpParser cbpparser;
qDebug()<<"Parsing file "<<cbpFile;
if (cbpparser.parseCbpFile(cbpFile)) {
......@@ -142,24 +143,6 @@ QString CMakeProject::findCbpFile(const QDir &directory)
return QString::null;
}
void CMakeProject::createCbpFile(const QDir &directory)
{
// We create a cbp file, only if we didn't find a cbp file in the base directory
// Yet that can still override cbp files in subdirectories
// And we are creating tons of files in the source directories
// All of that is not really nice.
// The mid term plan is to move away from the CodeBlocks Generator and use our own
// QtCreator generator, which actually can be very similar to the CodeBlock Generator
// TODO we need to pass on the same paremeters as the cmakestep
qDebug()<<"Creating cbp file";
directory.mkpath(directory.absolutePath());
QProcess cmake;
cmake.setWorkingDirectory(directory.absolutePath());
cmake.start("cmake", QStringList() << ".." << "-GCodeBlocks - Unix Makefiles");
cmake.waitForFinished(-1);
qDebug()<<"cmake output: \n"<<cmake.readAll();
}
void CMakeProject::buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list)
{
......@@ -300,8 +283,20 @@ void CMakeProject::restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader
{
// TODO
Project::restoreSettingsImpl(reader);
if (buildConfigurations().isEmpty()) {
// No build configuration, adding those
bool hasUserFile = !buildConfigurations().isEmpty();
if (!hasUserFile) {
// Ask the user for where he wants to build it
// and the cmake command line
// TODO check wheter there's already a CMakeCache.txt in the src directory,
// then we don't need to ask, we simply need to build in the src directory
CMakeConfigureDialog ccd(Core::ICore::instance()->mainWindow(), m_manager, QFileInfo(m_fileName).absolutePath());
ccd.exec();
qDebug()<<"ccd.buildDirectory()"<<ccd.buildDirectory();
// Now create a standard build configuration
CMakeStep *cmakeStep = new CMakeStep(this);
MakeStep *makeStep = new MakeStep(this);
......@@ -311,7 +306,14 @@ void CMakeProject::restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader
addBuildConfiguration("all");
setActiveBuildConfiguration("all");
makeStep->setBuildTarget("all", "all", true);
if (!ccd.buildDirectory().isEmpty())
setValue("all", "buildDirectory", ccd.buildDirectory());
cmakeStep->setUserArguments("all", ccd.arguments());
}
parseCMakeLists(); // Gets the directory from the active buildconfiguration
if (!hasUserFile) {
// Create run configurations for m_targets
qDebug()<<"Create run configurations of m_targets";
bool setActive = false;
......@@ -328,7 +330,6 @@ void CMakeProject::restoreSettingsImpl(ProjectExplorer::PersistentSettingsReader
}
}
// Restoring is fine
}
......
......@@ -105,11 +105,9 @@ public:
CMakeStep *cmakeStep() const;
QStringList targets() const;
private:
void parseCMakeLists(const QDir &directory);
void parseCMakeLists();
QString findCbpFile(const QDir &);
void createCbpFile(const QDir &);
void buildTree(CMakeProjectNode *rootNode, QList<ProjectExplorer::FileNode *> list);
ProjectExplorer::FolderNode *findOrCreateFolder(CMakeProjectNode *rootNode, QString directory);
......
......@@ -36,11 +36,14 @@
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include <coreplugin/icore.h>
#include <coreplugin/uniqueidmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/environment.h>
#include <qtconcurrent/QtConcurrentTools>
#include <QtCore/QtConcurrentRun>
#include <QtCore/QSettings>
#include <QFormLayout>
#include <QtGui/QFormLayout>
using namespace CMakeProjectManager::Internal;
......@@ -86,41 +89,131 @@ QString CMakeManager::mimeType() const
return Constants::CMAKEMIMETYPE;
}
QString CMakeManager::cmakeExecutable() const
{
return m_settingsPage->cmakeExecutable();
}
// TODO need to refactor this out
// we probably want the process instead of this function
// cmakeproject then could even run the cmake process in the background, adding the files afterwards
// sounds like a plan
QString CMakeManager::createXmlFile(const QStringList &arguments, const QString &sourceDirectory, const QDir &buildDirectory)
{
// We create a cbp file, only if we didn't find a cbp file in the base directory
// Yet that can still override cbp files in subdirectories
// And we are creating tons of files in the source directories
// All of that is not really nice.
// The mid term plan is to move away from the CodeBlocks Generator and use our own
// QtCreator generator, which actually can be very similar to the CodeBlock Generator
// TODO we need to pass on the same paremeters as the cmakestep
QString buildDirectoryPath = buildDirectory.absolutePath();
qDebug()<<"Creating cbp file in"<<buildDirectoryPath;
buildDirectory.mkpath(buildDirectoryPath);
QProcess cmake;
cmake.setWorkingDirectory(buildDirectoryPath);
cmake.start(cmakeExecutable(), QStringList() << sourceDirectory << arguments << "-GCodeBlocks - Unix Makefiles");
qDebug()<<cmakeExecutable()<<sourceDirectory << arguments;
cmake.waitForFinished(-1);
cmake.setProcessChannelMode(QProcess::MergedChannels);
QString output = cmake.readAll();
qDebug()<<"cmake output: \n"<<output;
return output;
}
/////
// CMakeSettingsPage
// CMakeRunner
////
// TODO give a better name, what this class is to update cached information
// about a cmake executable, with qtconcurrent
// The nifty feature of this class is that it does so in a seperate thread,
// not blocking the main thread
CMakeSettingsPage::CMakeSettingsPage()
CMakeRunner::CMakeRunner()
: m_cacheUpToDate(false)
{
Core::ICore *core = Core::ICore::instance();
QSettings * settings = core->settings();
settings->beginGroup("CMakeSettings");
m_cmakeExecutable = settings->value("cmakeExecutable").toString();
settings->endGroup();
updateCachedInformation();
}
void CMakeSettingsPage::updateCachedInformation() const
void CMakeRunner::run(QFutureInterface<void> &fi)
{
// We find out two things:
// Does this cmake version support a QtCreator generator
// and the version
QFileInfo fi(m_cmakeExecutable);
if (!fi.exists()) {
m_version.clear();
m_supportsQtCreator = false;
}
m_mutex.lock();
QString executable = m_executable;
m_mutex.unlock();
QProcess cmake;
cmake.start(m_cmakeExecutable, QStringList()<<"--help");
cmake.start(executable, QStringList()<<"--help");
cmake.waitForFinished();
QString response = cmake.readAll();
QRegExp versionRegexp("^cmake version ([*\\d\\.]*)-(|patch (\\d*))(|\\r)\\n");
versionRegexp.indexIn(response);
m_mutex.lock();
m_supportsQtCreator = response.contains("QtCreator");
m_version = versionRegexp.cap(1);
if (!versionRegexp.capturedTexts().size()>3)
m_version += "." + versionRegexp.cap(3);
m_cacheUpToDate = true;
m_mutex.unlock();
fi.reportFinished();
}
void CMakeRunner::setExecutable(const QString &executable)
{
waitForUpToDate();
m_mutex.lock();
m_executable = executable;
m_cacheUpToDate = false;
m_mutex.unlock();
m_future = QtConcurrent::run(&CMakeRunner::run, this);
}
QString CMakeRunner::executable() const
{
waitForUpToDate();
m_mutex.lock();
QString result = m_executable;
m_mutex.unlock();
return result;
}
QString CMakeRunner::version() const
{
waitForUpToDate();
m_mutex.lock();
QString result = m_version;
m_mutex.unlock();
return result;
}
bool CMakeRunner::supportsQtCreator() const
{
waitForUpToDate();
m_mutex.lock();
bool result = m_supportsQtCreator;
m_mutex.unlock();
return result;
}
void CMakeRunner::waitForUpToDate() const
{
m_future.waitForFinished();
}
/////
// CMakeSettingsPage
////
CMakeSettingsPage::CMakeSettingsPage()
{
Core::ICore *core = Core::ICore::instance();
QSettings * settings = core->settings();
settings->beginGroup("CMakeSettings");
m_cmakeRunner.setExecutable(settings->value("cmakeExecutable").toString());
settings->endGroup();
}
QString CMakeSettingsPage::findCmakeExecutable() const
......@@ -160,14 +253,13 @@ void CMakeSettingsPage::saveSettings() const
{
QSettings *settings = Core::ICore::instance()->settings();
settings->beginGroup("CMakeSettings");
settings->setValue("cmakeExecutable", m_cmakeExecutable);
settings->setValue("cmakeExecutable", m_cmakeRunner.executable());
settings->endGroup();
}
void CMakeSettingsPage::apply()
{
m_cmakeExecutable = m_pathchooser->path();
updateCachedInformation();
m_cmakeRunner.setExecutable(m_pathchooser->path());
saveSettings();
}
......@@ -178,14 +270,14 @@ void CMakeSettingsPage::finish()
QString CMakeSettingsPage::cmakeExecutable() const
{
if (m_cmakeExecutable.isEmpty()) {
m_cmakeExecutable = findCmakeExecutable();
if (!m_cmakeExecutable.isEmpty()) {
updateCachedInformation();
if (m_cmakeRunner.executable().isEmpty()) {
QString cmakeExecutable = findCmakeExecutable();
if (!cmakeExecutable.isEmpty()) {
m_cmakeRunner.setExecutable(cmakeExecutable);
saveSettings();
}
}
return m_cmakeExecutable;
return m_cmakeRunner.executable();
}
void CMakeSettingsPage::askUserForCMakeExecutable()
......
......@@ -37,11 +37,15 @@
#include <coreplugin/dialogs/ioptionspage.h>
#include <projectexplorer/iprojectmanager.h>
#include <utils/pathchooser.h>
#include <QtCore/QFuture>
#include <QtCore/QStringList>
#include <QtCore/QDir>
namespace CMakeProjectManager {
namespace Internal {
class CMakeSettingsPage;
class CMakeRunner;
class CMakeManager : public ProjectExplorer::IProjectManager
{
......@@ -52,16 +56,37 @@ public:
virtual int projectContext() const;
virtual int projectLanguage() const;
//virtual bool canOpenProject(const QString &fileName);
virtual ProjectExplorer::Project *openProject(const QString &fileName);
virtual QString mimeType() const;
//virtual QString fileFilter() const;
QString cmakeExecutable() const;
QString createXmlFile(const QStringList &arguments, const QString &sourceDirectory, const QDir &buildDirectory);
private:
int m_projectContext;
int m_projectLanguage;
CMakeSettingsPage *m_settingsPage;
};
class CMakeRunner
{
public:
CMakeRunner();
void run(QFutureInterface<void> &fi);
void setExecutable(const QString &executable);
QString executable() const;
QString version() const;
bool supportsQtCreator() const;
void waitForUpToDate() const;
private:
QString m_executable;
QString m_version;
bool m_supportsQtCreator;
bool m_cacheUpToDate;
mutable QFuture<void> m_future;
mutable QMutex m_mutex;
};
class CMakeSettingsPage : public Core::IOptionsPage
{
Q_OBJECT
......@@ -82,9 +107,8 @@ private:
void updateCachedInformation() const;
void saveSettings() const;
QString findCmakeExecutable() const;
mutable QString m_cmakeExecutable;
mutable QString m_version;
mutable bool m_supportsQtCreator;
mutable CMakeRunner m_cmakeRunner;
Core::Utils::PathChooser *m_pathchooser;
};
......
......@@ -9,12 +9,15 @@ HEADERS = cmakeproject.h \
cmakeprojectnodes.h \
cmakestep.h \
makestep.h \
cmakerunconfiguration.h
cmakerunconfiguration.h \
cmakeconfigurewidget.h
SOURCES = cmakeproject.cpp \
cmakeprojectplugin.cpp \
cmakeprojectmanager.cpp \
cmakeprojectnodes.cpp \
cmakestep.cpp \
makestep.cpp \
cmakerunconfiguration.cpp
cmakerunconfiguration.cpp \
cmakeconfigurewidget.cpp
RESOURCES += cmakeproject.qrc
FORMS += cmakeconfigurewidget.ui
......@@ -36,6 +36,7 @@
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"
#include <projectexplorer/environment.h>
#include <utils/qtcassert.h>
#include <QtGui/QFormLayout>
#include <QtGui/QLineEdit>
......@@ -56,7 +57,10 @@ bool CMakeStep::init(const QString &buildConfiguration)
{
setEnabled(buildConfiguration, true);
setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration));
setCommand(buildConfiguration, "cmake"); // TODO give full path here?
CMakeManager *cmakeProjectManager = static_cast<CMakeManager *>(m_pro->projectManager());
setCommand(buildConfiguration, cmakeProjectManager->cmakeExecutable());
QString sourceDir = QFileInfo(m_pro->file()->fileName()).absolutePath();
setArguments(buildConfiguration,
......@@ -99,14 +103,14 @@ bool CMakeStep::immutable() const
return true;
}
QString CMakeStep::userArguments(const QString &buildConfiguration) const
QStringList CMakeStep::userArguments(const QString &buildConfiguration) const
{
return ProjectExplorer::Environment::joinArgumentList(value(buildConfiguration, "userArguments").toStringList());
return value(buildConfiguration, "userArguments").toStringList();
}
void CMakeStep::setUserArguments(const QString &buildConfiguration, const QString &arguments)
void CMakeStep::setUserArguments(const QString &buildConfiguration, const QStringList &arguments)
{
setValue(buildConfiguration, "userArguments", ProjectExplorer::Environment::parseCombinedArgString(arguments));
setValue(buildConfiguration, "userArguments", arguments);
}
//
......@@ -132,13 +136,13 @@ void CMakeBuildStepConfigWidget::init(const QString &buildConfiguration)