diff --git a/projectbuilders/qmakebuilder/qmakebuilder.h b/projectbuilders/qmakebuilder/qmakebuilder.h --- a/projectbuilders/qmakebuilder/qmakebuilder.h +++ b/projectbuilders/qmakebuilder/qmakebuilder.h @@ -23,6 +23,9 @@ #include #include "iqmakebuilder.h" + +#include + #include /** @@ -58,6 +61,13 @@ void pruned(KDevelop::ProjectBaseItem*); private: + /** + * If @p dom needs a configure run, return a composite job consisting of configure job + @p job + * + * Otherwise just return @p job + */ + KJob* maybePrependConfigureJob(KDevelop::ProjectBaseItem* project, KJob* job, KDevelop::BuilderJob::BuildType type); + KDevelop::IPlugin* m_makeBuilder; }; diff --git a/projectbuilders/qmakebuilder/qmakebuilder.cpp b/projectbuilders/qmakebuilder/qmakebuilder.cpp --- a/projectbuilders/qmakebuilder/qmakebuilder.cpp +++ b/projectbuilders/qmakebuilder/qmakebuilder.cpp @@ -22,6 +22,7 @@ #include "qmakebuilderpreferences.h" #include "qmakeconfig.h" +#include "qmakeutils.h" #include #include @@ -92,7 +93,7 @@ IMakeBuilder* builder = m_makeBuilder->extension(); if (builder) { qCDebug(KDEV_QMAKEBUILDER) << "Building with make"; - return builder->build(dom); + return maybePrependConfigureJob(dom, builder->build(dom), BuilderJob::Build); } } return nullptr; @@ -112,7 +113,7 @@ IMakeBuilder* builder = m_makeBuilder->extension(); if (builder) { qCDebug(KDEV_QMAKEBUILDER) << "Cleaning with make"; - return builder->clean(dom); + return maybePrependConfigureJob(dom, builder->clean(dom), BuilderJob::Clean); } } return nullptr; @@ -125,7 +126,7 @@ IMakeBuilder* builder = m_makeBuilder->extension(); if (builder) { qCDebug(KDEV_QMAKEBUILDER) << "Installing with make"; - return builder->install(dom); + return maybePrependConfigureJob(dom, builder->install(dom), BuilderJob::Install); } } return nullptr; @@ -157,4 +158,28 @@ return QList(); } + +KJob* QMakeBuilder::maybePrependConfigureJob(ProjectBaseItem* dom, KJob* job, BuilderJob::BuildType type) +{ + Q_ASSERT(dom); + + if (!job) { + qCDebug(KDEV_QMAKEBUILDER) << "Null job passed"; + return nullptr; + } + + const bool needsConfigure = QMakeUtils::checkForNeedingConfigure(dom->project()); + if (needsConfigure) { + qCDebug(KDEV_QMAKEBUILDER) << "Project" << dom->project()->name() << "needs configure"; + + auto builderJob = new BuilderJob; + builderJob->addCustomJob(BuilderJob::Configure, configure(dom->project()), dom); + builderJob->addCustomJob(type, job, dom); + builderJob->updateJobName(); + return builderJob; + } + + return job; +} + #include "qmakebuilder.moc" diff --git a/projectbuilders/qmakebuilder/qmakejob.cpp b/projectbuilders/qmakebuilder/qmakejob.cpp --- a/projectbuilders/qmakebuilder/qmakejob.cpp +++ b/projectbuilders/qmakebuilder/qmakejob.cpp @@ -21,6 +21,7 @@ #include "qmakejob.h" +#include "debug.h" #include "qmakeconfig.h" #include @@ -31,7 +32,7 @@ #include #include -#include +#include #include using namespace KDevelop; @@ -50,24 +51,40 @@ void QMakeJob::start() { + qCDebug(KDEV_QMAKE) << "Running qmake in" << workingDirectory(); + if (!m_project) { setError(NoProjectError); setErrorText(i18n("No project specified.")); return emitResult(); } + // create build directory if it does not exist yet + QDir::temp().mkpath(workingDirectory().toLocalFile()); + OutputExecuteJob::start(); } QUrl QMakeJob::workingDirectory() const { - return m_project ? m_project->path().toUrl() : QUrl(); + if (!m_project) { + return QUrl(); + } + + return QMakeConfig::buildDirFromSrc(m_project, m_project->path()).toUrl(); } QStringList QMakeJob::commandLine() const { + if (!m_project) { + return {}; + } + QStringList args; args << QMakeConfig::qmakeBinary(m_project); + + args << m_project->path().toUrl().toLocalFile(); + return args; } diff --git a/projectmanagers/qmake/CMakeLists.txt b/projectmanagers/qmake/CMakeLists.txt --- a/projectmanagers/qmake/CMakeLists.txt +++ b/projectmanagers/qmake/CMakeLists.txt @@ -19,6 +19,7 @@ qmakeincludefile.cpp qmakemkspecs.cpp qmakeprojectfile.cpp + qmakeutils.cpp variablereferenceparser.cpp ) ki18n_wrap_ui(qmakecommon_SRCS qmakebuilddirchooser.ui) diff --git a/projectmanagers/qmake/qmakeconfig.cpp b/projectmanagers/qmake/qmakeconfig.cpp --- a/projectmanagers/qmake/qmakeconfig.cpp +++ b/projectmanagers/qmake/qmakeconfig.cpp @@ -68,7 +68,7 @@ { QMutexLocker lock(&s_buildDirMutex); KConfigGroup cg(project->projectConfiguration(), QMakeConfig::CONFIG_GROUP); - Path buildDir = Path(cg.readEntry(QMakeConfig::BUILD_FOLDER, project->path().toLocalFile())); + Path buildDir = Path(cg.readEntry(QMakeConfig::BUILD_FOLDER, QString())); lock.unlock(); if (buildDir.isValid()) { diff --git a/projectmanagers/qmake/qmakemanager.h b/projectmanagers/qmake/qmakemanager.h --- a/projectmanagers/qmake/qmakemanager.h +++ b/projectmanagers/qmake/qmakemanager.h @@ -91,9 +91,7 @@ KDevelop::ProjectFolderItem* projectRootItem( KDevelop::IProject* project, const KDevelop::Path& path ); KDevelop::ProjectFolderItem* buildFolderItem( KDevelop::IProject* project, const KDevelop::Path& path, KDevelop::ProjectBaseItem* parent ); - QHash queryQMake( KDevelop::IProject* ) const; QMakeCache* findQMakeCache( KDevelop::IProject* project, const KDevelop::Path &path = {} ) const; - bool projectNeedsConfiguration(KDevelop::IProject* project); IQMakeBuilder* m_builder; mutable QString m_qtIncludeDir; diff --git a/projectmanagers/qmake/qmakemanager.cpp b/projectmanagers/qmake/qmakemanager.cpp --- a/projectmanagers/qmake/qmakemanager.cpp +++ b/projectmanagers/qmake/qmakemanager.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +56,7 @@ #include "qmakejob.h" #include "qmakebuilddirchooserdialog.h" #include "qmakeconfig.h" -#include -#include +#include "qmakeutils.h" #include "debug.h" using namespace KDevelop; @@ -178,7 +178,7 @@ projectfile = l.first(); } - QHash qmvars = queryQMake(project); + QHash qmvars = QMakeUtils::queryQMake(project); const QString mkSpecFile = QMakeConfig::findBasicMkSpec(qmvars); Q_ASSERT(!mkSpecFile.isEmpty()); QMakeMkSpecs* mkspecs = new QMakeMkSpecs(mkSpecFile, qmvars); @@ -317,19 +317,10 @@ return nullptr; } - while (projectNeedsConfiguration(project)) { - QMakeBuildDirChooserDialog chooser(project); - if (chooser.exec() == QDialog::Rejected) { - qDebug() << "User stopped project import"; - // TODO: return 0 has no effect. - return nullptr; - } - } + QMakeUtils::checkForNeedingConfigure(project); ProjectFolderItem* ret = AbstractFileManagerPlugin::import(project); - connect(projectWatcher(project), SIGNAL(dirty(QString)), this, SLOT(slotDirty(QString))); - return ret; } @@ -460,14 +451,6 @@ return findQMakeFolderParent(item); } -QHash QMakeProjectManager::queryQMake(IProject* project) const -{ - if (!project->path().toUrl().isLocalFile() || !m_builder) - return QHash(); - - return QMakeConfig::queryQMake(QMakeConfig::qmakeBinary(project)); -} - QMakeCache* QMakeProjectManager::findQMakeCache(IProject* project, const Path& path) const { QDir curdir(QMakeConfig::buildDirFromSrc(project, !path.isValid() ? project->path() : path).toLocalFile()); @@ -523,26 +506,4 @@ KDevelop::ICore::self()->runController()->registerJob(job); } -bool QMakeProjectManager::projectNeedsConfiguration(IProject* project) -{ - if (!QMakeConfig::isConfigured(project)) { - return true; - } - const QString qmakeBinary = QMakeConfig::qmakeBinary(project); - if (qmakeBinary.isEmpty()) { - return true; - } - const QHash vars = queryQMake(project); - if (vars.isEmpty()) { - return true; - } - if (QMakeConfig::findBasicMkSpec(vars).isEmpty()) { - return true; - } - if (!QMakeConfig::buildDirFromSrc(project, project->path()).isValid()) { - return true; - } - return false; -} - #include "qmakemanager.moc" diff --git a/projectmanagers/qmake/qmakeutils.h b/projectmanagers/qmake/qmakeutils.h new file mode 100644 --- /dev/null +++ b/projectmanagers/qmake/qmakeutils.h @@ -0,0 +1,47 @@ +/* + * Copyright 2015 Kevin Funk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef QMAKEUTILS_H +#define QMAKEUTILS_H + +#include + +namespace KDevelop +{ +class IProject; +} + +namespace QMakeUtils { + +/** + * Checks wether there's a need to run qmake for the given project item + * This is the case if no builddir has been specified, in which case + * it asks for one. + * + * @returns true if configure should be run, false otherwise + */ +bool checkForNeedingConfigure(KDevelop::IProject* project); + +QHash queryQMake(KDevelop::IProject*); + +} + +#endif // QMAKEUTILS_H diff --git a/projectmanagers/qmake/qmakeutils.cpp b/projectmanagers/qmake/qmakeutils.cpp new file mode 100644 --- /dev/null +++ b/projectmanagers/qmake/qmakeutils.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Kevin Funk + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "qmakeutils.h" +#include "debug.h" + +#include "qmakebuilddirchooserdialog.h" +#include "qmakeconfig.h" + +#include +#include + +#include +#include + +using namespace KDevelop; + +bool QMakeUtils::checkForNeedingConfigure(IProject* project) +{ + Q_ASSERT(project); + + qCDebug(KDEV_QMAKE) << "Checking whether" << project->name() << "needs a configure run"; + + const auto buildDir = QMakeConfig::buildDirFromSrc(project, project->path()); + if (!buildDir.isValid()) { + QMakeBuildDirChooserDialog chooser(project); + if (chooser.exec() == QDialog::Rejected) { + return false; // cancelled, can't configure => false + } + } + + qCDebug(KDEV_QMAKE) << "Build directory for" << project->name() << "is" << buildDir; + + if (!QMakeConfig::isConfigured(project)) { + return true; + } + const QString qmakeBinary = QMakeConfig::qmakeBinary(project); + if (qmakeBinary.isEmpty()) { + return true; + } + const QHash vars = queryQMake(project); + if (vars.isEmpty()) { + return true; + } + if (QMakeConfig::findBasicMkSpec(vars).isEmpty()) { + return true; + } + + if (!QFile::exists(buildDir.toLocalFile())) { + qCDebug(KDEV_QMAKE) << "build dir" << buildDir << "configured, but does not exist yet"; + return true; + } + + qCDebug(KDEV_QMAKE) << "No configure needed for project" << project->name(); + return false; +} + +QHash QMakeUtils::queryQMake(IProject* project) +{ + if (!project->path().toUrl().isLocalFile()) + return QHash(); + + return QMakeConfig::queryQMake(QMakeConfig::qmakeBinary(project)); +} diff --git a/projectmanagers/qmake/tests/test_qmakeproject.cpp b/projectmanagers/qmake/tests/test_qmakeproject.cpp --- a/projectmanagers/qmake/tests/test_qmakeproject.cpp +++ b/projectmanagers/qmake/tests/test_qmakeproject.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -136,7 +137,12 @@ QList buildItems = project->foldersForPath(IndexedString(buildUrl.pathOrUrl())); QCOMPARE(buildItems.size(), 1); IBuildSystemManager* buildManager = project->buildSystemManager(); - const Path actual = buildManager->buildDirectory(buildItems.first()); + const auto buildFolder = buildItems.first(); + + const Path actual = buildManager->buildDirectory(buildFolder); QCOMPARE(actual, expectedPath); + + auto buildJob = buildManager->builder()->configure(project); + QVERIFY(buildJob->exec()); }