diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index ecc12a98279..208ca398fe4 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -480,7 +480,8 @@ BuildConfiguration *QbsBuildConfigurationFactory::create(Target *parent, const B QTC_ASSERT(info->kitId == parent->kit()->id(), return 0); QTC_ASSERT(!info->displayName.isEmpty(), return 0); - QVariantMap configData; + const QbsBuildInfo * const bi = static_cast(info); + QVariantMap configData = bi->config; configData.insert(QLatin1String(Constants::QBS_CONFIG_VARIANT_KEY), (info->buildType == BuildConfiguration::Debug) ? QLatin1String(Constants::QBS_VARIANT_DEBUG) diff --git a/src/plugins/qbsprojectmanager/qbsbuildinfo.h b/src/plugins/qbsprojectmanager/qbsbuildinfo.h index a6cf23c764a..ea92b650554 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildinfo.h +++ b/src/plugins/qbsprojectmanager/qbsbuildinfo.h @@ -28,6 +28,8 @@ #include +#include + namespace QbsProjectManager { namespace Internal { @@ -36,6 +38,8 @@ class QbsBuildInfo final : public ProjectExplorer::BuildInfo public: QbsBuildInfo(const ProjectExplorer::IBuildConfigurationFactory *f); + QVariantMap config; + private: QList reportIssues(const QString &projectPath, const QString &buildDir) const override; diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 693023ece41..e459d26a898 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -28,6 +28,7 @@ #include "qbsbuildconfiguration.h" #include "qbslogsink.h" #include "qbspmlogging.h" +#include "qbsprojectimporter.h" #include "qbsprojectparser.h" #include "qbsprojectmanagerconstants.h" #include "qbsnodes.h" @@ -152,6 +153,7 @@ QbsProject::~QbsProject() { delete m_cppCodeModelUpdater; delete m_qbsProjectParser; + delete m_importer; if (m_qbsUpdateFutureInterface) { m_qbsUpdateFutureInterface->reportCanceled(); m_qbsUpdateFutureInterface->reportFinished(); @@ -171,6 +173,13 @@ void QbsProject::projectLoaded() m_parsingDelay.start(0); } +ProjectImporter *QbsProject::projectImporter() const +{ + if (!m_importer) + m_importer = new QbsProjectImporter(projectFilePath()); + return m_importer; +} + QStringList QbsProject::filesGeneratedFrom(const QString &sourceFile) const { QStringList generated; @@ -654,19 +663,6 @@ void QbsProject::registerQbsProjectParser(QbsProjectParser *p) } } -Project::RestoreResult QbsProject::fromMap(const QVariantMap &map, QString *errorMessage) -{ - RestoreResult result = Project::fromMap(map, errorMessage); - if (result != RestoreResult::Ok) - return result; - - Kit *defaultKit = KitManager::defaultKit(); - if (!activeTarget() && defaultKit) - addTarget(createTarget(defaultKit)); - - return RestoreResult::Ok; -} - void QbsProject::generateErrors(const qbs::ErrorInfo &e) { foreach (const qbs::ErrorItem &item, e.items()) diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 017934156dc..82f20ab2445 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -122,8 +122,6 @@ private: void buildConfigurationChanged(ProjectExplorer::BuildConfiguration *bc); void startParsing(); - RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; - void parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir, const QString &configName); @@ -139,7 +137,11 @@ private: bool checkCancelStatus(); void updateAfterParse(); void updateProjectNodes(); + void projectLoaded() override; + ProjectExplorer::ProjectImporter *projectImporter() const override; + bool needsConfiguration() const override { return targets().isEmpty(); } + bool requiresTargetPanel() const override { return !targets().isEmpty(); } static bool ensureWriteableQbsFile(const QString &file); @@ -166,6 +168,7 @@ private: CppTools::ProjectInfo m_cppCodeModelProjectInfo; QbsBuildConfiguration *m_currentBc; + mutable ProjectExplorer::ProjectImporter *m_importer = nullptr; QTimer m_parsingDelay; QList m_extraCompilers; diff --git a/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp new file mode 100644 index 00000000000..406039e40f4 --- /dev/null +++ b/src/plugins/qbsprojectmanager/qbsprojectimporter.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "qbsprojectimporter.h" + +#include "qbsbuildconfiguration.h" +#include "qbsbuildinfo.h" +#include "qbspmlogging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace QbsProjectManager { +namespace Internal { + +struct BuildGraphData +{ + FileName bgFilePath; + QVariantMap overriddenProperties; + FileName cCompilerPath; + FileName cxxCompilerPath; + FileName qtBinPath; + FileName sysroot; + QString buildVariant; +}; +static BuildGraphData extractBgData(const qbs::Project::BuildGraphInfo &bgInfo) +{ + BuildGraphData bgData; + bgData.bgFilePath = FileName::fromString(bgInfo.bgFilePath); + bgData.overriddenProperties = bgInfo.overriddenProperties; + const QVariantMap &moduleProps = bgInfo.requestedProperties; + const QVariantMap prjCompilerPathByLanguage + = moduleProps.value("cpp.compilerPathByLanguage").toMap(); + const QString prjCompilerPath = moduleProps.value("cpp.compilerPath").toString(); + const QStringList prjToolchain = moduleProps.value("qbs.toolchain").toStringList(); + const bool prjIsMsvc = prjToolchain.contains("msvc"); + bgData.cCompilerPath = FileName::fromString( + prjIsMsvc ? prjCompilerPath : prjCompilerPathByLanguage.value("c").toString()); + bgData.cxxCompilerPath = FileName::fromString( + prjIsMsvc ? prjCompilerPath : prjCompilerPathByLanguage.value("cpp").toString()); + bgData.qtBinPath = FileName::fromString(moduleProps.value("Qt.core.binPath").toString()); + bgData.sysroot = FileName::fromString(moduleProps.value("qbs.sysroot").toString()); + bgData.buildVariant = moduleProps.value("qbs.buildVariant").toString(); + return bgData; +} + +QbsProjectImporter::QbsProjectImporter(const FileName &path) : QtProjectImporter(path) +{ +} + +static QString buildDir(const QString &projectFilePath, const Kit *k) +{ + const QString projectName = QFileInfo(projectFilePath).completeBaseName(); + ProjectMacroExpander expander(projectFilePath, projectName, k, QString(), + BuildConfiguration::Unknown); + const QString projectDir + = Project::projectDirectory(FileName::fromString(projectFilePath)).toString(); + const QString buildPath = expander.expand(Core::DocumentManager::buildDirectory()); + return FileUtils::resolvePath(projectDir, buildPath); +} + +static bool hasBuildGraph(const QString &dir) +{ + const QString &dirName = QFileInfo(dir).fileName(); + return QFileInfo::exists(dir + QLatin1Char('/') + dirName + QLatin1String(".bg")); +} + +static QStringList candidatesForDirectory(const QString &dir) +{ + QStringList candidates; + for (const QString &subDir : QDir(dir).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + const QString absSubDir = dir + QLatin1Char('/') + subDir; + if (hasBuildGraph(absSubDir)) + candidates << absSubDir; + } + return candidates; +} + +QStringList QbsProjectImporter::importCandidates() +{ + const QString projectDir = QFileInfo(projectFilePath().toString()).absolutePath(); + QStringList candidates = candidatesForDirectory(projectDir); + + QSet seenCandidates; + seenCandidates.insert(projectDir); + for (Kit * const k : KitManager::kits()) { + QFileInfo fi(buildDir(projectFilePath().toString(), k)); + const QString candidate = fi.absolutePath(); + if (!seenCandidates.contains(candidate)) { + seenCandidates.insert(candidate); + candidates << candidatesForDirectory(candidate); + } + } + qCDebug(qbsPmLog) << "build directory candidates:" << candidates; + return candidates; +} + +QList QbsProjectImporter::examineDirectory(const FileName &importPath) const +{ + qCDebug(qbsPmLog) << "examining build directory" << importPath.toUserOutput(); + QList data; + const QString bgFilePath = importPath.toString() + QLatin1Char('/') + importPath.fileName() + + QLatin1String(".bg"); + const QStringList relevantProperties({ + "qbs.buildVariant", "qbs.sysroot", "qbs.toolchain", + "cpp.compilerPath", "cpp.compilerPathByLanguage", + "Qt.core.binPath" + }); + const qbs::Project::BuildGraphInfo bgInfo + = qbs::Project::getBuildGraphInfo(bgFilePath, relevantProperties); + if (bgInfo.error.hasError()) { + qCDebug(qbsPmLog) << "error getting build graph info:" << bgInfo.error.toString(); + return data; + } + qCDebug(qbsPmLog) << "retrieved build graph info:" << bgInfo.requestedProperties; + data << new BuildGraphData(extractBgData(bgInfo)); + return data; +} + +bool QbsProjectImporter::matchKit(void *directoryData, const Kit *k) const +{ + const auto * const bgData = static_cast(directoryData); + qCDebug(qbsPmLog) << "matching kit" << k->displayName() << "against imported build" + << bgData->bgFilePath.toUserOutput(); + if (ToolChainKitInformation::toolChains(k).isEmpty() && bgData->cCompilerPath.isEmpty() + && bgData->cxxCompilerPath.isEmpty()) { + return true; + } + const ToolChain * const cToolchain + = ToolChainKitInformation::toolChain(k, Constants::C_LANGUAGE_ID); + const ToolChain * const cxxToolchain + = ToolChainKitInformation::toolChain(k, Constants::CXX_LANGUAGE_ID); + if (!bgData->cCompilerPath.isEmpty()) { + if (!cToolchain) + return false; + if (bgData->cCompilerPath != cToolchain->compilerCommand()) + return false; + } + if (!bgData->cxxCompilerPath.isEmpty()) { + if (!cxxToolchain) + return false; + if (bgData->cxxCompilerPath != cxxToolchain->compilerCommand()) + return false; + } + const QtSupport::BaseQtVersion * const qtVersion = QtSupport::QtKitInformation::qtVersion(k); + if (!bgData->qtBinPath.isEmpty()) { + if (!qtVersion) + return false; + if (bgData->qtBinPath != qtVersion->binPath()) + return false; + } + if (bgData->sysroot != SysRootKitInformation::sysRoot(k)) + return false; + + qCDebug(qbsPmLog) << "Kit matches"; + return true; +} + +Kit *QbsProjectImporter::createKit(void *directoryData) const +{ + const auto * const bgData = static_cast(directoryData); + qCDebug(qbsPmLog) << "creating kit for imported build" << bgData->bgFilePath.toUserOutput(); + QtVersionData qtVersionData; + if (!bgData->qtBinPath.isEmpty()) { + FileName qmakeFilePath = bgData->qtBinPath; + qmakeFilePath.appendPath(HostOsInfo::withExecutableSuffix("qmake")); + qtVersionData = findOrCreateQtVersion(qmakeFilePath); + } + return createTemporaryKit(qtVersionData,[this, bgData](Kit *k) -> void { + QList tcData; + if (!bgData->cxxCompilerPath.isEmpty()) + tcData << findOrCreateToolChains(bgData->cxxCompilerPath, Constants::CXX_LANGUAGE_ID); + if (!bgData->cCompilerPath.isEmpty()) + tcData << findOrCreateToolChains(bgData->cCompilerPath, Constants::C_LANGUAGE_ID); + foreach (const ToolChainData &tc, tcData) { + if (!tc.tcs.isEmpty()) + ToolChainKitInformation::setToolChain(k, tc.tcs.first()); + } + SysRootKitInformation::setSysRoot(k, bgData->sysroot); + }); +} + +QList QbsProjectImporter::buildInfoListForKit(const Kit *k, void *directoryData) const +{ + qCDebug(qbsPmLog) << "creating build info for kit" << k->displayName(); + QList result; + const auto factory = qobject_cast( + IBuildConfigurationFactory::find(k, projectFilePath().toString())); + if (!factory) { + qCDebug(qbsPmLog) << "no build config factory found"; + return result; + } + const auto * const bgData = static_cast(directoryData); + QbsBuildInfo * const buildInfo = new QbsBuildInfo(factory); + buildInfo->displayName = bgData->bgFilePath.toFileInfo().completeBaseName(); + buildInfo->buildType = bgData->buildVariant == "debug" + ? BuildConfiguration::Debug : BuildConfiguration::Release; + buildInfo->kitId = k->id(); + buildInfo->buildDirectory = bgData->bgFilePath.parentDir().parentDir(); + buildInfo->config = bgData->overriddenProperties; + buildInfo->config.insert("configName", buildInfo->displayName); + return result << buildInfo; +} + +void QbsProjectImporter::deleteDirectoryData(void *directoryData) const +{ + delete static_cast(directoryData); +} + +} // namespace Internal +} // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsprojectimporter.h b/src/plugins/qbsprojectmanager/qbsprojectimporter.h new file mode 100644 index 00000000000..2980a70834e --- /dev/null +++ b/src/plugins/qbsprojectmanager/qbsprojectimporter.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +namespace QbsProjectManager { +namespace Internal { + +class QbsProjectImporter final : public QtSupport::QtProjectImporter +{ + Q_OBJECT + +public: + QbsProjectImporter(const Utils::FileName &path); + +private: + QStringList importCandidates() override; + QList examineDirectory(const Utils::FileName &importPath) const override; + bool matchKit(void *directoryData, const ProjectExplorer::Kit *k) const override; + ProjectExplorer::Kit *createKit(void *directoryData) const override; + QList buildInfoListForKit(const ProjectExplorer::Kit *k, + void *directoryData) const override; + void deleteDirectoryData(void *directoryData) const override; +}; + +} // namespace Internal +} // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro index 2136cc0a45c..0270bf053c4 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.pro +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.pro @@ -36,6 +36,7 @@ HEADERS = \ qbspmlogging.h \ qbsprofilessettingspage.h \ qbsproject.h \ + qbsprojectimporter.h \ qbsprojectmanager.h \ qbsprojectmanager_global.h \ qbsprojectmanagerconstants.h \ @@ -62,6 +63,7 @@ SOURCES = \ qbspmlogging.cpp \ qbsprofilessettingspage.cpp \ qbsproject.cpp \ + qbsprojectimporter.cpp \ qbsprojectmanager.cpp \ qbsprojectmanagerplugin.cpp \ qbsprojectmanagersettings.cpp \ diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs index deba289d042..1b5a27ef974 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs +++ b/src/plugins/qbsprojectmanager/qbsprojectmanager.qbs @@ -99,6 +99,8 @@ QtcPlugin { "qbsprofilessettingswidget.ui", "qbsproject.cpp", "qbsproject.h", + "qbsprojectimporter.cpp", + "qbsprojectimporter.h", "qbsprojectmanager.cpp", "qbsprojectmanager.h", "qbsprojectmanager.qrc",