diff --git a/kdevplatform/project/interfaces/ibuildsystemmanager.h b/kdevplatform/project/interfaces/ibuildsystemmanager.h --- a/kdevplatform/project/interfaces/ibuildsystemmanager.h +++ b/kdevplatform/project/interfaces/ibuildsystemmanager.h @@ -130,6 +130,11 @@ * @returns the extra arguments that will be passed to the compiler when building @p item */ virtual QString extraArguments(ProjectBaseItem* item) const = 0; + + /** + * @returns the absolute path to the tool that will be used or an empty path if unknown + */ + virtual Path compiler(KDevelop::ProjectTargetItem* p) const = 0; }; } diff --git a/plugins/cmake/cmakemanager.h b/plugins/cmake/cmakemanager.h --- a/plugins/cmake/cmakemanager.h +++ b/plugins/cmake/cmakemanager.h @@ -137,6 +137,8 @@ void integrateData(const CMakeProjectData &data, KDevelop::IProject* project); + KDevelop::Path compiler(KDevelop::ProjectTargetItem * p) const override; + Q_SIGNALS: void folderRenamed(const KDevelop::Path& oldFolder, KDevelop::ProjectFolderItem* newFolder); void fileRenamed(const KDevelop::Path& oldFile, KDevelop::ProjectFileItem* newFile); @@ -154,6 +156,7 @@ private: void reloadProjects(); CMakeFile fileInformation(KDevelop::ProjectBaseItem* item) const; + CMakeTarget targetInformation(KDevelop::ProjectTargetItem* item) const; void folderAdded(KDevelop::ProjectFolderItem* folder); diff --git a/plugins/cmake/cmakemanager.cpp b/plugins/cmake/cmakemanager.cpp --- a/plugins/cmake/cmakemanager.cpp +++ b/plugins/cmake/cmakemanager.cpp @@ -315,6 +315,8 @@ connect(job, &KJob::finished, this, [project](KJob* job) { if (job->error()) return; + + KDevelop::ICore::self()->projectController()->projectConfigurationChanged(project); KDevelop::ICore::self()->projectController()->reparseProject(project, true); }); } @@ -984,4 +986,35 @@ } } +CMakeTarget CMakeManager::targetInformation(KDevelop::ProjectTargetItem* item) const +{ + const auto targets = m_projects[item->project()].targets[item->parent()->path()]; + for (auto target: targets) { + if (item->text() == target.name) { + return target; + } + } + return {}; +} + +KDevelop::Path CMakeManager::compiler(KDevelop::ProjectTargetItem* item) const +{ + const auto targetInfo = targetInformation(item); + if (targetInfo.sources.isEmpty()) { + qCDebug(CMAKE) << "could not find target" << item->text(); + return {}; + } + + const auto info = m_projects[item->project()].compilationData.files[targetInfo.sources.constFirst()]; + const auto lang = info.language; + if (lang.isEmpty()) { + qCDebug(CMAKE) << "no language for" << item << item->text() << info.defines << targetInfo.sources.constFirst(); + return {}; + } + const QString var = QLatin1String("CMAKE_") + lang + QLatin1String("_COMPILER"); + const auto ret = CMake::readCacheValues(KDevelop::Path(buildDirectory(item), QStringLiteral("CMakeCache.txt")), {var}); + qCDebug(CMAKE) << "compiler for" << lang << var << ret; + return KDevelop::Path(ret.value(var)); +} + #include "cmakemanager.moc" diff --git a/plugins/cmake/cmakeprojectdata.h b/plugins/cmake/cmakeprojectdata.h --- a/plugins/cmake/cmakeprojectdata.h +++ b/plugins/cmake/cmakeprojectdata.h @@ -40,11 +40,12 @@ KDevelop::Path::List includes; KDevelop::Path::List frameworkDirectories; QString compileFlags; + QString language; QHash defines; }; inline QDebug &operator<<(QDebug debug, const CMakeFile& file) { - debug << "CMakeFile(-I" << file.includes << ", -F" << file.frameworkDirectories << ", -D" << file.defines << ")"; + debug << "CMakeFile(-I" << file.includes << ", -F" << file.frameworkDirectories << ", -D" << file.defines << ", " << file.language << ")"; return debug.maybeSpace(); } diff --git a/plugins/cmake/cmakeserverimportjob.cpp b/plugins/cmake/cmakeserverimportjob.cpp --- a/plugins/cmake/cmakeserverimportjob.cpp +++ b/plugins/cmake/cmakeserverimportjob.cpp @@ -115,6 +115,7 @@ CMakeFile file; file.includes = kTransform(fileGroup.value(QStringLiteral("includePath")).toArray(), [](const QJsonValue& val) { return KDevelop::Path(val.toObject().value(QStringLiteral("path")).toString()); }); + file.language = fileGroup.value(QStringLiteral("language")).toString(), file.compileFlags = fileGroup.value(QStringLiteral("compileFlags")).toString(); file.defines = processDefines(file.compileFlags, fileGroup.value(QStringLiteral("defines")).toArray()); diff --git a/plugins/custom-buildsystem/custombuildsystemplugin.h b/plugins/custom-buildsystem/custombuildsystemplugin.h --- a/plugins/custom-buildsystem/custombuildsystemplugin.h +++ b/plugins/custom-buildsystem/custombuildsystemplugin.h @@ -52,6 +52,9 @@ /// @p installPrefix will be passed as DESTDIR environment variable KJob* install( KDevelop::ProjectBaseItem* item, const QUrl &installPrefix ) override; KJob* configure( KDevelop::IProject* ) override; + + KDevelop::Path compiler(KDevelop::ProjectTargetItem * p) const override; + Q_SIGNALS: void built( KDevelop::ProjectBaseItem *dom ); void installed( KDevelop::ProjectBaseItem* ); diff --git a/plugins/custom-buildsystem/custombuildsystemplugin.cpp b/plugins/custom-buildsystem/custombuildsystemplugin.cpp --- a/plugins/custom-buildsystem/custombuildsystemplugin.cpp +++ b/plugins/custom-buildsystem/custombuildsystemplugin.cpp @@ -195,4 +195,9 @@ return nullptr; } +KDevelop::Path CustomBuildSystem::compiler(KDevelop::ProjectTargetItem* item) const +{ + return {}; +} + #include "custombuildsystemplugin.moc" diff --git a/plugins/custom-definesandincludes/compilerprovider/compilerfactories.h b/plugins/custom-definesandincludes/compilerprovider/compilerfactories.h --- a/plugins/custom-definesandincludes/compilerprovider/compilerfactories.h +++ b/plugins/custom-definesandincludes/compilerprovider/compilerfactories.h @@ -32,6 +32,7 @@ CompilerPointer createCompiler( const QString& name, const QString& path, bool editable = true ) const override; QString name() const override; + bool isSupported(const KDevelop::Path& path) const override; void registerDefaultCompilers(CompilerProvider* provider) const override; }; @@ -42,6 +43,7 @@ CompilerPointer createCompiler( const QString& name, const QString& path, bool editable = true ) const override; QString name() const override; + bool isSupported(const KDevelop::Path& path) const override; void registerDefaultCompilers(CompilerProvider* provider) const override; }; @@ -52,6 +54,7 @@ CompilerPointer createCompiler( const QString& name, const QString& path, bool editable = true ) const override; QString name() const override; + bool isSupported(const KDevelop::Path& path) const override; void registerDefaultCompilers(CompilerProvider* provider) const override; }; diff --git a/plugins/custom-definesandincludes/compilerprovider/compilerfactories.cpp b/plugins/custom-definesandincludes/compilerprovider/compilerfactories.cpp --- a/plugins/custom-definesandincludes/compilerprovider/compilerfactories.cpp +++ b/plugins/custom-definesandincludes/compilerprovider/compilerfactories.cpp @@ -32,6 +32,12 @@ return QStringLiteral("Clang"); } +bool ClangFactory::isSupported(const KDevelop::Path& path) const +{ + const auto filename = path.lastPathSegment(); + return filename.contains(QLatin1String("clang")) && !filename.contains(QLatin1String("clang-cl")); +} + CompilerPointer ClangFactory::createCompiler(const QString& name, const QString& path, bool editable ) const { return CompilerPointer(new GccLikeCompiler(name, path, editable, this->name())); @@ -50,6 +56,11 @@ return QStringLiteral("GCC"); } +bool GccFactory::isSupported(const KDevelop::Path& path) const +{ + return path.lastPathSegment().contains(QLatin1String("gcc")) || path.lastPathSegment().contains(QLatin1String("g++")); +} + CompilerPointer GccFactory::createCompiler(const QString& name, const QString& path, bool editable ) const { return CompilerPointer(new GccLikeCompiler(name, path, editable, this->name())); @@ -77,3 +88,8 @@ { provider->registerCompiler(createCompiler(name(), QStringLiteral("cl.exe"), false)); } + +bool MsvcFactory::isSupported(const KDevelop::Path& path) const +{ + return path.lastPathSegment() == QLatin1String("cl.exe") || path.lastPathSegment().contains(QLatin1String("clang-cl")); +} diff --git a/plugins/custom-definesandincludes/compilerprovider/compilerprovider.h b/plugins/custom-definesandincludes/compilerprovider/compilerprovider.h --- a/plugins/custom-definesandincludes/compilerprovider/compilerprovider.h +++ b/plugins/custom-definesandincludes/compilerprovider/compilerprovider.h @@ -67,6 +67,7 @@ private Q_SLOTS: void retrieveUserDefinedCompilers(); + void projectChanged(KDevelop::IProject* p); private: mutable CompilerPointer m_defaultProvider; diff --git a/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp b/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp --- a/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp +++ b/plugins/custom-definesandincludes/compilerprovider/compilerprovider.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -101,6 +103,22 @@ } } +ProjectTargetItem* findCompiledTarget(ProjectBaseItem* item) +{ + for(auto item: item->targetList()) { + if (item->type() == ProjectBaseItem::ExecutableTarget || item->type() == ProjectBaseItem::LibraryTarget) { + return item; + } + } + + for(auto folder: item->folderList()) { + auto target = findCompiledTarget(folder); + if (target) + return target; + } + return nullptr; +} + CompilerProvider::CompilerProvider( SettingsManager* settings, QObject* parent ) : QObject( parent ) , m_settings(settings) @@ -127,10 +145,44 @@ retrieveUserDefinedCompilers(); connect(ICore::self()->runtimeController(), &IRuntimeController::currentRuntimeChanged, this, [this]() { m_defaultProvider.clear(); }); + connect(ICore::self()->projectController(), &IProjectController::projectConfigurationChanged, this, &CompilerProvider::projectChanged); + connect(ICore::self()->projectController(), &IProjectController::projectOpened, this, &CompilerProvider::projectChanged); } CompilerProvider::~CompilerProvider() = default; +void CompilerProvider::projectChanged(KDevelop::IProject* p) +{ + const auto target = findCompiledTarget(p->projectItem()); + if (!target) + return; + + auto path = p->buildSystemManager()->compiler(target); + qCDebug(DEFINESANDINCLUDES) << "found compiler" << path; + if (path.isEmpty()) + return; + + Q_ASSERT(QDir::isAbsolutePath(path.toLocalFile())); + const auto pathString = path.toLocalFile(); + auto it = std::find_if(m_compilers.begin(), m_compilers.end(), + [pathString](const CompilerPointer& compiler) { return compiler->path() == pathString; }); + if (it != m_compilers.end()) { + m_defaultProvider = *it; + return; + } + + //we need to search, sdk compiler names are weird: arm-linux-androideabi-g++ + for (auto factory : m_factories) { + if (factory->isSupported(path)) { + auto compiler = factory->createCompiler(path.lastPathSegment(), pathString); + const auto registered = registerCompiler(compiler); + m_defaultProvider = compiler; + } + } + + qCDebug(DEFINESANDINCLUDES) << "using compiler" << m_defaultProvider << path; +} + QHash CompilerProvider::defines( const QString& path ) const { auto config = configForItem(nullptr); diff --git a/plugins/custom-definesandincludes/compilerprovider/icompilerfactory.h b/plugins/custom-definesandincludes/compilerprovider/icompilerfactory.h --- a/plugins/custom-definesandincludes/compilerprovider/icompilerfactory.h +++ b/plugins/custom-definesandincludes/compilerprovider/icompilerfactory.h @@ -44,6 +44,9 @@ */ virtual void registerDefaultCompilers(CompilerProvider* provider) const = 0; + /** @returns whether @p path is a compiler supported by the factory */ + virtual bool isSupported(const KDevelop::Path &path) const = 0; + virtual ~ICompilerFactory() = default; }; diff --git a/plugins/custommake/custommakemanager.h b/plugins/custommake/custommakemanager.h --- a/plugins/custommake/custommakemanager.h +++ b/plugins/custommake/custommakemanager.h @@ -113,6 +113,8 @@ */ QList targets(KDevelop::ProjectFolderItem*) const override; + KDevelop::Path compiler(KDevelop::ProjectTargetItem * p) const override; + protected: KDevelop::ProjectFileItem* createFileItem(KDevelop::IProject* project, const KDevelop::Path& path, diff --git a/plugins/custommake/custommakemanager.cpp b/plugins/custommake/custommakemanager.cpp --- a/plugins/custommake/custommakemanager.cpp +++ b/plugins/custommake/custommakemanager.cpp @@ -324,5 +324,9 @@ IDefinesAndIncludesManager::manager()->unregisterBackgroundProvider(m_provider.data()); } -#include "custommakemanager.moc" +KDevelop::Path CustomMakeManager::compiler(KDevelop::ProjectTargetItem* item) const +{ + return {}; +} +#include "custommakemanager.moc" diff --git a/plugins/qmakemanager/qmakemanager.h b/plugins/qmakemanager/qmakemanager.h --- a/plugins/qmakemanager/qmakemanager.h +++ b/plugins/qmakemanager/qmakemanager.h @@ -82,6 +82,8 @@ } QList targets(KDevelop::ProjectFolderItem*) const override; + + KDevelop::Path compiler(KDevelop::ProjectTargetItem* item) const override; //END IBuildSystemManager private Q_SLOTS: diff --git a/plugins/qmakemanager/qmakemanager.cpp b/plugins/qmakemanager/qmakemanager.cpp --- a/plugins/qmakemanager/qmakemanager.cpp +++ b/plugins/qmakemanager/qmakemanager.cpp @@ -514,4 +514,9 @@ KDevelop::ICore::self()->runController()->registerJob(job); } +KDevelop::Path QMakeProjectManager::compiler(KDevelop::ProjectTargetItem* p) const +{ + return {}; +} + #include "qmakemanager.moc"