/* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * 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 "compilerprovider.h" #include "../debugarea.h" #include "compilerfactories.h" #include "settingsmanager.h" #include #include #include #include #include #include #include using namespace KDevelop; namespace { class NoCompiler : public ICompiler { public: NoCompiler(): ICompiler(i18n("None"), QString(), QString(), false) {} virtual QHash< QString, QString > defines() const override { return {}; } virtual Path::List includes() const override { return {}; } }; } CompilerProvider::CompilerProvider( SettingsManager* settings, QObject* parent ) : QObject( parent ) , m_settings(settings) { m_factories.append(CompilerFactoryPointer(new GccFactory())); m_factories.append(CompilerFactoryPointer(new ClangFactory())); #ifdef _WIN32 m_factories.append(CompilerFactoryPointer(new MsvcFactory())); #endif if (!KStandardDirs::findExe( "gcc" ).isEmpty()) { registerCompiler( m_factories[0]->createCompiler("GCC", "gcc", false) ); } if (!KStandardDirs::findExe( "clang" ).isEmpty()) { registerCompiler( m_factories[1]->createCompiler("Clang", "clang", false) ); } #ifdef _WIN32 if (!KStandardDirs::findExe("cl.exe").isEmpty()) { registerCompiler(m_factories[2]->createCompiler("MSVC", "cl.exe", false)); } #endif registerCompiler(CompilerPointer(new NoCompiler())); retrieveUserDefinedCompilers(); connect( ICore::self()->projectController(), SIGNAL( projectAboutToBeOpened( KDevelop::IProject* ) ), SLOT( projectOpened( KDevelop::IProject* ) ) ); connect( ICore::self()->projectController(), SIGNAL( projectClosed( KDevelop::IProject* ) ), SLOT( projectClosed( KDevelop::IProject* ) ) ); //Add a provider for files without project addPoject( nullptr, checkCompilerExists({})); for (auto project : ICore::self()->projectController()->projects()) { projectOpened( project ); } } CompilerProvider::~CompilerProvider() noexcept { } CompilerPointer CompilerProvider::compilerForItem(ProjectBaseItem* item) const { auto project = item ? item->project() : nullptr; Q_ASSERT(m_projects.contains(project)); auto compiler = m_projects[project]; Q_ASSERT(compiler); return compiler; } QHash CompilerProvider::defines( ProjectBaseItem* item ) const { return compilerForItem(item)->defines(); } Path::List CompilerProvider::includes( ProjectBaseItem* item ) const { return compilerForItem(item)->includes(); } IDefinesAndIncludesManager::Type CompilerProvider::type() const { return IDefinesAndIncludesManager::CompilerSpecific; } void CompilerProvider::addPoject( IProject* project, const CompilerPointer& compiler ) { Q_ASSERT(compiler); //cache includes/defines compiler->includes(); compiler->defines(); m_projects[project] = compiler; } void CompilerProvider::removePoject( IProject* project ) { m_projects.remove( project ); } CompilerPointer CompilerProvider::checkCompilerExists( const CompilerPointer& compiler ) const { //This may happen for opened for the first time projects if ( !compiler ) { for ( auto& compiler : m_compilers ) { if ( KStandardDirs::findExe( compiler->path() ).isEmpty() ) { continue; } definesAndIncludesDebug() << "Selected compiler: " << compiler->name(); return compiler; } kWarning() << "No compiler found. Standard includes/defines won't be provided to the project parser!"; }else{ for ( auto it = m_compilers.constBegin(); it != m_compilers.constEnd(); it++ ) { if ( (*it)->name() == compiler->name() ) { return *it; } } } return CompilerPointer(new NoCompiler()); } void CompilerProvider::setCompiler( IProject* project, const CompilerPointer& compiler ) { auto c = checkCompilerExists( compiler ); Q_ASSERT(c); addPoject( project, c ); } void CompilerProvider::projectOpened( KDevelop::IProject* project ) { definesAndIncludesDebug() << "Adding project: " << project->name(); auto projectConfig = project->projectConfiguration().data(); auto compiler = m_settings->currentCompiler( projectConfig, CompilerPointer(new NoCompiler()) ); auto name = compiler ? compiler->name() : QString(); compiler = checkCompilerExists( compiler ); if ( compiler && ( compiler->name() != name ) ) { m_settings->writeCurrentCompiler(projectConfig, compiler); } definesAndIncludesDebug() << " compiler is: " << compiler->name(); addPoject( project, compiler ); } void CompilerProvider::projectClosed( KDevelop::IProject* project ) { removePoject( project ); } QVector< CompilerPointer > CompilerProvider::compilers() const { return m_compilers; } CompilerPointer CompilerProvider::currentCompiler(IProject* project) const { Q_ASSERT(m_projects.contains(project)); return m_projects[project]; } bool CompilerProvider::registerCompiler(const CompilerPointer& compiler) { if (!compiler) { return false; } for(auto c: m_compilers){ if (c->name() == compiler->name()) { return false; } } m_compilers.append(compiler); return true; } void CompilerProvider::unregisterCompiler(const CompilerPointer& compiler) { if (!compiler->editable()) { return; } for (auto it = m_projects.constBegin(); it != m_projects.constEnd(); it++) { if (it.value() == compiler) { //Set empty compiler for opened projects that use the compiler that is being unregistered setCompiler(it.key(), CompilerPointer(new NoCompiler())); } } for (int i = 0; i < m_compilers.count(); i++) { if (m_compilers[i]->name() == compiler->name()) { m_compilers.remove(i); break; } } } QVector< CompilerFactoryPointer > CompilerProvider::compilerFactories() const { return m_factories; } void CompilerProvider::retrieveUserDefinedCompilers() { auto compilers = m_settings->userDefinedCompilers(); for (auto c : compilers) { registerCompiler(c); } } #include "moc_compilerprovider.cpp"