diff --git a/plugins/meson/mesonmanager.cpp b/plugins/meson/mesonmanager.cpp index 858634bea2..81e815df61 100644 --- a/plugins/meson/mesonmanager.cpp +++ b/plugins/meson/mesonmanager.cpp @@ -1,174 +1,251 @@ /* This file is part of KDevelop Copyright 2017 Aleix Pol Gonzalez Copyright 2018 Daniel Mensinger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mesonmanager.h" #include "mesonbuilder.h" #include "mesonconfig.h" +#include "mesonintrospectjob.h" +#include "mesontargets.h" #include "settings/mesonconfigpage.h" #include "settings/mesonnewbuilddir.h" #include #include #include #include #include #include #include #include #include #include "debug.h" using namespace KDevelop; static const QString GENERATOR_NINJA = QStringLiteral("ninja"); K_PLUGIN_FACTORY_WITH_JSON(MesonSupportFactory, "kdevmesonmanager.json", registerPlugin();) MesonManager::MesonManager(QObject* parent, const QVariantList& args) : AbstractFileManagerPlugin(QStringLiteral("KDevMesonManager"), parent, args) , m_builder(new MesonBuilder(this)) { if (m_builder->hasError()) { setErrorDescription(i18n("Meson builder error: %1", m_builder->errorDescription())); } } MesonManager::~MesonManager() { delete m_builder; } // ********************************* // * AbstractFileManagerPlugin API * // ********************************* IProjectFileManager::Features MesonManager::features() const { return IProjectFileManager::Files | IProjectFileManager::Folders | IProjectFileManager::Targets; } ProjectFolderItem* MesonManager::createFolderItem(IProject* project, const Path& path, ProjectBaseItem* parent) { // TODO: Maybe use meson targets instead if (QFile::exists(path.toLocalFile() + QStringLiteral("/meson.build"))) return new ProjectBuildFolderItem(project, path, parent); else return AbstractFileManagerPlugin::createFolderItem(project, path, parent); } // *************************** // * IBuildSystemManager API * // *************************** KJob* MesonManager::createImportJob(ProjectFolderItem* item) { - auto project = item->project(); + IProject* project = item->project(); + auto buildDir = Meson::currentBuildDir(project); + auto introJob = new MesonIntrospectJob(project->path(), buildDir, { MesonIntrospectJob::TARGETS }, + MesonIntrospectJob::BUILD_DIR, this); + + connect(introJob, &KJob::result, this, [this, introJob, project]() { + auto targets = introJob->targets(); + if (!targets) { + qCWarning(KDEV_Meson) << "Failed to import targets from project" << project->name(); + return; + } + m_projectTargets[project] = targets; + }); const QList jobs = { builder()->configure(project), // Make sure the project is configured + introJob, // Load targets from the build directory introspection files AbstractFileManagerPlugin::createImportJob(item) // generate the file system listing }; Q_ASSERT(!jobs.contains(nullptr)); auto composite = new ExecuteCompositeJob(this, jobs); composite->setAbortOnError(false); return composite; } Path MesonManager::buildDirectory(ProjectBaseItem* item) const { Q_ASSERT(item); Meson::BuildDir buildDir = Meson::currentBuildDir(item->project()); return buildDir.buildDir; } IProjectBuilder* MesonManager::builder() const { return m_builder; } -KJob *MesonManager::newBuildDirectory(IProject* project) +MESON_SOURCE MesonManager::sourceFromItem(KDevelop::ProjectBaseItem* item) const +{ + Q_ASSERT(item); + auto it = m_projectTargets.find(item->project()); + if (it == end(m_projectTargets)) { + qCDebug(KDEV_Meson) << item->path().toLocalFile() << "not found"; + return {}; + } + + auto targets = *it; + return targets->fileSource(item->path()); +} + +KDevelop::Path::List MesonManager::includeDirectories(KDevelop::ProjectBaseItem* item) const +{ + auto src = sourceFromItem(item); + if (!src) { + return {}; + } + return src->includeDirs(); +} + +KDevelop::Path::List MesonManager::frameworkDirectories(KDevelop::ProjectBaseItem*) const +{ + return {}; +} + +QHash MesonManager::defines(KDevelop::ProjectBaseItem* item) const +{ + auto src = sourceFromItem(item); + if (!src) { + return {}; + } + return src->defines(); +} + +QString MesonManager::extraArguments(KDevelop::ProjectBaseItem* item) const +{ + auto src = sourceFromItem(item); + if (!src) { + return {}; + } + return src->extraArgs().join(QChar::fromLatin1(' ')); +} + +bool MesonManager::hasBuildInfo(KDevelop::ProjectBaseItem* item) const +{ + auto src = sourceFromItem(item); + if (!src) { + return false; + } + return true; +} + +// ******************** +// * Custom functions * +// ******************** + +KJob* MesonManager::newBuildDirectory(IProject* project) { Q_ASSERT(project); MesonNewBuildDir newBD(project); if (!newBD.exec() || !newBD.isConfigValid()) { qCWarning(KDEV_Meson) << "Failed to create new build directory for project " << project->name(); return nullptr; } Meson::BuildDir buildDir = newBD.currentConfig(); Meson::MesonConfig mesonCfg = Meson::getMesonConfig(project); buildDir.canonicalizePaths(); mesonCfg.currentIndex = mesonCfg.addBuildDir(buildDir); Meson::writeMesonConfig(project, mesonCfg); return m_builder->configure(project, buildDir, newBD.mesonArgs()); } QStringList MesonManager::supportedMesonBackends() const { // Maybe add support for other generators return { GENERATOR_NINJA }; } QString MesonManager::defaultMesonBackend() const { return GENERATOR_NINJA; } Path MesonManager::findMeson() const { QString mesonPath; const static QStringList mesonExecutables = { QStringLiteral("meson"), QStringLiteral("meson.py") }; const static QStringList mesonPaths = { QStringLiteral("%1/.local/bin").arg(QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0]) }; for (auto const& i : mesonExecutables) { mesonPath = QStandardPaths::findExecutable(i); if (!mesonPath.isEmpty()) { break; } mesonPath = QStandardPaths::findExecutable(i, mesonPaths); if (!mesonPath.isEmpty()) { break; } } return Path(mesonPath); } +// *********** +// * IPlugin * +// *********** + ConfigPage* MesonManager::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) { if (number == 0) { return new MesonConfigPage(this, options.project, parent); } return nullptr; } int MesonManager::perProjectConfigPages() const { return 1; } #include "mesonmanager.moc" diff --git a/plugins/meson/mesonmanager.h b/plugins/meson/mesonmanager.h index f3cc4f9f78..d670f9633a 100644 --- a/plugins/meson/mesonmanager.h +++ b/plugins/meson/mesonmanager.h @@ -1,109 +1,117 @@ /* This file is part of KDevelop Copyright 2017 Aleix Pol Gonzalez Copyright 2018 Daniel Mensinger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_PLUGIN_MESONMANAGER_H #define KDEVPLATFORM_PLUGIN_MESONMANAGER_H #include "mesonconfig.h" +#include #include #include class MesonBuilder; +class MesonTargets; +class MesonTargetSources; + +using MESON_SOURCE = std::shared_ptr; +using MESON_TGT_PTR = std::shared_ptr; class MesonManager : public KDevelop::AbstractFileManagerPlugin, public KDevelop::IBuildSystemManager { Q_OBJECT Q_INTERFACES(KDevelop::IBuildSystemManager) public: explicit MesonManager(QObject* parent = nullptr, const QVariantList& args = QVariantList()); ~MesonManager() override; // ******************** // * Custom functions * // ******************** /** * Create a new build directory and write it into the config. * @returns The configuration job on success or nullptr on error. */ - KJob *newBuildDirectory(KDevelop::IProject* project); + KJob* newBuildDirectory(KDevelop::IProject* project); /// Returns a list of all supported Meson backends (for now only ninja) QStringList supportedMesonBackends() const; QString defaultMesonBackend() const; KDevelop::Path findMeson() const; // ********************************* // * AbstractFileManagerPlugin API * // ********************************* KDevelop::IProjectFileManager::Features features() const override; KDevelop::ProjectFolderItem* createFolderItem(KDevelop::IProject* project, const KDevelop::Path& path, KDevelop::ProjectBaseItem* parent = nullptr) override; // *********** // * IPlugin * // *********** KDevelop::ConfigPage* perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) override; int perProjectConfigPages() const override; // *************************** // * IBuildSystemManager API * // *************************** KJob* createImportJob(KDevelop::ProjectFolderItem* item) override; KDevelop::IProjectBuilder* builder() const override; - // FIXME now: should use compile_commands.json for these (i.e. m_projects) - KDevelop::Path::List includeDirectories(KDevelop::ProjectBaseItem*) const override { return {}; } - KDevelop::Path::List frameworkDirectories(KDevelop::ProjectBaseItem*) const override { return {}; } - QHash defines(KDevelop::ProjectBaseItem*) const override { return {}; } - QString extraArguments(KDevelop::ProjectBaseItem* /*item*/) const override { return {}; } - bool hasBuildInfo(KDevelop::ProjectBaseItem* /*item*/) const override { return false; } + KDevelop::Path::List includeDirectories(KDevelop::ProjectBaseItem* item) const override; + KDevelop::Path::List frameworkDirectories(KDevelop::ProjectBaseItem* item) const override; + QHash defines(KDevelop::ProjectBaseItem* item) const override; + QString extraArguments(KDevelop::ProjectBaseItem* item) const override; + bool hasBuildInfo(KDevelop::ProjectBaseItem* item) const override; KDevelop::Path buildDirectory(KDevelop::ProjectBaseItem*) const override; // fill if&when we have targets QList targets(KDevelop::ProjectFolderItem*) const override { return {}; } // you can ignore these for now I guess, but TODO KDevelop::ProjectTargetItem* createTarget(const QString& /*target*/, KDevelop::ProjectFolderItem* /*parent*/) override { return nullptr; } bool removeTarget(KDevelop::ProjectTargetItem* /*target*/) override { return false; } bool addFilesToTarget(const QList& /*files*/, KDevelop::ProjectTargetItem* /*target*/) override { return false; } bool removeFilesFromTargets(const QList& /*files*/) override { return false; } private: MesonBuilder* m_builder; + QHash m_projectTargets; + + MESON_SOURCE sourceFromItem(KDevelop::ProjectBaseItem* item) const; }; #endif diff --git a/plugins/meson/mesontargets.cpp b/plugins/meson/mesontargets.cpp index f08f8c4b97..02ea38a4a9 100644 --- a/plugins/meson/mesontargets.cpp +++ b/plugins/meson/mesontargets.cpp @@ -1,248 +1,255 @@ /* This file is part of KDevelop Copyright 2019 Daniel Mensinger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mesontargets.h" #include #include #include #include using namespace std; using namespace KDevelop; // MesonTargetSources MesonTargetSources::MesonTargetSources(const QJsonObject& json, MesonTarget* target) : m_target(target) { fromJSON(json); } MesonTargetSources::~MesonTargetSources() {} QString MesonTargetSources::language() const { return m_language; } QStringList MesonTargetSources::compiler() const { return m_compiler; } QStringList MesonTargetSources::paramerters() const { return m_paramerters; } KDevelop::Path::List MesonTargetSources::sources() const { return m_sources; } KDevelop::Path::List MesonTargetSources::generatedSources() const { return m_generatedSources; } KDevelop::Path::List MesonTargetSources::allSources() const { return m_sources + m_generatedSources; } KDevelop::Path::List MesonTargetSources::includeDirs() const { return m_includeDirs; } QHash MesonTargetSources::defines() const { return m_defines; } QStringList MesonTargetSources::extraArgs() const { return m_extraArgs; } MesonTarget* MesonTargetSources::target() { return m_target; } void MesonTargetSources::fromJSON(const QJsonObject& json) { m_language = json[QStringLiteral("language")].toString(); QJsonArray comp = json[QStringLiteral("compiler")].toArray(); QJsonArray param = json[QStringLiteral("parameters")].toArray(); QJsonArray src = json[QStringLiteral("sources")].toArray(); QJsonArray gensrc = json[QStringLiteral("generated_sources")].toArray(); transform(begin(comp), end(comp), back_inserter(m_compiler), [](auto const& x) { return x.toString(); }); transform(begin(param), end(param), back_inserter(m_paramerters), [](auto const& x) { return x.toString(); }); transform(begin(src), end(src), back_inserter(m_sources), [](auto const& x) { return Path(x.toString()); }); transform(begin(gensrc), end(gensrc), back_inserter(m_generatedSources), [](auto const& x) { return Path(x.toString()); }); splitParamerters(); - qCDebug(KDEV_Meson) << " - language: '" << m_language << "' " << m_sources.count() + m_generatedSources.count() - << " files with " << m_includeDirs.count() << " include directories and " << m_defines.count() - << " defines"; + qCDebug(KDEV_Meson) << " - language:" << m_language << "has" << m_sources.count() + m_generatedSources.count() + << "files with" << m_includeDirs.count() << "include directories and" << m_defines.count() + << "defines"; } void MesonTargetSources::splitParamerters() { for (QString const& i : m_paramerters) { [&]() { for (auto j : { QStringLiteral("-I"), QStringLiteral("/I"), QStringLiteral("-isystem") }) { if (i.startsWith(j)) { m_includeDirs << Path(i.mid(j.size())); return; } } for (auto j : { QStringLiteral("-D"), QStringLiteral("/D") }) { if (i.startsWith(j)) { QString define = i.mid(j.size()); QString name = define; QString value; int equalPos = define.indexOf(QChar::fromLatin1('=')); if (equalPos > 0) { name = define.left(equalPos); value = define.mid(equalPos + 1); } m_defines[name] = value; return; } } m_extraArgs << i; }(); } } // MesonTarget MesonTarget::MesonTarget(const QJsonObject& json) { fromJSON(json); } MesonTarget::~MesonTarget() {} QString MesonTarget::name() const { return m_name; } QString MesonTarget::type() const { return m_type; } QStringList MesonTarget::filename() const { return m_filename; } +KDevelop::Path MesonTarget::definedIn() const +{ + return m_definedIn; +} + bool MesonTarget::buildByDefault() const { return m_buildByDefault; } bool MesonTarget::installed() const { return m_installed; } MESON_SOURCES MesonTarget::targetSources() { return m_targetSources; } void MesonTarget::fromJSON(const QJsonObject& json) { m_name = json[QStringLiteral("name")].toString(); m_type = json[QStringLiteral("type")].toString(); + m_definedIn = Path(json[QStringLiteral("defined_in")].toString()); m_buildByDefault = json[QStringLiteral("build_by_default")].toBool(); m_installed = json[QStringLiteral("installed")].toBool(); QJsonArray files = json[QStringLiteral("filename")].toArray(); transform(begin(files), end(files), back_inserter(m_filename), [](auto const& x) { return x.toString(); }); - qCDebug(KDEV_Meson) << " - " << m_type << " '" << m_name << "': " << m_filename.join(QStringLiteral(", ")); + qCDebug(KDEV_Meson) << " - " << m_type << m_name << "output:" << m_filename.join(QStringLiteral(" and ")); for (auto const& i : json[QStringLiteral("target_sources")].toArray()) { m_targetSources << make_shared(i.toObject(), this); } } // MesonTargets MesonTargets::MesonTargets(const QJsonArray& json) { fromJSON(json); } MesonTargets::~MesonTargets() {} MESON_TARGETS MesonTargets::targets() { return m_targets; } MESON_SOURCE MesonTargets::fileSource(KDevelop::Path p) { auto it = m_sourceHash.find(p); if (it == end(m_sourceHash)) { return nullptr; } return *it; } MESON_SOURCE MesonTargets::operator[](KDevelop::Path p) { return fileSource(p); } void MesonTargets::fromJSON(const QJsonArray& json) { qCDebug(KDEV_Meson) << "MINTRO: Loading targets from json..."; for (auto const& i : json) { m_targets << make_shared(i.toObject()); } buildHashMap(); - qCDebug(KDEV_Meson) << "MINTRO: Loaded " << m_targets.count() << " with " << m_sourceHash.count() << " total files"; + qCDebug(KDEV_Meson) << "MINTRO: Loaded" << m_targets.count() << "targets with" << m_sourceHash.count() + << "total files"; } void MesonTargets::buildHashMap() { for (auto& i : m_targets) { for (auto j : i->targetSources()) { for (auto k : j->allSources()) { m_sourceHash[k] = j; } } } } diff --git a/plugins/meson/mesontargets.h b/plugins/meson/mesontargets.h index 255b23d79d..1a0bfb4f47 100644 --- a/plugins/meson/mesontargets.h +++ b/plugins/meson/mesontargets.h @@ -1,121 +1,123 @@ /* This file is part of KDevelop Copyright 2019 Daniel Mensinger This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include #include #include #include class QJsonArray; class QJsonObject; class MesonTarget; class MesonTargets; class MesonTargetSources; using MESON_SOURCE = std::shared_ptr; using MESON_SOURCES = QVector; using MESON_TARGET = std::shared_ptr; using MESON_TARGETS = QVector; -using MESON_TGT_PTR =std::shared_ptr; +using MESON_TGT_PTR = std::shared_ptr; class MesonTargetSources { public: explicit MesonTargetSources(QJsonObject const& json, MesonTarget* target); virtual ~MesonTargetSources(); QString language() const; QStringList compiler() const; QStringList paramerters() const; KDevelop::Path::List sources() const; KDevelop::Path::List generatedSources() const; KDevelop::Path::List allSources() const; KDevelop::Path::List includeDirs() const; QHash defines() const; QStringList extraArgs() const; MesonTarget* target(); void fromJSON(QJsonObject const& json); private: QString m_language; QStringList m_compiler; QStringList m_paramerters; KDevelop::Path::List m_sources; KDevelop::Path::List m_generatedSources; KDevelop::Path::List m_includeDirs; QHash m_defines; QStringList m_extraArgs; MesonTarget* m_target; // Store a pointer to the parent target void splitParamerters(); }; class MesonTarget { public: explicit MesonTarget(QJsonObject const& json); virtual ~MesonTarget(); QString name() const; QString type() const; + KDevelop::Path definedIn() const; QStringList filename() const; bool buildByDefault() const; bool installed() const; MESON_SOURCES targetSources(); void fromJSON(QJsonObject const& json); private: QString m_name; QString m_type; + KDevelop::Path m_definedIn; QStringList m_filename; bool m_buildByDefault; bool m_installed; MESON_SOURCES m_targetSources; }; class MesonTargets { public: explicit MesonTargets(QJsonArray const& json); virtual ~MesonTargets(); MESON_TARGETS targets(); MESON_SOURCE fileSource(KDevelop::Path p); MESON_SOURCE operator[](KDevelop::Path p); void fromJSON(QJsonArray const& json); private: MESON_TARGETS m_targets; QHash m_sourceHash; void buildHashMap(); };