cmakeprojectmanager.cpp 8.85 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6 7 8
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
9
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18 19 20 21 22 23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
**
25 26
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30 31 32 33 34
#include "cmakeprojectmanager.h"
#include "cmakeprojectconstants.h"
#include "cmakeproject.h"
#include "cmakeprojectconstants.h"

dt's avatar
dt committed
35
#include <coreplugin/icore.h>
con's avatar
con committed
36 37
#include <coreplugin/uniqueidmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
38
#include <projectexplorer/environment.h>
dt's avatar
dt committed
39 40
#include <qtconcurrent/QtConcurrentTools>
#include <QtCore/QtConcurrentRun>
41
#include <QtCore/QSettings>
dt's avatar
dt committed
42
#include <QtGui/QFormLayout>
con's avatar
con committed
43 44 45

using namespace CMakeProjectManager::Internal;

46 47
CMakeManager::CMakeManager(CMakeSettingsPage *cmakeSettingsPage)
    : m_settingsPage(cmakeSettingsPage)
con's avatar
con committed
48
{
49 50 51
    Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
    m_projectContext = uidm->uniqueIdentifier(CMakeProjectManager::Constants::PROJECTCONTEXT);
    m_projectLanguage = uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX);
con's avatar
con committed
52 53
}

54 55 56 57 58
CMakeSettingsPage::~CMakeSettingsPage()
{

}

con's avatar
con committed
59 60 61 62 63 64 65 66 67 68 69 70 71
int CMakeManager::projectContext() const
{
    return m_projectContext;
}

int CMakeManager::projectLanguage() const
{
    return m_projectLanguage;
}

ProjectExplorer::Project *CMakeManager::openProject(const QString &fileName)
{
    // TODO check wheter this project is already opened
72 73 74 75 76 77 78 79
    // Check that we have a cmake executable first
    // Look at the settings first
    QString cmakeExecutable = m_settingsPage->cmakeExecutable();
    if (cmakeExecutable.isNull())
        m_settingsPage->askUserForCMakeExecutable();
    cmakeExecutable = m_settingsPage->cmakeExecutable();
    if (cmakeExecutable.isNull())
        return 0;
con's avatar
con committed
80 81 82 83 84 85 86
    return new CMakeProject(this, fileName);
}

QString CMakeManager::mimeType() const
{
    return Constants::CMAKEMIMETYPE;
}
87

dt's avatar
dt committed
88 89 90 91 92 93 94 95 96
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
97
QProcess *CMakeManager::createXmlFile(const QStringList &arguments, const QString &sourceDirectory, const QDir &buildDirectory)
dt's avatar
dt committed
98 99 100 101 102 103 104 105 106 107 108 109 110
{
    // 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);
111 112
    QProcess * cmake = new QProcess;
    cmake->setWorkingDirectory(buildDirectoryPath);
113

114 115 116 117 118
#ifdef Q_OS_WIN
    QString generator = "-GCodeBlocks - MinGW Makefiles";
#else // Q_OS_WIN
   QString generator = "-GCodeBlocks - Unix Makefiles";
#endif // Q_OS_WIN
119 120 121
    qDebug()<<cmakeExecutable()<<sourceDirectory << arguments<<generator;
    cmake->start(cmakeExecutable(), QStringList() << sourceDirectory << arguments << generator);
    return cmake;
dt's avatar
dt committed
122 123
}

124 125 126 127 128 129 130 131 132 133 134 135 136 137
QString CMakeManager::findCbpFile(const QDir &directory)
{
    // Find the cbp file
    //   TODO the cbp file is named like the project() command in the CMakeList.txt file
    //   so this method below could find the wrong cbp file, if the user changes the project()
    //   2name
    foreach (const QString &cbpFile , directory.entryList()) {
        if (cbpFile.endsWith(".cbp"))
            return directory.path() + "/" + cbpFile;
    }
    return QString::null;
}


