File indexing completed on 2024-04-28 04:38:19
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Andreas Pakulat <apaku@gmx.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "cmakebuilder.h" 0008 #include "debug.h" 0009 0010 #include <cmakebuilderconfig.h> 0011 0012 #include <project/projectmodel.h> 0013 0014 #include <interfaces/iproject.h> 0015 #include <interfaces/icore.h> 0016 #include <interfaces/iplugincontroller.h> 0017 #include <project/builderjob.h> 0018 #include <makebuilder/imakebuilder.h> 0019 0020 #include "cmakejob.h" 0021 #include "prunejob.h" 0022 #include "cmakebuilderpreferences.h" 0023 #include "cmakeutils.h" 0024 #include <cmakemodelitems.h> 0025 0026 #include <KPluginFactory> 0027 #include <KLocalizedString> 0028 #include <KJob> 0029 0030 #include <QUrl> 0031 0032 K_PLUGIN_FACTORY_WITH_JSON(CMakeBuilderFactory, "kdevcmakebuilder.json", registerPlugin<CMakeBuilder>(); ) 0033 0034 class ErrorJob : public KJob 0035 { 0036 Q_OBJECT 0037 public: 0038 ErrorJob(QObject* parent, const QString& error) 0039 : KJob(parent) 0040 , m_error(error) 0041 {} 0042 0043 void start() override { 0044 setError(!m_error.isEmpty()); 0045 setErrorText(m_error); 0046 emitResult(); 0047 } 0048 0049 private: 0050 QString m_error; 0051 }; 0052 0053 CMakeBuilder::CMakeBuilder(QObject *parent, const QVariantList &) 0054 : KDevelop::IPlugin(QStringLiteral("kdevcmakebuilder"), parent) 0055 { 0056 addBuilder(QStringLiteral("Makefile"), QStringList{QStringLiteral("Unix Makefiles"), 0057 QStringLiteral("NMake Makefiles"), 0058 QStringLiteral("MinGW Makefiles")}, 0059 core()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IMakeBuilder"))); 0060 addBuilder(QStringLiteral("build.ninja"), QStringList(QStringLiteral("Ninja")), core()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IProjectBuilder"), QStringLiteral("KDevNinjaBuilder"))); 0061 } 0062 0063 CMakeBuilder::~CMakeBuilder() 0064 { 0065 } 0066 0067 void CMakeBuilder::addBuilder(const QString& neededfile, const QStringList& generators, KDevelop::IPlugin* i) 0068 { 0069 if( i ) 0070 { 0071 auto* b = i->extension<KDevelop::IProjectBuilder>(); 0072 if( b ) 0073 { 0074 m_builders[neededfile] = b; 0075 for (const QString& gen : generators) { 0076 m_buildersForGenerator[gen] = b; 0077 } 0078 // can't use new signal/slot syntax here, IProjectBuilder is not a QObject 0079 connect(i, SIGNAL(built(KDevelop::ProjectBaseItem*)), this, SIGNAL(built(KDevelop::ProjectBaseItem*))); 0080 connect(i, SIGNAL(failed(KDevelop::ProjectBaseItem*)), this, SIGNAL(failed(KDevelop::ProjectBaseItem*))); 0081 connect(i, SIGNAL(cleaned(KDevelop::ProjectBaseItem*)), this, SIGNAL(cleaned(KDevelop::ProjectBaseItem*))); 0082 connect(i, SIGNAL(installed(KDevelop::ProjectBaseItem*)), this, SIGNAL(installed(KDevelop::ProjectBaseItem*))); 0083 0084 qCDebug(KDEV_CMAKEBUILDER) << "Added builder " << i->metaObject()->className() << "for" << neededfile; 0085 } 0086 else 0087 qCWarning(KDEV_CMAKEBUILDER) << "Couldn't add" << i->metaObject()->className(); 0088 } 0089 } 0090 0091 KJob* CMakeBuilder::build(KDevelop::ProjectBaseItem *dom) 0092 { 0093 KDevelop::IProject* p = dom->project(); 0094 IProjectBuilder* builder = builderForProject(p); 0095 if( builder ) 0096 { 0097 bool valid; 0098 KJob* configure = checkConfigureJob(dom->project(), valid); 0099 0100 KJob* build = nullptr; 0101 if(dom->file()) 0102 { 0103 auto* makeBuilder = dynamic_cast<IMakeBuilder*>(builder); 0104 if (!makeBuilder) { 0105 return new ErrorJob(this, i18n("Could not find the make builder. Check your installation")); 0106 } 0107 KDevelop::ProjectFileItem* file = dom->file(); 0108 int lastDot = file->text().lastIndexOf(QLatin1Char('.')); 0109 const QString target = file->text().midRef(0, lastDot) + QLatin1String(".o"); 0110 build = makeBuilder->executeMakeTarget(dom->parent(), target); 0111 qCDebug(KDEV_CMAKEBUILDER) << "create build job for target" << build << dom << target; 0112 } 0113 qCDebug(KDEV_CMAKEBUILDER) << "Building with" << builder; 0114 if (!build) 0115 { 0116 build = builder->build(dom); 0117 } 0118 if( configure ) 0119 { 0120 qCDebug(KDEV_CMAKEBUILDER) << "creating composite job"; 0121 auto* builderJob = new KDevelop::BuilderJob; 0122 builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, dom ); 0123 builderJob->addCustomJob( KDevelop::BuilderJob::Build, build, dom ); 0124 builderJob->updateJobName(); 0125 build = builderJob; 0126 } 0127 return build; 0128 } 0129 return new ErrorJob(this, i18n("Could not find a builder for %1", p->name())); 0130 } 0131 0132 KJob* CMakeBuilder::clean(KDevelop::ProjectBaseItem *dom) 0133 { 0134 IProjectBuilder* builder = builderForProject(dom->project()); 0135 if( builder ) 0136 { 0137 bool valid; 0138 KJob* configure = checkConfigureJob(dom->project(), valid); 0139 0140 KDevelop::ProjectBaseItem* item = dom; 0141 if(dom->file()) //It doesn't work to compile a file 0142 item=(KDevelop::ProjectBaseItem*) dom->parent(); 0143 0144 qCDebug(KDEV_CMAKEBUILDER) << "Cleaning with" << builder; 0145 KJob* clean = builder->clean(item); 0146 if( configure ) { 0147 auto* builderJob = new KDevelop::BuilderJob; 0148 builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); 0149 builderJob->addCustomJob( KDevelop::BuilderJob::Clean, clean, item ); 0150 builderJob->updateJobName(); 0151 clean = builderJob; 0152 } 0153 return clean; 0154 } 0155 return new ErrorJob(this, i18n("Could not find a builder for %1", dom->project()->name())); 0156 } 0157 0158 KJob* CMakeBuilder::install(KDevelop::ProjectBaseItem *dom, const QUrl &installPrefix) 0159 { 0160 IProjectBuilder* builder = builderForProject(dom->project()); 0161 if( builder ) 0162 { 0163 bool valid; 0164 KJob* configure = checkConfigureJob(dom->project(), valid); 0165 0166 KDevelop::ProjectBaseItem* item = dom; 0167 if(dom->file()) 0168 item=(KDevelop::ProjectBaseItem*) dom->parent(); 0169 0170 qCDebug(KDEV_CMAKEBUILDER) << "Installing with" << builder; 0171 KJob* install = builder->install(item, installPrefix); 0172 if( configure ) { 0173 auto* builderJob = new KDevelop::BuilderJob; 0174 builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); 0175 builderJob->addCustomJob( KDevelop::BuilderJob::Install, install, item ); 0176 builderJob->updateJobName(); 0177 install = builderJob; 0178 } 0179 return install; 0180 0181 } 0182 return new ErrorJob(this, i18n("Could not find a builder for %1", dom->project()->name())); 0183 } 0184 0185 KJob* CMakeBuilder::checkConfigureJob(KDevelop::IProject* project, bool& valid) 0186 { 0187 valid = false; 0188 KJob* configure = nullptr; 0189 if( CMake::checkForNeedingConfigure(project) ) 0190 { 0191 configure = this->configure(project); 0192 } 0193 else if( CMake::currentBuildDir(project).isEmpty() ) 0194 { 0195 return new ErrorJob(this, i18n("No build directory configured, cannot install")); 0196 } 0197 valid = true; 0198 return configure; 0199 } 0200 0201 KJob* CMakeBuilder::configure( KDevelop::IProject* project ) 0202 { 0203 if( CMake::currentBuildDir( project ).isEmpty() ) 0204 { 0205 return new ErrorJob(this, i18n("No build directory configured, cannot configure")); 0206 } 0207 auto* job = new CMakeJob(this); 0208 job->setProject(project); 0209 connect(job, &KJob::result, this, [this, project] { 0210 emit configured(project); 0211 }); 0212 return job; 0213 } 0214 0215 KJob* CMakeBuilder::prune( KDevelop::IProject* project ) 0216 { 0217 return new PruneJob(project); 0218 } 0219 0220 KDevelop::IProjectBuilder* CMakeBuilder::builderForProject(KDevelop::IProject* p) const 0221 { 0222 QString builddir = CMake::currentBuildDir( p ).toLocalFile(); 0223 QMap<QString, IProjectBuilder*>::const_iterator it = m_builders.constBegin(), itEnd = m_builders.constEnd(); 0224 for(; it!=itEnd; ++it) { 0225 if (QFile::exists(builddir+QLatin1Char('/')+it.key())) 0226 return it.value(); 0227 } 0228 //It means that it still has to be generated, so use the builder for 0229 //the generator we use 0230 return m_buildersForGenerator[CMake::defaultGenerator()]; 0231 } 0232 0233 QList< KDevelop::IProjectBuilder* > CMakeBuilder::additionalBuilderPlugins( KDevelop::IProject* project ) const 0234 { 0235 IProjectBuilder* b = builderForProject( project ); 0236 QList< KDevelop::IProjectBuilder* > ret; 0237 if(b) 0238 ret << b; 0239 return ret; 0240 } 0241 0242 int CMakeBuilder::configPages() const 0243 { 0244 return 1; 0245 } 0246 0247 KDevelop::ConfigPage* CMakeBuilder::configPage(int number, QWidget* parent) 0248 { 0249 if (number == 0) { 0250 return new CMakeBuilderPreferences(this, parent); 0251 } 0252 return nullptr; 0253 } 0254 0255 0256 #include "cmakebuilder.moc" 0257 #include "moc_cmakebuilder.cpp"