diff --git a/projectbuilders/cmakebuilder/cmakebuilder.cpp b/projectbuilders/cmakebuilder/cmakebuilder.cpp index 5d30df7c01..197abf1f80 100644 --- a/projectbuilders/cmakebuilder/cmakebuilder.cpp +++ b/projectbuilders/cmakebuilder/cmakebuilder.cpp @@ -1,278 +1,311 @@ /* KDevelop CMake Support * * Copyright 2006-2007 Andreas Pakulat * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakebuilder.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_LOGGING_CATEGORY(CMAKEBUILDER, "kdevelop.projectbuilders.cmakebuilder") #include "cmakejob.h" #include "prunejob.h" #include "cmakebuilderpreferences.h" #include "cmakeutils.h" #include K_PLUGIN_FACTORY_WITH_JSON(CMakeBuilderFactory, "kdevcmakebuilder.json", registerPlugin(); ) class ErrorJob : public KJob { public: ErrorJob(QObject* parent, const QString& error) : KJob(parent) , m_error(error) {} void start() override { setError(!m_error.isEmpty()); setErrorText(m_error); emitResult(); } private: QString m_error; }; CMakeBuilder::CMakeBuilder(QObject *parent, const QVariantList &) : KDevelop::IPlugin("kdevcmakebuilder", parent) { KDEV_USE_EXTENSION_INTERFACE( KDevelop::IProjectBuilder ) addBuilder("Makefile", QStringList("Unix Makefiles") << "NMake Makefiles", core()->pluginController()->pluginForExtension("org.kdevelop.IMakeBuilder")); addBuilder("build.ninja", QStringList("Ninja"), core()->pluginController()->pluginForExtension("org.kdevelop.IProjectBuilder", "KDevNinjaBuilder")); } CMakeBuilder::~CMakeBuilder() { } void CMakeBuilder::addBuilder(const QString& neededfile, const QStringList& generators, KDevelop::IPlugin* i) { if( i ) { IProjectBuilder* b = i->extension(); if( b ) { m_builders[neededfile] = b; foreach(const QString& gen, generators) { m_buildersForGenerator[gen] = b; } // can't use new signal/slot syntax here, IProjectBuilder is not a QObject connect(i, SIGNAL(built(KDevelop::ProjectBaseItem*)), this, SIGNAL(built(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(failed(KDevelop::ProjectBaseItem*)), this, SIGNAL(failed(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(cleaned(KDevelop::ProjectBaseItem*)), this, SIGNAL(cleaned(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(installed(KDevelop::ProjectBaseItem*)), this, SIGNAL(installed(KDevelop::ProjectBaseItem*))); qCDebug(CMAKEBUILDER) << "Added builder " << i->metaObject()->className() << "for" << neededfile; } else qWarning() << "Couldn't add " << i->metaObject()->className() << i->extensions(); } } KJob* CMakeBuilder::build(KDevelop::ProjectBaseItem *dom) { KDevelop::IProject* p = dom->project(); IProjectBuilder* builder = builderForProject(p); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KJob* build = 0; if(dom->file()) { IMakeBuilder* makeBuilder = dynamic_cast(builder); if (!makeBuilder) { return new ErrorJob(this, i18n("Couldn't find the make builder. Check your installation")); } KDevelop::ProjectFileItem* file = dom->file(); int lastDot = file->text().lastIndexOf('.'); QString target = file->text().mid(0, lastDot)+".o"; build = makeBuilder->executeMakeTarget(dom->parent(), target); qCDebug(CMAKEBUILDER) << "create build job for target" << build << dom << target; } qCDebug(CMAKEBUILDER) << "Building with" << builder; if (!build) { build = builder->build(dom); } if( configure ) { qCDebug(CMAKEBUILDER) << "creating composite job"; KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, dom ); builderJob->addCustomJob( KDevelop::BuilderJob::Build, build, dom ); builderJob->updateJobName(); build = builderJob; } return build; } return new ErrorJob(this, i18n("Couldn't find a builder for %1", p->name())); } KJob* CMakeBuilder::clean(KDevelop::ProjectBaseItem *dom) { IProjectBuilder* builder = builderForProject(dom->project()); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KDevelop::ProjectBaseItem* item = dom; if(dom->file()) //It doesn't work to compile a file item=(KDevelop::ProjectBaseItem*) dom->parent(); qCDebug(CMAKEBUILDER) << "Cleaning with" << builder; KJob* clean = builder->clean(item); if( configure ) { KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); builderJob->addCustomJob( KDevelop::BuilderJob::Clean, clean, item ); builderJob->updateJobName(); clean = builderJob; } return clean; } return new ErrorJob(this, i18n("Couldn't find a builder for %1", dom->project()->name())); } KJob* CMakeBuilder::install(KDevelop::ProjectBaseItem *dom, const QUrl &installPrefix) { IProjectBuilder* builder = builderForProject(dom->project()); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KDevelop::ProjectBaseItem* item = dom; if(dom->file()) item=(KDevelop::ProjectBaseItem*) dom->parent(); qCDebug(CMAKEBUILDER) << "Installing with" << builder; KJob* install = builder->install(item, installPrefix); if( configure ) { KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); builderJob->addCustomJob( KDevelop::BuilderJob::Install, install, item ); builderJob->updateJobName(); install = builderJob; } return install; } return new ErrorJob(this, i18n("Couldn't find a builder for %1", dom->project()->name())); } KJob* CMakeBuilder::checkConfigureJob(KDevelop::IProject* project, bool& valid) { valid = false; KJob* configure = nullptr; if( CMake::checkForNeedingConfigure(project) ) { configure = this->configure(project); } else if( CMake::currentBuildDir(project).isEmpty() ) { return new ErrorJob(this, i18n("No Build Directory configured, cannot install")); } valid = true; return configure; } KJob* CMakeBuilder::configure( KDevelop::IProject* project ) { if( CMake::currentBuildDir( project ).isEmpty() ) { return new ErrorJob(this, i18n("No Build Directory configured, cannot configure")); } CMakeJob* job = new CMakeJob(this); job->setProject(project); connect(job, &KJob::result, this, [this, project] { emit configured(project); }); return job; } KJob* CMakeBuilder::prune( KDevelop::IProject* project ) { return new PruneJob(project); } KDevelop::IProjectBuilder* CMakeBuilder::builderForProject(KDevelop::IProject* p) const { QString builddir = CMake::currentBuildDir( p ).toLocalFile(); QMap::const_iterator it = m_builders.constBegin(), itEnd = m_builders.constEnd(); for(; it!=itEnd; ++it) { if(QFile::exists(builddir+'/'+it.key())) return it.value(); } //It means that it still has to be generated, so use the builder for //the generator we use - return m_buildersForGenerator[CMakeBuilderSettings::self()->generator()]; + return m_buildersForGenerator[defaultGenerator()]; } QList< KDevelop::IProjectBuilder* > CMakeBuilder::additionalBuilderPlugins( KDevelop::IProject* project ) const { IProjectBuilder* b = builderForProject( project ); QList< KDevelop::IProjectBuilder* > ret; if(b) ret << b; return ret; } int CMakeBuilder::configPages() const { return 1; } +QStringList CMakeBuilder::supportedGenerators() +{ + QStringList generatorNames; + + bool hasNinja = KDevelop::ICore::self()->pluginController()->pluginForExtension("org.kdevelop.IProjectBuilder", "KDevNinjaBuilder"); + if (hasNinja) + generatorNames << "Ninja"; + +#ifdef Q_OS_WIN + // Visual Studio solution is the standard generator under windows, but we dont want to use + // the VS IDE, so we need nmake makefiles + generatorNames << "NMake Makefiles"; +#endif + generatorNames << "Unix Makefiles"; + + return generatorNames; +} + +QString CMakeBuilder::defaultGenerator() +{ + const QStringList generatorNames = supportedGenerators(); + + QString defGen = generatorNames.value(CMakeBuilderSettings::self()->generator()); + if (defGen.isEmpty()) + { + qWarning() << "Couldn't find builder with index " << CMakeBuilderSettings::self()->generator() + << ", defaulting to 0"; + CMakeBuilderSettings::self()->setGenerator(0); + defGen = generatorNames.at(0); + } + return defGen; +} + KDevelop::ConfigPage* CMakeBuilder::configPage(int number, QWidget* parent) { if (number == 0) { return new CMakeBuilderPreferences(this, parent); } return nullptr; } #include "cmakebuilder.moc" diff --git a/projectbuilders/cmakebuilder/cmakebuilder.h b/projectbuilders/cmakebuilder/cmakebuilder.h index 050ba81bf6..cb35fa9a3f 100644 --- a/projectbuilders/cmakebuilder/cmakebuilder.h +++ b/projectbuilders/cmakebuilder/cmakebuilder.h @@ -1,84 +1,87 @@ /* KDevelop CMake Support * * Copyright 2006-2007 Aleix Pol * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKEBUILDER_H #define CMAKEBUILDER_H #include #include #include #include #include #include #include class QStringList; class QSignalMapper; class KDialog; namespace KDevelop{ class ProjectBaseItem; class CommandExecutor; class OutputModel; } /** * @author Aleix Pol */ class CMakeBuilder : public KDevelop::IPlugin, public KDevelop::IProjectBuilder { Q_OBJECT Q_INTERFACES( KDevelop::IProjectBuilder ) public: explicit CMakeBuilder(QObject *parent = 0, const QVariantList &args = QVariantList()); ~CMakeBuilder() override; KJob* build(KDevelop::ProjectBaseItem *dom) override; KJob* install(KDevelop::ProjectBaseItem *dom, const QUrl &installPrefix) override; KJob* clean(KDevelop::ProjectBaseItem *dom) override; KJob* configure(KDevelop::IProject*) override; KJob* prune(KDevelop::IProject*) override; QList< KDevelop::IProjectBuilder* > additionalBuilderPlugins( KDevelop::IProject* project ) const override; // bool updateConfig( KDevelop::IProject* project ); + static QStringList supportedGenerators(); + static QString defaultGenerator(); + int configPages() const override; KDevelop::ConfigPage* configPage(int number, QWidget* parent) override; Q_SIGNALS: void built(KDevelop::ProjectBaseItem*); void failed(KDevelop::ProjectBaseItem*); void installed(KDevelop::ProjectBaseItem*); void cleaned(KDevelop::ProjectBaseItem*); void configured(KDevelop::IProject*); void pruned(KDevelop::IProject*); private: KJob* checkConfigureJob(KDevelop::IProject* project, bool& valid); void addBuilder(const QString& neededfile, const QStringList& generator, KDevelop::IPlugin* i); KDevelop::IProjectBuilder* builderForProject(KDevelop::IProject* p) const; QMap m_builders; QMap m_buildersForGenerator; }; #endif // CMAKEBUILDER_H diff --git a/projectbuilders/cmakebuilder/cmakebuilderconfig.kcfg b/projectbuilders/cmakebuilder/cmakebuilderconfig.kcfg index 880b6d7ea0..3d71116eb2 100644 --- a/projectbuilders/cmakebuilder/cmakebuilderconfig.kcfg +++ b/projectbuilders/cmakebuilder/cmakebuilderconfig.kcfg @@ -1,15 +1,15 @@ - - Unix Makefiles + + 0 diff --git a/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp b/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp index 72d2258448..8cfd1e710d 100644 --- a/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp +++ b/projectbuilders/cmakebuilder/cmakebuilderpreferences.cpp @@ -1,104 +1,68 @@ /* KDevelop CCMake Support * * Copyright 2012 Aleix Pol Gonzalez * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakebuilderpreferences.h" #include #include #include #include "ui_cmakebuilderpreferences.h" +#include "cmakebuilder.h" #include "cmakebuilderconfig.h" #include "cmakeutils.h" CMakeBuilderPreferences::CMakeBuilderPreferences(KDevelop::IPlugin* plugin, QWidget* parent) : KDevelop::ConfigPage(plugin, CMakeBuilderSettings::self(), parent) { QVBoxLayout* l = new QVBoxLayout( this ); QWidget* w = new QWidget; m_prefsUi = new Ui::CMakeBuilderPreferences; m_prefsUi->setupUi( w ); l->addWidget( w ); #ifdef Q_OS_WIN - // Visual Studio solution is the standard generator under windows, but we dont want to use - // the VS IDE, so we need nmake makefiles - m_prefsUi->kcfg_generator->addItem("NMake Makefiles"); - static_cast(CMakeBuilderSettings::self()->findItem("generator"))->setDefaultValue("NMake Makefiles"); - m_prefsUi->kcfg_cmakeExe->setFilter("*.exe"); -#else - m_prefsUi->kcfg_generator->addItem("Unix Makefiles"); #endif - bool hasNinja = KDevelop::ICore::self()->pluginController()->pluginForExtension("org.kdevelop.IProjectBuilder", "KDevNinjaBuilder"); - if(hasNinja) - m_prefsUi->kcfg_generator->addItem("Ninja"); - - connect(m_prefsUi->kcfg_generator, static_cast(&QComboBox::currentIndexChanged), this, &CMakeBuilderPreferences::generatorChanged); + foreach(const QString& generator, CMakeBuilder::supportedGenerators()) + m_prefsUi->kcfg_generator->addItem(generator); } CMakeBuilderPreferences::~CMakeBuilderPreferences() { delete m_prefsUi; } -void CMakeBuilderPreferences::defaults() -{ - m_prefsUi->kcfg_generator->setCurrentIndex(0); - KDevelop::ConfigPage::defaults(); -} - -void CMakeBuilderPreferences::apply() -{ - CMakeBuilderSettings::setGenerator(m_prefsUi->kcfg_generator->currentText()); - KDevelop::ConfigPage::apply(); - CMakeBuilderSettings::self()->save(); -} - -void CMakeBuilderPreferences::reset() -{ - int idx = m_prefsUi->kcfg_generator->findText(CMakeBuilderSettings::self()->generator()); - m_prefsUi->kcfg_generator->setCurrentIndex(idx); - KDevelop::ConfigPage::reset(); -} - -void CMakeBuilderPreferences::generatorChanged(const QString& generator) -{ - if (CMakeBuilderSettings::self()->generator() != generator) { - emit changed(); - } -} - QString CMakeBuilderPreferences::name() const { return i18n("CMake"); } QString CMakeBuilderPreferences::fullName() const { return i18n("Configure global CMake settings"); } QIcon CMakeBuilderPreferences::icon() const { return QIcon::fromTheme("cmake"); } diff --git a/projectbuilders/cmakebuilder/cmakebuilderpreferences.h b/projectbuilders/cmakebuilder/cmakebuilderpreferences.h index 83b1994ece..8e92919237 100644 --- a/projectbuilders/cmakebuilder/cmakebuilderpreferences.h +++ b/projectbuilders/cmakebuilder/cmakebuilderpreferences.h @@ -1,54 +1,47 @@ /* KDevelop CCMake Support * * Copyright 2012 Aleix Pol Gonzalez * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKEBUILDERPREFERENCES_H #define CMAKEBUILDERPREFERENCES_H #include class QWidget; class QStringList; class CMakeBuilderSettings; namespace Ui { class CMakeBuilderPreferences; } class CMakeBuilderPreferences : public KDevelop::ConfigPage { Q_OBJECT public: explicit CMakeBuilderPreferences(KDevelop::IPlugin* plugin, QWidget* parent = nullptr); ~CMakeBuilderPreferences() override; QString name() const override; QString fullName() const override; QIcon icon() const override; - void apply() override; - void reset() override; - void defaults() override; - -public slots: - void generatorChanged(const QString& generator); - private: Ui::CMakeBuilderPreferences* m_prefsUi; }; #endif diff --git a/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui b/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui index 0b10cf1155..4491cbc1fe 100644 --- a/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui +++ b/projectbuilders/cmakebuilder/cmakebuilderpreferences.ui @@ -1,45 +1,45 @@ CMakeBuilderPreferences 0 0 549 363 Default CMake executable: 0 0 - Generator: + Default generator: diff --git a/projectbuilders/cmakebuilder/cmakejob.cpp b/projectbuilders/cmakebuilder/cmakejob.cpp index 45f12c8926..2b2117b987 100644 --- a/projectbuilders/cmakebuilder/cmakejob.cpp +++ b/projectbuilders/cmakebuilder/cmakejob.cpp @@ -1,144 +1,145 @@ /* KDevelop CMake Support * * Copyright 2006-2007 Andreas Pakulat * Copyright 2008 Hamish Rodda * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakejob.h" #include +#include #include #include #include #include #include #include #include #include "cmakeutils.h" #include "debug.h" using namespace KDevelop; CMakeJob::CMakeJob(QObject* parent) : OutputExecuteJob(parent) , m_project(0) { setCapabilities( Killable ); setFilteringStrategy( OutputModel::CompilerFilter ); setProperties( NeedWorkingDirectory | PortableMessages | DisplayStderr | IsBuilderHint ); setToolTitle( i18n("CMake") ); setStandardToolView( KDevelop::IOutputView::BuildView ); setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll ); } void CMakeJob::start() { qCDebug(CMAKEBUILDER) << "Configuring cmake" << workingDirectory(); if( !m_project ) { setError(NoProjectError); setErrorText("Internal error: no project specified to configure."); emitResult(); return; } QDir::temp().mkpath(workingDirectory().toLocalFile()); CMake::updateConfig( m_project, CMake::currentBuildDirIndex(m_project) ); OutputExecuteJob::start(); } QString CMakeJob::cmakeBinary( KDevelop::IProject* project ) { return CMake::currentCMakeBinary( project ).toLocalFile(); } QUrl CMakeJob::workingDirectory() const { KDevelop::Path path = CMake::currentBuildDir( m_project ); qCDebug(CMAKEBUILDER) << "builddir: " << path; Q_ASSERT(path.isValid()); //We cannot get the project folder as a build directory! return path.toUrl(); } QStringList CMakeJob::commandLine() const { QStringList args; args << CMake::currentCMakeBinary( m_project ).toLocalFile(); args << "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"; QString installDir = CMake::currentInstallDir( m_project ).toLocalFile(); if( !installDir.isEmpty() ) { args << QStringLiteral("-DCMAKE_INSTALL_PREFIX=%1").arg(installDir); } QString buildType = CMake::currentBuildType( m_project ); if( !buildType.isEmpty() ) { args << QStringLiteral("-DCMAKE_BUILD_TYPE=%1").arg(buildType); } QVariantMap cacheArgs = property("extraCMakeCacheValues").toMap(); for( auto it = cacheArgs.constBegin(), itEnd = cacheArgs.constEnd(); it!=itEnd; ++it) { args << QStringLiteral("-D%1=%2").arg(it.key()).arg(it.value().toString()); } //if we are creating a new build directory, we'll want to specify the generator QDir builddir(CMake::currentBuildDir( m_project ).toLocalFile()); if(!builddir.exists() || builddir.count()==2) { CMakeBuilderSettings::self()->load(); - args << QString("-G") << CMakeBuilderSettings::self()->generator(); + args << QString("-G") << CMakeBuilder::defaultGenerator(); } QString cmakeargs = CMake::currentExtraArguments( m_project ); if( !cmakeargs.isEmpty() ) { KShell::Errors err; QStringList tmp = KShell::splitArgs( cmakeargs, KShell::TildeExpand | KShell::AbortOnMeta, &err ); if( err == KShell::NoError ) { args += tmp; } else { qWarning() << "Ignoring cmake Extra arguments"; if( err == KShell::BadQuoting ) { qWarning() << "CMake arguments badly quoted:" << cmakeargs; } else { qWarning() << "CMake arguments had meta character:" << cmakeargs; } } } args << CMake::projectRoot( m_project ).toLocalFile(); return args; } QString CMakeJob::environmentProfile() const { return CMake::currentEnvironment( m_project ); } void CMakeJob::setProject(KDevelop::IProject* project) { m_project = project; if (m_project) setJobName( i18n("CMake: %1", m_project->name()) ); }