dt's avatar
dt committed
138

139
/////
dt's avatar
dt committed
140
// CMakeRunner
141
////
dt's avatar
dt committed
142 143 144 145
// 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
146

dt's avatar
dt committed
147 148
CMakeRunner::CMakeRunner()
    : m_cacheUpToDate(false)
149
{
dt's avatar
dt committed
150

151 152
}

dt's avatar
dt committed
153
void CMakeRunner::run(QFutureInterface<void> &fi)
154
{
dt's avatar
dt committed
155 156 157
    m_mutex.lock();
    QString executable = m_executable;
    m_mutex.unlock();
158
    QProcess cmake;
dt's avatar
dt committed
159
    cmake.start(executable, QStringList()<<"--help");
160 161 162 163 164
    cmake.waitForFinished();
    QString response = cmake.readAll();
    QRegExp versionRegexp("^cmake version ([*\\d\\.]*)-(|patch (\\d*))(|\\r)\\n");
    versionRegexp.indexIn(response);

dt's avatar
dt committed
165
    m_mutex.lock();
166 167 168 169
    m_supportsQtCreator = response.contains("QtCreator");
    m_version = versionRegexp.cap(1);
    if (!versionRegexp.capturedTexts().size()>3)
        m_version += "." + versionRegexp.cap(3);
dt's avatar
dt committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    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();
229 230 231 232 233 234 235 236
}

QString CMakeSettingsPage::findCmakeExecutable() const
{
    ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment();
    return env.searchInPath("cmake");
}

237 238 239 240
QString CMakeSettingsPage::id() const
{
    return QLatin1String("CMake");
}
241

242
QString CMakeSettingsPage::trName() const
243
{
244
    return tr("CMake");
245 246 247 248
}

QString CMakeSettingsPage::category() const
{
249
    return QLatin1String("CMake");
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
}

QString CMakeSettingsPage::trCategory() const
{
    return tr("CMake");
}

QWidget *CMakeSettingsPage::createPage(QWidget *parent)
{
    QWidget *w = new QWidget(parent);
    QFormLayout *fl = new QFormLayout(w);
    m_pathchooser = new Core::Utils::PathChooser(w);
    m_pathchooser->setExpectedKind(Core::Utils::PathChooser::Command);
    fl->addRow("CMake executable", m_pathchooser);
    m_pathchooser->setPath(cmakeExecutable());
    return w;
}

void CMakeSettingsPage::saveSettings() const
{
    QSettings *settings = Core::ICore::instance()->settings();
    settings->beginGroup("CMakeSettings");
dt's avatar
dt committed
272
    settings->setValue("cmakeExecutable", m_cmakeRunner.executable());
273 274 275 276 277
    settings->endGroup();
}

void CMakeSettingsPage::apply()
{
dt's avatar
dt committed
278
    m_cmakeRunner.setExecutable(m_pathchooser->path());
279 280 281 282 283 284 285 286 287 288
    saveSettings();
}

void CMakeSettingsPage::finish()
{

}

QString CMakeSettingsPage::cmakeExecutable() const
{
dt's avatar
dt committed
289 290 291 292
    if (m_cmakeRunner.executable().isEmpty()) {
        QString cmakeExecutable = findCmakeExecutable();
        if (!cmakeExecutable.isEmpty()) {
            m_cmakeRunner.setExecutable(cmakeExecutable);
293 294 295
            saveSettings();
        }
    }
dt's avatar
dt committed
296
    return m_cmakeRunner.executable();
297 298 299 300 301 302 303 304 305 306 307
}

void CMakeSettingsPage::askUserForCMakeExecutable()
{
    // TODO implement
    // That is ideally add a label to the settings page, which says something
    // to the effect: please configure the cmake executable
    // and show the settings page
    // ensure that we rehide the label in the finish() function
    // But to test that i need an environment without cmake, e.g. windows
}