diff options
127 files changed, 2511 insertions, 2502 deletions
diff --git a/src/plugins/android/androidextralibrarylistmodel.cpp b/src/plugins/android/androidextralibrarylistmodel.cpp index 0890cbefb30..58c6c2c8a78 100644 --- a/src/plugins/android/androidextralibrarylistmodel.cpp +++ b/src/plugins/android/androidextralibrarylistmodel.cpp @@ -45,11 +45,11 @@ AndroidExtraLibraryListModel::AndroidExtraLibraryListModel(ProjectExplorer::Targ { updateModel(); - connect(target->project(), &ProjectExplorer::Project::parsingStarted, + connect(target, &Target::parsingStarted, this, &AndroidExtraLibraryListModel::updateModel); - connect(target->project(), &ProjectExplorer::Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &AndroidExtraLibraryListModel::updateModel); - connect(target, &ProjectExplorer::Target::activeRunConfigurationChanged, + connect(target, &Target::activeRunConfigurationChanged, this, &AndroidExtraLibraryListModel::updateModel); } diff --git a/src/plugins/android/androidrunconfiguration.cpp b/src/plugins/android/androidrunconfiguration.cpp index ac4aa5f0c0c..1d562ad16b9 100644 --- a/src/plugins/android/androidrunconfiguration.cpp +++ b/src/plugins/android/androidrunconfiguration.cpp @@ -132,7 +132,7 @@ AndroidRunConfiguration::AndroidRunConfiguration(Target *target, Core::Id id) postStartShellCmdAspect->setSettingsKey("Android.PostStartShellCmdListKey"); postStartShellCmdAspect->setLabel(tr("Shell commands to run on Android device after application quits.")); - connect(target->project(), &Project::parsingFinished, this, [this] { + connect(target, &Target::parsingFinished, this, [this] { updateTargetInformation(); AndroidManager::updateGradleProperties(this->target(), buildKey()); }); diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp index 177ebdad2fa..9a9e69a08f9 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp @@ -42,13 +42,13 @@ using namespace ProjectExplorer; namespace AutotoolsProjectManager { namespace Internal { -AutotoolsBuildSystem::AutotoolsBuildSystem(Project *project) - : BuildSystem(project) +AutotoolsBuildSystem::AutotoolsBuildSystem(Target *target) + : BuildSystem(target) , m_cppCodeModelUpdater(new CppTools::CppProjectUpdater) { - connect(project, &Project::activeBuildConfigurationChanged, this, [this]() { requestParse(); }); + connect(target, &Target::activeBuildConfigurationChanged, this, [this]() { requestParse(); }); - connect(project, &Project::projectFileIsDirty, this, [this]() { requestParse(); }); + connect(target->project(), &Project::projectFileIsDirty, this, [this]() { requestParse(); }); } AutotoolsBuildSystem::~AutotoolsBuildSystem() @@ -62,7 +62,7 @@ AutotoolsBuildSystem::~AutotoolsBuildSystem() } } -void AutotoolsBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) +void AutotoolsBuildSystem::triggerParsing() { if (m_makefileParserThread) { // The thread is still busy parsing a previous configuration. @@ -78,8 +78,7 @@ void AutotoolsBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) } // Parse the makefile asynchronously in a thread - m_makefileParserThread = new MakefileParserThread(project()->projectFilePath().toString(), - std::move(ctx.guard)); + m_makefileParserThread = new MakefileParserThread(this); connect(m_makefileParserThread, &MakefileParserThread::finished, @@ -114,7 +113,7 @@ void AutotoolsBuildSystem::makefileParsingFinished() QVector<Utils::FilePath> filesToWatch; // Apply sources to m_files, which are returned at AutotoolsBuildSystem::files() - const QFileInfo fileInfo = project()->projectFilePath().toFileInfo(); + const QFileInfo fileInfo = projectFilePath().toFileInfo(); const QDir dir = fileInfo.absoluteDir(); const QStringList files = m_makefileParserThread->sources(); foreach (const QString& file, files) @@ -202,7 +201,7 @@ void AutotoolsBuildSystem::updateCppCodeModel() rpp.setMacros(m_makefileParserThread->macros()); rpp.setFiles(m_files); - m_cppCodeModelUpdater->update({project(), kitInfo, project()->activeParseEnvironment(), {rpp}}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), {rpp}}); } } // namespace Internal diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h index 8bbad6a580b..3af006b0948 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h @@ -29,12 +29,9 @@ #include <projectexplorer/buildsystem.h> -namespace Utils { class FileSystemWatcher; } - namespace CppTools { class CppProjectUpdater; } namespace AutotoolsProjectManager { - namespace Internal { class MakefileParserThread; @@ -44,13 +41,12 @@ class AutotoolsBuildSystem : public ProjectExplorer::BuildSystem Q_OBJECT public: - explicit AutotoolsBuildSystem(ProjectExplorer::Project *project); + explicit AutotoolsBuildSystem(ProjectExplorer::Target *target); ~AutotoolsBuildSystem() override; -protected: - void parseProject(ParsingContext &&ctx) final; - private: + void triggerParsing() final; + /** * Is invoked when the makefile parsing by m_makefileParserThread has * been finished. Adds all sources and files into the project tree and diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp index 977ddade3e0..6aaf8f64a23 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectplugin.cpp @@ -36,7 +36,9 @@ #include "makestep.h" #include <coreplugin/icontext.h> + #include <projectexplorer/projectmanager.h> +#include <projectexplorer/target.h> namespace AutotoolsProjectManager { namespace Internal { @@ -50,7 +52,7 @@ AutotoolsProject::AutotoolsProject(const Utils::FilePath &fileName) setHasMakeInstallEquivalent(true); - setBuildSystemCreator([](Project *p) { return new AutotoolsBuildSystem(p); }); + setBuildSystemCreator([](ProjectExplorer::Target *t) { return new AutotoolsBuildSystem(t); }); } class AutotoolsProjectPluginPrivate diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp index fa225f69456..1a88febbf84 100644 --- a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp +++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp @@ -31,10 +31,9 @@ using namespace AutotoolsProjectManager::Internal; -MakefileParserThread::MakefileParserThread(const QString &makefile, - ProjectExplorer::Project::ParseGuard &&guard) - : m_parser(makefile) - , m_guard(std::move(guard)) +MakefileParserThread::MakefileParserThread(ProjectExplorer::BuildSystem *bs) + : m_parser(bs->projectFilePath().toString()), + m_guard(bs->guardParsingRun()) { connect(&m_parser, &MakefileParser::status, this, &MakefileParserThread::status); diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.h b/src/plugins/autotoolsprojectmanager/makefileparserthread.h index 63d86190e26..75547af1dc5 100644 --- a/src/plugins/autotoolsprojectmanager/makefileparserthread.h +++ b/src/plugins/autotoolsprojectmanager/makefileparserthread.h @@ -29,7 +29,7 @@ #include "makefileparser.h" -#include <projectexplorer/project.h> +#include <projectexplorer/buildsystem.h> #include <projectexplorer/projectmacro.h> #include <QMutex> @@ -54,7 +54,7 @@ class MakefileParserThread : public QThread using Macros = ProjectExplorer::Macros; public: - MakefileParserThread(const QString &makefile, ProjectExplorer::Project::ParseGuard &&guard); + explicit MakefileParserThread(ProjectExplorer::BuildSystem *bs); /** @see QThread::run() */ void run() override; @@ -143,7 +143,7 @@ private: QStringList m_cflags; ///< Return value for MakefileParserThread::cflags() QStringList m_cxxflags; ///< Return value for MakefileParserThread::cxxflags() - ProjectExplorer::Project::ParseGuard m_guard; + ProjectExplorer::BuildSystem::ParseGuard m_guard; }; } // namespace Internal diff --git a/src/plugins/baremetal/baremetalrunconfiguration.cpp b/src/plugins/baremetal/baremetalrunconfiguration.cpp index 8ba44b9343e..c182025a617 100644 --- a/src/plugins/baremetal/baremetalrunconfiguration.cpp +++ b/src/plugins/baremetal/baremetalrunconfiguration.cpp @@ -55,7 +55,7 @@ BareMetalRunConfiguration::BareMetalRunConfiguration(Target *target, Core::Id id this, &BareMetalRunConfiguration::updateTargetInformation); connect(target, &Target::kitChanged, this, &BareMetalRunConfiguration::updateTargetInformation); // Handles device changes, etc. - connect(target->project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &BareMetalRunConfiguration::updateTargetInformation); } diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp index d1abe582290..65df6703428 100644 --- a/src/plugins/boot2qt/qdbrunconfiguration.cpp +++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp @@ -91,7 +91,7 @@ QdbRunConfiguration::QdbRunConfiguration(Target *target, Core::Id id) this, &QdbRunConfiguration::updateTargetInformation); connect(target, &Target::kitChanged, this, &QdbRunConfiguration::updateTargetInformation); - connect(target->project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &QdbRunConfiguration::updateTargetInformation); setDefaultDisplayName(tr("Run on Boot2Qt Device")); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index aa0caae7ecb..e5af6025f6f 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -65,24 +65,29 @@ Q_LOGGING_CATEGORY(cmakeBuildDirManagerLog, "qtc.cmake.builddirmanager", QtWarni // BuildDirManager: // -------------------------------------------------------------------- -BuildDirManager::BuildDirManager(CMakeProject *project) : m_project(project) { assert(project); } +BuildDirManager::BuildDirManager(CMakeBuildSystem *buildSystem) + : m_buildSystem(buildSystem) +{ + assert(buildSystem); +} BuildDirManager::~BuildDirManager() = default; -Utils::FilePath BuildDirManager::workDirectory(const BuildDirParameters ¶meters) const +FilePath BuildDirManager::workDirectory(const BuildDirParameters ¶meters) const { const Utils::FilePath bdir = parameters.buildDirectory; const CMakeTool *cmake = parameters.cmakeTool(); if (bdir.exists()) { m_buildDirToTempDir.erase(bdir); return bdir; - } else { - if (cmake && cmake->autoCreateBuildDirectory()) { - if (!QDir().mkpath(bdir.toString())) - emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput())); - return bdir; - } } + + if (cmake && cmake->autoCreateBuildDirectory()) { + if (!QDir().mkpath(bdir.toString())) + emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput())); + return bdir; + } + auto tmpDirIt = m_buildDirToTempDir.find(bdir); if (tmpDirIt == m_buildDirToTempDir.end()) { auto ret = m_buildDirToTempDir.emplace(std::make_pair(bdir, std::make_unique<Utils::TemporaryDirectory>("qtc-cmake-XXXXXXXX"))); @@ -290,22 +295,20 @@ void BuildDirManager::setParametersAndRequestParse(const BuildDirParameters &par updateReaderType(m_parameters, [this]() { emitReparseRequest(); }); } -CMakeBuildConfiguration *BuildDirManager::buildConfiguration() const +CMakeBuildSystem *BuildDirManager::buildSystem() const { - if (m_project->activeTarget() && m_project->activeTarget()->activeBuildConfiguration() == m_parameters.buildConfiguration) - return m_parameters.buildConfiguration; - return nullptr; + return m_buildSystem; } FilePath BuildDirManager::buildDirectory() const { - return buildConfiguration() ? m_parameters.buildDirectory : FilePath(); + return m_parameters.buildDirectory; } void BuildDirManager::becameDirty() { qCDebug(cmakeBuildDirManagerLog) << "BuildDirManager: becameDirty was triggered."; - if (isParsing() || !buildConfiguration()) + if (isParsing() || !buildSystem()) return; const CMakeTool *tool = m_parameters.cmakeTool(); @@ -444,7 +447,7 @@ static CMakeBuildTarget utilityTarget(const QString &title, const BuildDirManage target.title = title; target.targetType = UtilityType; target.workingDirectory = bdm->buildDirectory(); - target.sourceDirectory = bdm->project()->projectDirectory(); + target.sourceDirectory = bdm->buildSystem()->project()->projectDirectory(); return target; } @@ -528,13 +531,10 @@ QString BuildDirManager::flagsString(int reparseFlags) bool BuildDirManager::checkConfiguration() { - CMakeBuildConfiguration *bc = buildConfiguration(); - QTC_ASSERT(m_parameters.isValid() || !bc, return false); - if (m_parameters.workDirectory != m_parameters.buildDirectory) // always throw away changes in the tmpdir! return false; - const CMakeConfig cache = bc->configurationFromCMake(); + const CMakeConfig cache = m_buildSystem->cmakeBuildConfiguration()->configurationFromCMake(); if (cache.isEmpty()) return false; // No cache file yet. @@ -586,8 +586,8 @@ bool BuildDirManager::checkConfiguration() box->exec(); if (box->clickedButton() == applyButton) { m_parameters.configuration = newConfig; - QSignalBlocker blocker(bc); - bc->setConfigurationForCMake(newConfig); + QSignalBlocker blocker(m_buildSystem->buildConfiguration()); + m_buildSystem->cmakeBuildConfiguration()->setConfigurationForCMake(newConfig); return false; } else if (box->clickedButton() == defaultButton) return true; diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index d3537104cc7..2be437c31b0 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -27,7 +27,6 @@ #include "builddirparameters.h" #include "builddirreader.h" -#include "cmakebuildsystem.h" #include "cmakebuildtarget.h" #include "cmakeconfigitem.h" @@ -46,14 +45,11 @@ namespace ProjectExplorer { class FileNode; } namespace CMakeProjectManager { - -class CMakeProject; -class CMakeTool; - namespace Internal { -class CMakeProjectNode; class CMakeBuildConfiguration; +class CMakeBuildSystem; +class CMakeProjectNode; class BuildDirManager : public QObject { @@ -71,7 +67,7 @@ public: static QString flagsString(int reparseFlags); - BuildDirManager(CMakeProject *project); + explicit BuildDirManager(CMakeBuildSystem *buildSystem); ~BuildDirManager() final; bool isParsing() const; @@ -81,8 +77,7 @@ public: void setParametersAndRequestParse(const BuildDirParameters ¶meters, const int reparseOptions); // nullptr if the BC is not active anymore! - CMakeBuildConfiguration *buildConfiguration() const; - CMakeProject *project() const {return m_project; } + CMakeBuildSystem *buildSystem() const; Utils::FilePath buildDirectory() const; void clearCache(); @@ -133,7 +128,7 @@ private: BuildDirParameters m_parameters; int m_reparseParameters; - CMakeProject *m_project = nullptr; + CMakeBuildSystem *m_buildSystem = nullptr; mutable std::unordered_map<Utils::FilePath, std::unique_ptr<Utils::TemporaryDirectory>> m_buildDirToTempDir; mutable std::unique_ptr<BuildDirReader> m_reader; mutable bool m_isHandlingError = false; diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp index 160b50bef1a..6bf4ccc8c39 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp +++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp @@ -45,7 +45,7 @@ BuildDirParameters::BuildDirParameters() = default; BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc) { - buildConfiguration = bc; + initialized = bc != nullptr; const Kit *k = bc->target()->kit(); @@ -82,7 +82,7 @@ BuildDirParameters::BuildDirParameters(CMakeBuildConfiguration *bc) generatorArguments = CMakeGeneratorKitAspect::generatorArguments(k); } -bool BuildDirParameters::isValid() const { return buildConfiguration && cmakeTool(); } +bool BuildDirParameters::isValid() const { return initialized && cmakeTool(); } CMakeTool *BuildDirParameters::cmakeTool() const { diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h index d0bd9dd7833..740327dcad0 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.h +++ b/src/plugins/cmakeprojectmanager/builddirparameters.h @@ -42,14 +42,14 @@ class CMakeBuildConfiguration; class BuildDirParameters { public: BuildDirParameters(); - BuildDirParameters(CMakeBuildConfiguration *bc); + explicit BuildDirParameters(CMakeBuildConfiguration *bc); BuildDirParameters(const BuildDirParameters &other); BuildDirParameters &operator=(const BuildDirParameters &other); bool isValid() const; CMakeTool *cmakeTool() const; - CMakeBuildConfiguration *buildConfiguration = nullptr; + bool initialized = false; QString projectName; Utils::FilePath sourceDirectory; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index a638ec439a1..d08f14feab7 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -84,101 +84,17 @@ const char CONFIGURATION_KEY[] = "CMake.Configuration"; CMakeBuildConfiguration::CMakeBuildConfiguration(Target *parent, Core::Id id) : BuildConfiguration(parent, id) - , m_buildDirManager(qobject_cast<CMakeProject *>(parent->project())) { + m_buildSystem = new CMakeBuildSystem(this); setBuildDirectory(shadowBuildDirectory(project()->projectFilePath(), target()->kit(), displayName(), BuildConfiguration::Unknown)); +} - BuildSystem *bs = qobject_cast<CMakeBuildSystem *>(project()->buildSystem()); - - // BuildDirManager: - connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this, bs]() { - if (isActive()) - bs->requestParse(); - }); - connect(&m_buildDirManager, &BuildDirManager::requestDelayedReparse, this, [this, bs]() { - if (isActive()) - bs->requestDelayedParse(); - }); - connect(&m_buildDirManager, - &BuildDirManager::dataAvailable, - this, - &CMakeBuildConfiguration::handleParsingSucceeded); - connect(&m_buildDirManager, - &BuildDirManager::errorOccured, - this, - &CMakeBuildConfiguration::handleParsingFailed); - connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() { - clearError(CMakeBuildConfiguration::ForceEnabledChanged::True); - }); - - // Kit changed: - connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { - if (k != target()->kit()) - return; // not for us... - // Build configuration has not changed, but Kit settings might have: - // reparse and check the configuration, independent of whether the reader has changed - m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_CHECK_CONFIGURATION); - }); - - // Became active/inactive: - connect(project(), &Project::activeBuildConfigurationChanged, this, [this]() { - if (isActive()) { - // Build configuration has switched: - // * Check configuration if reader changes due to it not existing yet:-) - // * run cmake without configuration arguments if the reader stays - m_buildDirManager - .setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_CHECK_CONFIGURATION); - } else { - m_buildDirManager.stopParsingAndClearState(); - } - }); - - // BuildConfiguration changed: - connect(this, &CMakeBuildConfiguration::environmentChanged, this, [this]() { - if (isActive()) { - // The environment on our BC has changed: - // * Error out if the reader updates, cannot happen since all BCs share a target/kit. - // * run cmake without configuration arguments if the reader stays - m_buildDirManager - .setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_CHECK_CONFIGURATION); - } - }); - connect(this, &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() { - if (isActive()) { - // The build directory of our BC has changed: - // * Error out if the reader updates, cannot happen since all BCs share a target/kit. - // * run cmake without configuration arguments if the reader stays - // If no configuration exists, then the arguments will get added automatically by - // the reader. - m_buildDirManager - .setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_CHECK_CONFIGURATION); - } - }); - connect(this, &CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() { - if (isActive()) { - // The CMake configuration has changed on our BC: - // * Error out if the reader updates, cannot happen since all BCs share a target/kit. - // * run cmake with configuration arguments if the reader stays - m_buildDirManager - .setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_FORCE_CONFIGURATION); - } - }); - - connect(parent->project(), &Project::projectFileIsDirty, this, [this]() { - if (isActive()) { - m_buildDirManager - .setParametersAndRequestParse(BuildDirParameters(this), - BuildDirManager::REPARSE_DEFAULT); - } - }); +CMakeBuildConfiguration::~CMakeBuildConfiguration() +{ + delete m_buildSystem; } void CMakeBuildConfiguration::initialize() @@ -284,82 +200,11 @@ bool CMakeBuildConfiguration::fromMap(const QVariantMap &map) return true; } -const QList<BuildTargetInfo> CMakeBuildConfiguration::appTargets() const -{ - QList<BuildTargetInfo> appTargetList; - const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit()) - == Android::Constants::ANDROID_DEVICE_TYPE; - for (const CMakeBuildTarget &ct : m_buildTargets) { - if (ct.targetType == UtilityType) - continue; - - if (ct.targetType == ExecutableType || (forAndroid && ct.targetType == DynamicLibraryType)) { - BuildTargetInfo bti; - bti.displayName = ct.title; - bti.targetFilePath = ct.executable; - bti.projectFilePath = ct.sourceDirectory.stringAppended("/"); - bti.workingDirectory = ct.workingDirectory; - bti.buildKey = ct.title; - - // Workaround for QTCREATORBUG-19354: - bti.runEnvModifier = [this](Environment &env, bool) { - if (HostOsInfo::isWindowsHost()) { - const Kit *k = target()->kit(); - if (const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k)) - env.prependOrSetPath(qt->binPath().toString()); - } - }; - - appTargetList.append(bti); - } - } - - return appTargetList; -} - -DeploymentData CMakeBuildConfiguration::deploymentData() const -{ - DeploymentData result; - - QDir sourceDir = target()->project()->projectDirectory().toString(); - QDir buildDir = buildDirectory().toString(); - QString deploymentPrefix; - QString deploymentFilePath = sourceDir.filePath("QtCreatorDeployment.txt"); - bool hasDeploymentFile = QFileInfo::exists(deploymentFilePath); - if (!hasDeploymentFile) { - deploymentFilePath = buildDir.filePath("QtCreatorDeployment.txt"); - hasDeploymentFile = QFileInfo::exists(deploymentFilePath); - } - if (!hasDeploymentFile) - return result; - - deploymentPrefix = result.addFilesFromDeploymentFile(deploymentFilePath, - sourceDir.absolutePath()); - for (const CMakeBuildTarget &ct : m_buildTargets) { - if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) { - if (!ct.executable.isEmpty() - && result.deployableForLocalFile(ct.executable).localFilePath() != ct.executable) { - result.addFile(ct.executable.toString(), - deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), - DeployableFile::TypeExecutable); - } - } - } - return result; -} -QStringList CMakeBuildConfiguration::buildTargetTitles() const -{ - return transform(m_buildTargets, &CMakeBuildTarget::title); -} -const QList<CMakeBuildTarget> &CMakeBuildConfiguration::buildTargets() const -{ - return m_buildTargets; -} FilePath CMakeBuildConfiguration::shadowBuildDirectory(const FilePath &projectFilePath, const Kit *k, @@ -408,11 +253,6 @@ void CMakeBuildConfiguration::setConfigurationFromCMake(const CMakeConfig &confi m_configurationFromCMake = config; } -void CMakeBuildConfiguration::setBuildTargets(const QList<CMakeBuildTarget> &targets) -{ - m_buildTargets = targets; -} - void CMakeBuildConfiguration::setConfigurationForCMake(const QList<ConfigModel::DataItem> &items) { const CMakeConfig newConfig = Utils::transform(items, [](const ConfigModel::DataItem &i) { @@ -548,64 +388,6 @@ void CMakeBuildConfiguration::setWarning(const QString &message) emit warningOccured(m_warning); } -void CMakeBuildConfiguration::handleParsingSucceeded() -{ - if (!isActive()) { - m_buildDirManager.stopParsingAndClearState(); - return; - } - - clearError(); - - QString errorMessage; - { - const QList<CMakeBuildTarget> buildTargets = m_buildDirManager.takeBuildTargets( - errorMessage); - checkAndReportError(errorMessage); - setBuildTargets(buildTargets); - } - - { - const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration(errorMessage); - checkAndReportError(errorMessage); - setConfigurationFromCMake(cmakeConfig); - } - - { - target()->setApplicationTargets(appTargets()); - target()->setDeploymentData(deploymentData()); - } - - static_cast<CMakeBuildSystem *>(project()->buildSystem())->handleParsingSuccess(this); -} - -void CMakeBuildConfiguration::handleParsingFailed(const QString &msg) -{ - setError(msg); - - QString errorMessage; - setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage)); - // ignore errorMessage here, we already got one. - - static_cast<CMakeBuildSystem *>(project()->buildSystem())->handleParsingError(this); -} - -std::unique_ptr<CMakeProjectNode> CMakeBuildConfiguration::generateProjectTree( - const QList<const FileNode *> &allFiles) -{ - QString errorMessage; - auto root = m_buildDirManager.generateProjectTree(allFiles, errorMessage); - checkAndReportError(errorMessage); - return root; -} - -void CMakeBuildConfiguration::checkAndReportError(QString &errorMessage) -{ - if (!errorMessage.isEmpty()) { - setError(errorMessage); - errorMessage.clear(); - } -} QString CMakeBuildConfiguration::error() const { @@ -775,5 +557,10 @@ CMakeProject *CMakeBuildConfiguration::project() const return qobject_cast<CMakeProject *>(BuildConfiguration::project()); } +BuildSystem *CMakeBuildConfiguration::buildSystem() const +{ + return m_buildSystem; +} + } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 833f77131f2..70f1b17a742 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -34,13 +34,12 @@ #include <projectexplorer/deploymentdata.h> namespace CMakeProjectManager { -class CMakeBuildSystem; -class CMakeExtraBuildInfo; class CMakeProject; namespace Internal { class BuildDirManager; +class CMakeBuildSystem; class CMakeBuildSettingsWidget; class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration @@ -49,6 +48,7 @@ class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration friend class ProjectExplorer::BuildConfigurationFactory; CMakeBuildConfiguration(ProjectExplorer::Target *parent, Core::Id id); + ~CMakeBuildConfiguration() final; public: void emitBuildTypeChanged(); @@ -61,17 +61,14 @@ public: CMakeProject *project() const; - QStringList buildTargetTitles() const; - const QList<CMakeBuildTarget> &buildTargets() const; - const QList<ProjectExplorer::BuildTargetInfo> appTargets() const; - ProjectExplorer::DeploymentData deploymentData() const; - static Utils::FilePath shadowBuildDirectory(const Utils::FilePath &projectFilePath, const ProjectExplorer::Kit *k, const QString &bcName, BuildConfiguration::BuildType buildType); // Context menu action: void buildTarget(const QString &buildTarget); + ProjectExplorer::BuildSystem *buildSystem() const final; + signals: void errorOccured(const QString &message); void warningOccured(const QString &message); @@ -92,7 +89,6 @@ private: enum ForceEnabledChanged { False, True }; void clearError(ForceEnabledChanged fec = ForceEnabledChanged::False); - void setBuildTargets(const QList<CMakeBuildTarget> &targets); void setConfigurationFromCMake(const CMakeConfig &config); void setConfigurationForCMake(const QList<ConfigModel::DataItem> &items); void setConfigurationForCMake(const CMakeConfig &config); @@ -100,27 +96,17 @@ private: void setError(const QString &message); void setWarning(const QString &message); - void handleParsingSucceeded(); - void handleParsingFailed(const QString &msg); - - std::unique_ptr<CMakeProjectNode> generateProjectTree( - const QList<const ProjectExplorer::FileNode *> &allFiles); - - void checkAndReportError(QString &errorMessage); - - Internal::BuildDirManager m_buildDirManager; - CMakeConfig m_configurationForCMake; CMakeConfig m_initialConfiguration; QString m_error; QString m_warning; CMakeConfig m_configurationFromCMake; - QList<CMakeBuildTarget> m_buildTargets; + CMakeBuildSystem *m_buildSystem = nullptr; friend class CMakeBuildSettingsWidget; - friend class CMakeProjectManager::CMakeBuildSystem; - friend class CMakeProjectManager::CMakeProject; + friend class CMakeBuildSystem; + friend class CMakeProject; friend class BuildDirManager; }; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index 710828ff01b..1652ed959f6 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -59,6 +59,8 @@ #include <QStyledItemDelegate> #include <QMenu> +using namespace ProjectExplorer; + namespace CMakeProjectManager { namespace Internal { @@ -102,7 +104,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setColumnStretch(1, 10); - auto project = static_cast<CMakeProject *>(bc->project()); + auto project = bc->project(); auto buildDirChooser = new Utils::PathChooser; buildDirChooser->setBaseFileName(project->projectDirectory()); @@ -245,21 +247,20 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) setError(bc->error()); setWarning(bc->warning()); - connect(project, &ProjectExplorer::Project::parsingStarted, this, [this]() { + connect(bc->target(), &Target::parsingStarted, this, [this]() { updateButtonState(); m_configView->setEnabled(false); m_showProgressTimer.start(); }); - if (project->isParsing()) + if (bc->buildSystem()->isParsing()) m_showProgressTimer.start(); else { m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake()); m_configView->expandAll(); } - connect(project, &ProjectExplorer::Project::parsingFinished, - this, [this, buildDirChooser, stretcher]() { + connect(bc->target(), &Target::parsingFinished, this, [this, buildDirChooser, stretcher] { m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake()); m_configView->expandAll(); m_configView->setEnabled(true); @@ -363,7 +364,7 @@ void CMakeBuildSettingsWidget::setWarning(const QString &message) void CMakeBuildSettingsWidget::updateButtonState() { - const bool isParsing = m_buildConfiguration->project()->isParsing(); + const bool isParsing = m_buildConfiguration->buildSystem()->isParsing(); const bool hasChanges = m_configModel->hasChanges(); m_resetButton->setEnabled(hasChanges && !isParsing); m_reconfigureButton->setEnabled((hasChanges || m_configModel->hasCMakeChanges()) && !isParsing); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 00032dabff5..67d6bc5252b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -26,6 +26,7 @@ #include "cmakebuildstep.h" #include "cmakebuildconfiguration.h" +#include "cmakebuildsystem.h" #include "cmakekitinformation.h" #include "cmakeparser.h" #include "cmakeprojectconstants.h" @@ -91,7 +92,7 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl) : setLowPriority(); connect(target(), &Target::kitChanged, this, &CMakeBuildStep::cmakeCommandChanged); - connect(project(), &Project::parsingFinished, + connect(target(), &Target::parsingFinished, this, &CMakeBuildStep::handleBuildTargetChanges); } @@ -221,17 +222,17 @@ void CMakeBuildStep::doRun() QTC_ASSERT(bc, return); m_waiting = false; - auto p = static_cast<CMakeProject *>(bc->project()); - if (p->persistCMakeState()) { + auto bs = static_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem()); + if (bs->persistCMakeState()) { emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage); m_waiting = true; - } else if (p->mustUpdateCMakeStateBeforeBuild()) { + } else if (buildConfiguration()->buildSystem()->isWaitingForParse()) { emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage); m_waiting = true; } if (m_waiting) { - m_runTrigger = connect(project(), &Project::parsingFinished, + m_runTrigger = connect(target(), &Target::parsingFinished, this, [this](bool success) { handleProjectWasParsed(success); }); } else { runImpl(); @@ -367,7 +368,7 @@ Utils::CommandLine CMakeBuildStep::cmakeCommand(RunConfiguration *rc) const QStringList CMakeBuildStep::knownBuildTargets() { - auto bc = qobject_cast<CMakeBuildConfiguration *>(buildConfiguration()); + auto bc = qobject_cast<CMakeBuildSystem *>(buildConfiguration()->buildSystem()); return bc ? bc->buildTargetTitles() : QStringList(); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index ae1e20972ff..b84a39625b9 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -30,13 +30,18 @@ #include "cmakeprojectconstants.h" #include "cmakeprojectnodes.h" +#include <android/androidconstants.h> + #include <coreplugin/progressmanager/progressmanager.h> #include <cpptools/cppprojectupdater.h> #include <cpptools/generatedcodemodelsupport.h> +#include <projectexplorer/kitmanager.h> #include <projectexplorer/project.h> #include <projectexplorer/target.h> #include <qmljs/qmljsmodelmanagerinterface.h> + #include <qtsupport/qtcppkitinfo.h> +#include <qtsupport/qtkitinformation.h> #include <utils/fileutils.h> #include <utils/mimetypes/mimetype.h> @@ -48,8 +53,7 @@ using namespace ProjectExplorer; using namespace Utils; namespace CMakeProjectManager { - -using namespace Internal; +namespace Internal { Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); @@ -57,15 +61,15 @@ Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg); // CMakeBuildSystem: // -------------------------------------------------------------------- -CMakeBuildSystem::CMakeBuildSystem(Project *project) - : BuildSystem(project) +CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc) + : BuildSystem(bc) + , m_buildConfiguration(bc) + , m_buildDirManager(this) , m_cppCodeModelUpdater(new CppTools::CppProjectUpdater) { // TreeScanner: - connect(&m_treeScanner, - &TreeScanner::finished, - this, - &CMakeBuildSystem::handleTreeScanningFinished); + connect(&m_treeScanner, &TreeScanner::finished, + this, &CMakeBuildSystem::handleTreeScanningFinished); m_treeScanner.setFilter([this](const MimeType &mimeType, const FilePath &fn) { // Mime checks requires more resources, so keep it last in check list @@ -98,6 +102,109 @@ CMakeBuildSystem::CMakeBuildSystem(Project *project) } return type; }); + + // BuildDirManager: + connect(&m_buildDirManager, &BuildDirManager::requestReparse, this, [this] { + if (m_buildConfiguration->isActive()) + requestParse(); + }); + connect(&m_buildDirManager, &BuildDirManager::requestDelayedReparse, this, [this] { + if (m_buildConfiguration->isActive()) + requestDelayedParse(); + }); + + connect(&m_buildDirManager, &BuildDirManager::dataAvailable, + this, &CMakeBuildSystem::handleParsingSucceeded); + + connect(&m_buildDirManager, &BuildDirManager::errorOccured, + this, &CMakeBuildSystem::handleParsingFailed); + + connect(&m_buildDirManager, &BuildDirManager::parsingStarted, this, [this]() { + m_buildConfiguration->clearError(CMakeBuildConfiguration::ForceEnabledChanged::True); + }); + + // Kit changed: + connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { + if (k != target()->kit()) + return; // not for us... + // Build configuration has not changed, but Kit settings might have: + // reparse and check the configuration, independent of whether the reader has changed + m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); + }); + + // Became active/inactive: + connect(project(), &Project::activeTargetChanged, this, [this](Target *t) { + if (t == target()) { + // Build configuration has switched: + // * Check configuration if reader changes due to it not existing yet:-) + // * run cmake without configuration arguments if the reader stays + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); + } else { + m_buildDirManager.stopParsingAndClearState(); + } + }); + connect(target(), &Target::activeBuildConfigurationChanged, this, [this](BuildConfiguration *bc) { + if (m_buildConfiguration->isActive()) { + if (m_buildConfiguration == bc) { + // Build configuration has switched: + // * Check configuration if reader changes due to it not existing yet:-) + // * run cmake without configuration arguments if the reader stays + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); + } else { + m_buildDirManager.stopParsingAndClearState(); + } + } + }); + + // BuildConfiguration changed: + connect(m_buildConfiguration, &CMakeBuildConfiguration::environmentChanged, this, [this]() { + if (m_buildConfiguration->isActive()) { + // The environment on our BC has changed: + // * Error out if the reader updates, cannot happen since all BCs share a target/kit. + // * run cmake without configuration arguments if the reader stays + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); + } + }); + connect(m_buildConfiguration, &CMakeBuildConfiguration::buildDirectoryChanged, this, [this]() { + if (m_buildConfiguration->isActive()) { + // The build directory of our BC has changed: + // * Error out if the reader updates, cannot happen since all BCs share a target/kit. + // * run cmake without configuration arguments if the reader stays + // If no configuration exists, then the arguments will get added automatically by + // the reader. + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); + } + }); + connect(m_buildConfiguration, &CMakeBuildConfiguration::configurationForCMakeChanged, this, [this]() { + if (m_buildConfiguration->isActive()) { + // The CMake configuration has changed on our BC: + // * Error out if the reader updates, cannot happen since all BCs share a target/kit. + // * run cmake with configuration arguments if the reader stays + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_FORCE_CONFIGURATION); + } + }); + + connect(project(), &Project::projectFileIsDirty, this, [this]() { + if (m_buildConfiguration->isActive()) { + m_buildDirManager + .setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_DEFAULT); + } + }); + + m_buildDirManager.setParametersAndRequestParse(BuildDirParameters(m_buildConfiguration), + BuildDirManager::REPARSE_CHECK_CONFIGURATION); } CMakeBuildSystem::~CMakeBuildSystem() @@ -112,36 +219,84 @@ CMakeBuildSystem::~CMakeBuildSystem() qDeleteAll(m_allFiles); } -bool CMakeBuildSystem::validateParsingContext(const ParsingContext &ctx) +void CMakeBuildSystem::triggerParsing() { - QTC_ASSERT(!m_currentContext.guard.guardsProject(), return false); - return ctx.project && qobject_cast<CMakeBuildConfiguration *>(ctx.buildConfiguration); -} - -void CMakeBuildSystem::parseProject(ParsingContext &&ctx) -{ - m_currentContext = std::move(ctx); - - auto bc = qobject_cast<CMakeBuildConfiguration *>(m_currentContext.buildConfiguration); - QTC_ASSERT(bc, return ); + m_currentGuard = guardParsingRun(); if (m_allFiles.isEmpty()) - bc->m_buildDirManager.requestFilesystemScan(); + m_buildDirManager.requestFilesystemScan(); - m_waitingForScan = bc->m_buildDirManager.isFilesystemScanRequested(); + m_waitingForScan = m_buildDirManager.isFilesystemScanRequested(); m_waitingForParse = true; m_combinedScanAndParseResult = true; if (m_waitingForScan) { QTC_CHECK(m_treeScanner.isFinished()); - m_treeScanner.asyncScanForFiles(m_currentContext.project->projectDirectory()); + m_treeScanner.asyncScanForFiles(projectDirectory()); Core::ProgressManager::addTask(m_treeScanner.future(), tr("Scan \"%1\" project tree") - .arg(m_currentContext.project->displayName()), + .arg(project()->displayName()), "CMake.Scan.Tree"); } - bc->m_buildDirManager.parse(); + m_buildDirManager.parse(); +} + +QStringList CMakeBuildSystem::filesGeneratedFrom(const QString &sourceFile) const +{ + QFileInfo fi(sourceFile); + FilePath project = projectDirectory(); + FilePath baseDirectory = FilePath::fromString(fi.absolutePath()); + + while (baseDirectory.isChildOf(project)) { + const FilePath cmakeListsTxt = baseDirectory.pathAppended("CMakeLists.txt"); + if (cmakeListsTxt.exists()) + break; + baseDirectory = baseDirectory.parentDir(); + } + + QDir srcDirRoot = QDir(project.toString()); + QString relativePath = srcDirRoot.relativeFilePath(baseDirectory.toString()); + QDir buildDir = QDir(target()->activeBuildConfiguration()->buildDirectory().toString()); + QString generatedFilePath = buildDir.absoluteFilePath(relativePath); + + if (fi.suffix() == "ui") { + generatedFilePath += "/ui_"; + generatedFilePath += fi.completeBaseName(); + generatedFilePath += ".h"; + return {QDir::cleanPath(generatedFilePath)}; + } + if (fi.suffix() == "scxml") { + generatedFilePath += "/"; + generatedFilePath += QDir::cleanPath(fi.completeBaseName()); + return {generatedFilePath + ".h", generatedFilePath + ".cpp"}; + } + + // TODO: Other types will be added when adapters for their compilers become available. + return {}; +} + +void CMakeBuildSystem::runCMake() +{ + BuildDirParameters parameters(m_buildConfiguration); + m_buildDirManager.setParametersAndRequestParse(parameters, + BuildDirManager::REPARSE_CHECK_CONFIGURATION + | BuildDirManager::REPARSE_FORCE_CMAKE_RUN + | BuildDirManager::REPARSE_URGENT); +} + +void CMakeBuildSystem::runCMakeAndScanProjectTree() +{ + BuildDirParameters parameters(m_buildConfiguration); + m_buildDirManager.setParametersAndRequestParse(parameters, + BuildDirManager::REPARSE_CHECK_CONFIGURATION + | BuildDirManager::REPARSE_SCAN); +} + +void CMakeBuildSystem::buildCMakeTarget(const QString &buildTarget) +{ + QTC_ASSERT(!buildTarget.isEmpty(), return); + m_buildConfiguration->buildTarget(buildTarget); } void CMakeBuildSystem::handleTreeScanningFinished() @@ -156,11 +311,18 @@ void CMakeBuildSystem::handleTreeScanningFinished() combineScanAndParse(); } -void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc) +bool CMakeBuildSystem::persistCMakeState() { - if (bc != m_currentContext.buildConfiguration) - return; // Not current information, ignore. + return m_buildDirManager.persistCMakeState(); +} + +void CMakeBuildSystem::clearCMakeCache() +{ + m_buildDirManager.clearCache(); +} +void CMakeBuildSystem::handleParsingSuccess() +{ QTC_ASSERT(m_waitingForParse, return ); m_waitingForParse = false; @@ -168,11 +330,8 @@ void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc) combineScanAndParse(); } -void CMakeBuildSystem::handleParsingError(CMakeBuildConfiguration *bc) +void CMakeBuildSystem::handleParsingError() { - if (bc != m_currentContext.buildConfiguration) - return; // Not current information, ignore. - QTC_CHECK(m_waitingForParse); m_waitingForParse = false; @@ -181,35 +340,51 @@ void CMakeBuildSystem::handleParsingError(CMakeBuildConfiguration *bc) combineScanAndParse(); } +std::unique_ptr<CMakeProjectNode> + CMakeBuildSystem::generateProjectTree(const QList<const FileNode *> &allFiles) +{ + QString errorMessage; + auto root = m_buildDirManager.generateProjectTree(allFiles, errorMessage); + checkAndReportError(errorMessage); + return root; +} + void CMakeBuildSystem::combineScanAndParse() { - auto bc = qobject_cast<CMakeBuildConfiguration *>(m_currentContext.buildConfiguration); - if (bc && bc->isActive()) { + if (m_buildConfiguration->isActive()) { if (m_waitingForParse || m_waitingForScan) return; if (m_combinedScanAndParseResult) { - updateProjectData(qobject_cast<CMakeProject *>(m_currentContext.project), bc); - m_currentContext.guard.markAsSuccess(); + updateProjectData(); + m_currentGuard.markAsSuccess(); } } - m_currentContext = BuildSystem::ParsingContext(); + m_currentGuard = {}; +} + +void CMakeBuildSystem::checkAndReportError(QString &errorMessage) +{ + if (!errorMessage.isEmpty()) { + m_buildConfiguration->setError(errorMessage); + errorMessage.clear(); + } } -void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguration *bc) +void CMakeBuildSystem::updateProjectData() { qCDebug(cmakeBuildSystemLog) << "Updating CMake project data"; - QTC_ASSERT(m_treeScanner.isFinished() && !bc->m_buildDirManager.isParsing(), return ); + QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return); - project()->setExtraProjectFiles(bc->m_buildDirManager.takeProjectFilesToWatch()); + m_buildConfiguration->project()->setExtraProjectFiles(m_buildDirManager.takeProjectFilesToWatch()); - CMakeConfig patchedConfig = bc->configurationFromCMake(); + CMakeConfig patchedConfig = m_buildConfiguration->configurationFromCMake(); { CMakeConfigItem settingFileItem; settingFileItem.key = "ANDROID_DEPLOYMENT_SETTINGS_FILE"; - settingFileItem.value = bc->buildDirectory() + settingFileItem.value = m_buildConfiguration->buildDirectory() .pathAppended("android_deployment_settings.json") .toString() .toUtf8(); @@ -218,7 +393,7 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio { QSet<QString> res; QStringList apps; - for (const auto &target : bc->buildTargets()) { + for (const auto &target : m_buildTargets) { if (target.targetType == CMakeProjectManager::DynamicLibraryType) { res.insert(target.executable.parentDir().toString()); apps.push_back(target.executable.toUserOutput()); @@ -241,14 +416,15 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio } } + Project *p = project(); { - auto newRoot = bc->generateProjectTree(m_allFiles); + auto newRoot = generateProjectTree(m_allFiles); if (newRoot) { p->setRootProjectNode(std::move(newRoot)); if (p->rootProjectNode()) p->setDisplayName(p->rootProjectNode()->displayName()); - for (const CMakeBuildTarget &bt : bc->buildTargets()) { + for (const CMakeBuildTarget &bt : m_buildTargets) { const QString buildKey = bt.title; if (ProjectNode *node = p->findNodeForBuildKey(buildKey)) { if (auto targetNode = dynamic_cast<CMakeTargetNode *>(node)) @@ -260,7 +436,7 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio { qDeleteAll(m_extraCompilers); - m_extraCompilers = findExtraCompilers(p); + m_extraCompilers = findExtraCompilers(); CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); qCDebug(cmakeBuildSystemLog) << "Extra compilers updated."; } @@ -270,9 +446,9 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio { QString errorMessage; - RawProjectParts rpps = bc->m_buildDirManager.createRawProjectParts(errorMessage); + RawProjectParts rpps = m_buildDirManager.createRawProjectParts(errorMessage); if (!errorMessage.isEmpty()) - bc->setError(errorMessage); + m_buildConfiguration->setError(errorMessage); qCDebug(cmakeBuildSystemLog) << "Raw project parts created." << errorMessage; for (RawProjectPart &rpp : rpps) { @@ -284,22 +460,147 @@ void CMakeBuildSystem::updateProjectData(CMakeProject *p, CMakeBuildConfiguratio rpp.setFlagsForC({kitInfo.cToolChain, rpp.flagsForC.commandLineFlags}); } - m_cppCodeModelUpdater->update({p, kitInfo, bc->environment(), rpps}); + m_cppCodeModelUpdater->update({p, kitInfo, m_buildConfiguration->environment(), rpps}); } { - updateQmlJSCodeModel(p, bc); + updateQmlJSCodeModel(); } emit p->fileListChanged(); - emit bc->emitBuildTypeChanged(); + emit m_buildConfiguration->emitBuildTypeChanged(); - bc->m_buildDirManager.resetData(); + m_buildDirManager.resetData(); qCDebug(cmakeBuildSystemLog) << "All CMake project data up to date."; } -QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMakeProject *p) +void CMakeBuildSystem::handleParsingSucceeded() +{ + if (!m_buildConfiguration->isActive()) { + m_buildDirManager.stopParsingAndClearState(); + return; + } + + m_buildConfiguration->clearError(); + + QString errorMessage; + { + m_buildTargets = m_buildDirManager.takeBuildTargets(errorMessage); + checkAndReportError(errorMessage); + } + + { + const CMakeConfig cmakeConfig = m_buildDirManager.takeCMakeConfiguration(errorMessage); + checkAndReportError(errorMessage); + m_buildConfiguration->setConfigurationFromCMake(cmakeConfig); + } + + setApplicationTargets(appTargets()); + setDeploymentData(deploymentData()); + + handleParsingSuccess(); +} + +void CMakeBuildSystem::handleParsingFailed(const QString &msg) +{ + m_buildConfiguration->setError(msg); + + QString errorMessage; + m_buildConfiguration->setConfigurationFromCMake(m_buildDirManager.takeCMakeConfiguration(errorMessage)); + // ignore errorMessage here, we already got one. + + handleParsingError(); +} + +BuildConfiguration *CMakeBuildSystem::buildConfiguration() const +{ + return m_buildConfiguration; +} + +CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const +{ + return m_buildConfiguration; +} + +const QList<BuildTargetInfo> CMakeBuildSystem::appTargets() const +{ + QList<BuildTargetInfo> appTargetList; + const bool forAndroid = DeviceTypeKitAspect::deviceTypeId(target()->kit()) + == Android::Constants::ANDROID_DEVICE_TYPE; + for (const CMakeBuildTarget &ct : m_buildTargets) { + if (ct.targetType == UtilityType) + continue; + + if (ct.targetType == ExecutableType || (forAndroid && ct.targetType == DynamicLibraryType)) { + BuildTargetInfo bti; + bti.displayName = ct.title; + bti.targetFilePath = ct.executable; + bti.projectFilePath = ct.sourceDirectory.stringAppended("/"); + bti.workingDirectory = ct.workingDirectory; + bti.buildKey = ct.title; + + // Workaround for QTCREATORBUG-19354: + bti.runEnvModifier = [this](Environment &env, bool) { + if (HostOsInfo::isWindowsHost()) { + const Kit *k = target()->kit(); + if (const QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k)) + env.prependOrSetPath(qt->binPath().toString()); + } + }; + + appTargetList.append(bti); + } + } + + return appTargetList; +} + +QStringList CMakeBuildSystem::buildTargetTitles() const +{ + return transform(m_buildTargets, &CMakeBuildTarget::title); +} + +const QList<CMakeBuildTarget> &CMakeBuildSystem::buildTargets() const +{ + return m_buildTargets; +} + +DeploymentData CMakeBuildSystem::deploymentData() const +{ + DeploymentData result; + + QDir sourceDir = target()->project()->projectDirectory().toString(); + QDir buildDir = buildConfiguration()->buildDirectory().toString(); + + QString deploymentPrefix; + QString deploymentFilePath = sourceDir.filePath("QtCreatorDeployment.txt"); + + bool hasDeploymentFile = QFileInfo::exists(deploymentFilePath); + if (!hasDeploymentFile) { + deploymentFilePath = buildDir.filePath("QtCreatorDeployment.txt"); + hasDeploymentFile = QFileInfo::exists(deploymentFilePath); + } + if (!hasDeploymentFile) + return result; + + deploymentPrefix = result.addFilesFromDeploymentFile(deploymentFilePath, + sourceDir.absolutePath()); + for (const CMakeBuildTarget &ct : m_buildTargets) { + if (ct.targetType == ExecutableType || ct.targetType == DynamicLibraryType) { + if (!ct.executable.isEmpty() + && result.deployableForLocalFile(ct.executable).localFilePath() != ct.executable) { + result.addFile(ct.executable.toString(), + deploymentPrefix + buildDir.relativeFilePath(ct.executable.toFileInfo().dir().path()), + DeployableFile::TypeExecutable); + } + } + } + + return result; +} + +QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers() { qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: start."; @@ -315,6 +616,7 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa << fileExtensions; // Find all files generated by any of the extra compilers, in a rather crude way. + Project *p = project(); const FilePathList fileList = p->files([&fileExtensions, p](const Node *n) { if (!p->SourceFiles(n)) return false; @@ -336,7 +638,7 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa }); QTC_ASSERT(factory, continue); - QStringList generated = p->filesGeneratedFrom(file.toString()); + QStringList generated = filesGeneratedFrom(file.toString()); qCDebug(cmakeBuildSystemLog) << "Finding Extra Compilers: generated files:" << generated; if (generated.isEmpty()) @@ -355,19 +657,20 @@ QList<ProjectExplorer::ExtraCompiler *> CMakeBuildSystem::findExtraCompilers(CMa return extraCompilers; } -void CMakeBuildSystem::updateQmlJSCodeModel(CMakeProject *p, CMakeBuildConfiguration *bc) +void CMakeBuildSystem::updateQmlJSCodeModel() { QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); if (!modelManager) return; + Project *p = project(); QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager ->defaultProjectInfoForProject(p); projectInfo.importPaths.clear(); - const CMakeConfig &cm = bc->configurationFromCMake(); + const CMakeConfig &cm = m_buildConfiguration->configurationFromCMake(); const QString cmakeImports = QString::fromUtf8(CMakeConfigItem::valueOf("QML_IMPORT_PATH", cm)); foreach (const QString &cmakeImport, CMakeConfigItem::cmakeSplitValue(cmakeImports)) @@ -376,4 +679,5 @@ void CMakeBuildSystem::updateQmlJSCodeModel(CMakeProject *p, CMakeBuildConfigura modelManager->updateProjectInfo(projectInfo, p); } +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index c1325dcc0ce..66806b1911e 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -25,8 +25,12 @@ #pragma once +#include "builddirmanager.h" + #include <projectexplorer/buildsystem.h> +namespace ProjectExplorer { class ExtraCompiler; } + namespace CppTools { class CppProjectUpdater; } // namespace CppTools @@ -37,7 +41,6 @@ class CMakeProject; namespace Internal { class CMakeBuildConfiguration; -} // namespace Internal // -------------------------------------------------------------------- // CMakeBuildSystem: @@ -48,12 +51,10 @@ class CMakeBuildSystem : public ProjectExplorer::BuildSystem Q_OBJECT public: - explicit CMakeBuildSystem(ProjectExplorer::Project *project); + explicit CMakeBuildSystem(CMakeBuildConfiguration *bc); ~CMakeBuildSystem() final; -protected: - bool validateParsingContext(const ParsingContext &ctx) final; - void parseProject(ParsingContext &&ctx) final; + void triggerParsing() final; bool supportsAction(ProjectExplorer::Node *context, ProjectExplorer::ProjectAction action, @@ -62,20 +63,49 @@ protected: bool addFiles(ProjectExplorer::Node *context, const QStringList &filePaths, QStringList *) final; -private: + QStringList filesGeneratedFrom(const QString &sourceFile) const final; + + void runCMake(); + void runCMakeAndScanProjectTree(); + + // Context menu actions: + void buildCMakeTarget(const QString &buildTarget); // Treescanner states: void handleTreeScanningFinished(); + bool persistCMakeState(); + void clearCMakeCache(); + // Parser states: - void handleParsingSuccess(Internal::CMakeBuildConfiguration *bc); - void handleParsingError(Internal::CMakeBuildConfiguration *bc); + void handleParsingSuccess(); + void handleParsingError(); + + ProjectExplorer::BuildConfiguration *buildConfiguration() const; + CMakeBuildConfiguration *cmakeBuildConfiguration() const; + + const QList<ProjectExplorer::BuildTargetInfo> appTargets() const; + QStringList buildTargetTitles() const; + const QList<CMakeBuildTarget> &buildTargets() const; + ProjectExplorer::DeploymentData deploymentData() const; + +private: + std::unique_ptr<CMakeProjectNode> generateProjectTree( + const QList<const ProjectExplorer::FileNode *> &allFiles); // Combining Treescanner and Parser states: void combineScanAndParse(); - void updateProjectData(CMakeProject *p, Internal::CMakeBuildConfiguration *bc); - QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers(CMakeProject *p); - void updateQmlJSCodeModel(CMakeProject *p, Internal::CMakeBuildConfiguration *bc); + void checkAndReportError(QString &errorMessage); + + void updateProjectData(); + QList<ProjectExplorer::ExtraCompiler *> findExtraCompilers(); + void updateQmlJSCodeModel(); + + void handleParsingSucceeded(); + void handleParsingFailed(const QString &msg); + + CMakeBuildConfiguration *m_buildConfiguration = nullptr; + BuildDirManager m_buildDirManager; ProjectExplorer::TreeScanner m_treeScanner; QHash<QString, bool> m_mimeBinaryCache; @@ -85,12 +115,12 @@ private: bool m_waitingForParse = false; bool m_combinedScanAndParseResult = false; - ParsingContext m_currentContext; + ParseGuard m_currentGuard; CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers; - - friend class Internal::CMakeBuildConfiguration; // For handleParsing* callbacks + QList<CMakeBuildTarget> m_buildTargets; }; +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index f7149a4eb21..0f48dc28307 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -66,12 +66,11 @@ void CMakeTargetLocatorFilter::prepareSearch(const QString &entry) auto cmakeProject = qobject_cast<const CMakeProject *>(p); if (!cmakeProject || !cmakeProject->activeTarget()) continue; - auto bc = qobject_cast<CMakeBuildConfiguration *>( - cmakeProject->activeTarget()->activeBuildConfiguration()); - if (!bc) + auto bs = qobject_cast<CMakeBuildSystem *>(cmakeProject->activeTarget()->buildSystem()); + if (!bs) continue; - const QList<CMakeBuildTarget> buildTargets = bc->buildTargets(); + const QList<CMakeBuildTarget> buildTargets = bs->buildTargets(); for (const CMakeBuildTarget &target : buildTargets) { const int index = target.title.indexOf(entry); if (index >= 0) { diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index e44018affdb..ddcba34840f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -68,11 +68,6 @@ namespace CMakeProjectManager { using namespace Internal; -static CMakeBuildConfiguration *activeBc(const CMakeProject *p) -{ - return qobject_cast<CMakeBuildConfiguration *>(p->activeTarget() ? p->activeTarget()->activeBuildConfiguration() : nullptr); -} - // QtCreator CMake Generator wishlist: // Which make targets we need to build to get all executables // What is the actual compiler executable @@ -90,8 +85,6 @@ CMakeProject::CMakeProject(const FilePath &fileName) setCanBuildProducts(); setKnowsAllBuildExecutables(false); setHasMakeInstallEquivalent(true); - - setBuildSystemCreator([](Project *p) { return new CMakeBuildSystem(p); }); } CMakeProject::~CMakeProject() = default; @@ -108,38 +101,6 @@ Tasks CMakeProject::projectIssues(const Kit *k) const return result; } -void CMakeProject::runCMake() -{ - CMakeBuildConfiguration *bc = activeBc(this); - if (isParsing() || !bc) - return; - - BuildDirParameters parameters(bc); - bc->m_buildDirManager.setParametersAndRequestParse(parameters, - BuildDirManager::REPARSE_CHECK_CONFIGURATION - | BuildDirManager::REPARSE_FORCE_CMAKE_RUN - | BuildDirManager::REPARSE_URGENT); -} - -void CMakeProject::runCMakeAndScanProjectTree() -{ - CMakeBuildConfiguration *bc = activeBc(this); - if (isParsing() || !bc) - return; - - BuildDirParameters parameters(bc); - bc->m_buildDirManager.setParametersAndRequestParse(parameters, - BuildDirManager::REPARSE_CHECK_CONFIGURATION - | BuildDirManager::REPARSE_SCAN); -} - -void CMakeProject::buildCMakeTarget(const QString &buildTarget) -{ - QTC_ASSERT(!buildTarget.isEmpty(), return); - CMakeBuildConfiguration *bc = activeBc(this); - if (bc) - bc->buildTarget(buildTarget); -} ProjectImporter *CMakeProject::projectImporter() const { @@ -148,19 +109,6 @@ ProjectImporter *CMakeProject::projectImporter() const return m_projectImporter.get(); } -bool CMakeProject::persistCMakeState() -{ - CMakeBuildConfiguration *bc = activeBc(this); - return bc ? bc->m_buildDirManager.persistCMakeState() : false; -} - -void CMakeProject::clearCMakeCache() -{ - CMakeBuildConfiguration *bc = activeBc(this); - if (bc) - bc->m_buildDirManager.clearCache(); -} - bool CMakeProject::setupTarget(Target *t) { t->updateDefaultBuildConfigurations(); @@ -170,42 +118,6 @@ bool CMakeProject::setupTarget(Target *t) return true; } -QStringList CMakeProject::filesGeneratedFrom(const QString &sourceFile) const -{ - if (!activeTarget()) - return QStringList(); - QFileInfo fi(sourceFile); - FilePath project = projectDirectory(); - FilePath baseDirectory = FilePath::fromString(fi.absolutePath()); - - while (baseDirectory.isChildOf(project)) { - const FilePath cmakeListsTxt = baseDirectory.pathAppended("CMakeLists.txt"); - if (cmakeListsTxt.exists()) - break; - baseDirectory = baseDirectory.parentDir(); - } - - QDir srcDirRoot = QDir(project.toString()); - QString relativePath = srcDirRoot.relativeFilePath(baseDirectory.toString()); - QDir buildDir = QDir(activeTarget()->activeBuildConfiguration()->buildDirectory().toString()); - QString generatedFilePath = buildDir.absoluteFilePath(relativePath); - - if (fi.suffix() == "ui") { - generatedFilePath += "/ui_"; - generatedFilePath += fi.completeBaseName(); - generatedFilePath += ".h"; - return QStringList(QDir::cleanPath(generatedFilePath)); - } else if (fi.suffix() == "scxml") { - generatedFilePath += "/"; - generatedFilePath += QDir::cleanPath(fi.completeBaseName()); - return QStringList({generatedFilePath + ".h", - generatedFilePath + ".cpp"}); - } else { - // TODO: Other types will be added when adapters for their compilers become available. - return QStringList(); - } -} - ProjectExplorer::DeploymentKnowledge CMakeProject::deploymentKnowledge() const { return !files([](const ProjectExplorer::Node *n) { @@ -232,9 +144,4 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target, return cmd; } -bool CMakeProject::mustUpdateCMakeStateBeforeBuild() const -{ - return buildSystem()->isWaitingForParse(); -} - } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 1b5dcca35c6..484e860097d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -49,24 +49,12 @@ public: ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final; - void runCMake(); - void runCMakeAndScanProjectTree(); - - // Context menu actions: - void buildCMakeTarget(const QString &buildTarget); - ProjectExplorer::ProjectImporter *projectImporter() const final; - bool persistCMakeState(); - void clearCMakeCache(); - bool mustUpdateCMakeStateBeforeBuild() const; - protected: bool setupTarget(ProjectExplorer::Target *t) final; private: - QStringList filesGeneratedFrom(const QString &sourceFile) const final; - ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target, const QString &installRoot) override; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index 10f8202ad5d..be27ebb4f17 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -78,7 +78,7 @@ CMakeManager::CMakeManager() : command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY); connect(m_runCMakeAction, &QAction::triggered, [this]() { - runCMake(SessionManager::startupProject()); + runCMake(SessionManager::startupBuildSystem()); }); command = Core::ActionManager::registerAction(m_clearCMakeCacheAction, @@ -86,7 +86,7 @@ CMakeManager::CMakeManager() : command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY); connect(m_clearCMakeCacheAction, &QAction::triggered, [this]() { - clearCMakeCache(SessionManager::startupProject()); + clearCMakeCache(SessionManager::startupBuildSystem()); }); command = Core::ActionManager::registerAction(m_runCMakeActionContextMenu, @@ -95,7 +95,7 @@ CMakeManager::CMakeManager() : mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); connect(m_runCMakeActionContextMenu, &QAction::triggered, [this]() { - runCMake(ProjectTree::currentProject()); + runCMake(ProjectTree::currentBuildSystem()); }); m_buildFileContextMenu = new QAction(tr("Build"), this); @@ -111,7 +111,7 @@ CMakeManager::CMakeManager() : command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY); connect(m_rescanProjectAction, &QAction::triggered, [this]() { - rescanProject(ProjectTree::currentProject()); + rescanProject(ProjectTree::currentBuildSystem()); }); m_buildFileAction = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""), @@ -146,34 +146,29 @@ void CMakeManager::updateCmakeActions() enableBuildFileMenus(ProjectTree::currentNode()); } -void CMakeManager::clearCMakeCache(Project *project) +void CMakeManager::clearCMakeCache(BuildSystem *buildSystem) { - auto cmakeProject = qobject_cast<CMakeProject *>(project); - if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration()) - return; + auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem); + QTC_ASSERT(cmakeBuildSystem, return); - cmakeProject->clearCMakeCache(); + cmakeBuildSystem->clearCMakeCache(); } -void CMakeManager::runCMake(Project *project) +void CMakeManager::runCMake(BuildSystem *buildSystem) { - auto cmakeProject = qobject_cast<CMakeProject *>(project); - if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration()) - return; - - if (!ProjectExplorerPlugin::saveModifiedFiles()) - return; + auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem); + QTC_ASSERT(cmakeBuildSystem, return); - cmakeProject->runCMake(); + if (ProjectExplorerPlugin::saveModifiedFiles()) + cmakeBuildSystem->runCMake(); } -void CMakeManager::rescanProject(Project *project) +void CMakeManager::rescanProject(BuildSystem *buildSystem) { - auto cmakeProject = qobject_cast<CMakeProject *>(project); - if (!cmakeProject || !cmakeProject->activeTarget() || !cmakeProject->activeTarget()->activeBuildConfiguration()) - return; + auto cmakeBuildSystem = dynamic_cast<CMakeBuildSystem *>(buildSystem); + QTC_ASSERT(cmakeBuildSystem, return); - cmakeProject->runCMakeAndScanProjectTree();// by my experience: every rescan run requires cmake run too + cmakeBuildSystem->runCMakeAndScanProjectTree();// by my experience: every rescan run requires cmake run too } void CMakeManager::updateBuildFileAction() @@ -235,14 +230,15 @@ void CMakeManager::buildFile(Node *node) CMakeTargetNode *targetNode = dynamic_cast<CMakeTargetNode *>(fileNode->parentProjectNode()); if (!targetNode) return; - auto cmakeProject = static_cast<CMakeProject *>(project); - Target *target = cmakeProject->activeTarget(); + Target *target = project->activeTarget(); + QTC_ASSERT(target, return); const QString generator = CMakeGeneratorKitAspect::generator(target->kit()); const QString relativeSource = fileNode->filePath().relativeChildPath(targetNode->filePath()).toString(); const QString objExtension = Utils::HostOsInfo::isWindowsHost() ? QString(".obj") : QString(".o"); Utils::FilePath targetBase; + BuildConfiguration *bc = target->activeBuildConfiguration(); + QTC_ASSERT(bc, return); if (generator == "Ninja") { - BuildConfiguration *bc = target->activeBuildConfiguration(); const Utils::FilePath relativeBuildDir = targetNode->buildDirectory().relativeChildPath( bc->buildDirectory()); targetBase = relativeBuildDir @@ -253,7 +249,9 @@ void CMakeManager::buildFile(Node *node) .arg(generator)); return; } - cmakeProject->buildCMakeTarget(targetBase.pathAppended(relativeSource).toString() + objExtension); + + static_cast<CMakeBuildSystem *>(bc->buildSystem()) + ->buildCMakeTarget(targetBase.pathAppended(relativeSource).toString() + objExtension); } void CMakeManager::buildFileContextMenu() diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index eab78b190a2..db3b10b6e2c 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -45,9 +45,9 @@ public: private: void updateCmakeActions(); - void clearCMakeCache(ProjectExplorer::Project *project); - void runCMake(ProjectExplorer::Project *project); - void rescanProject(ProjectExplorer::Project *project); + void clearCMakeCache(ProjectExplorer::BuildSystem *buildSystem); + void runCMake(ProjectExplorer::BuildSystem *buildSystem); + void rescanProject(ProjectExplorer::BuildSystem *buildSystem); void buildFileContextMenu(); void buildFile(ProjectExplorer::Node *node = nullptr); void updateBuildFileAction(); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 9943ca5784a..46c50104ed9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -265,7 +265,10 @@ Utils::optional<Utils::FilePath> CMakeTargetNode::visibleAfterAddFileAction() co void CMakeTargetNode::build() { - static_cast<CMakeProject *>(getProject())->buildCMakeTarget(displayName()); + Project *p = getProject(); + Target *t = p ? p->activeTarget() : nullptr; + if (t) + static_cast<CMakeBuildSystem *>(t->buildSystem())->buildCMakeTarget(displayName()); } void CMakeTargetNode::setTargetInformation(const QList<Utils::FilePath> &artifacts, diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp index 9eeeb71048a..701b192b5be 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectplugin.cpp @@ -47,6 +47,7 @@ #include <projectexplorer/projectmanager.h> #include <projectexplorer/projecttree.h> #include <projectexplorer/runcontrol.h> +#include <projectexplorer/target.h> #include <texteditor/snippets/snippetprovider.h> @@ -70,8 +71,6 @@ public: ParameterAction::AlwaysEnabled/*handled manually*/ }; - QMetaObject::Connection m_actionConnect; - CMakeSettingsPage settingsPage; CMakeSpecificSettingsPage specificSettings{CMakeProjectPlugin::projectTypeSpecificSettings()}; @@ -129,6 +128,13 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString * connect(ProjectTree::instance(), &ProjectTree::currentNodeChanged, this, &CMakeProjectPlugin::updateContextActions); + connect(&d->buildTargetContextAction, &ParameterAction::triggered, this, [] { + if (auto bs = qobject_cast<CMakeBuildSystem *>(ProjectTree::currentBuildSystem())) { + auto targetNode = dynamic_cast<const CMakeTargetNode *>(ProjectTree::currentNode()); + bs->buildCMakeTarget(targetNode ? targetNode->displayName() : QString()); + } + }); + return true; } @@ -140,24 +146,13 @@ void CMakeProjectPlugin::extensionsInitialized() void CMakeProjectPlugin::updateContextActions() { - Project *project = ProjectTree::currentProject(); - const Node *node = ProjectTree::currentNode(); - auto targetNode = dynamic_cast<const CMakeTargetNode *>(node); - // as targetNode can be deleted while the menu is open, we keep only the + auto targetNode = dynamic_cast<const CMakeTargetNode *>(ProjectTree::currentNode()); const QString targetDisplayName = targetNode ? targetNode->displayName() : QString(); - auto cmProject = dynamic_cast<CMakeProject *>(project); // Build Target: - disconnect(d->m_actionConnect); d->buildTargetContextAction.setParameter(targetDisplayName); d->buildTargetContextAction.setEnabled(targetNode); d->buildTargetContextAction.setVisible(targetNode); - if (cmProject && targetNode) { - d->m_actionConnect = connect(&d->buildTargetContextAction, &ParameterAction::triggered, - cmProject, [cmProject, targetDisplayName]() { - cmProject->buildCMakeTarget(targetDisplayName); - }); - } } } // Internal diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index d9bf685f08b..89f82a780ff 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -337,9 +337,46 @@ void createTree(std::unique_ptr<ProjectNode> &root, } // anonymous namespace -void CompilationDatabaseProject::buildTreeAndProjectParts() +CompilationDatabaseBuildSystem::CompilationDatabaseBuildSystem(Target *target) + : BuildSystem(target) + , m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>()) + , m_parseDelay(new QTimer(this)) + , m_deployFileWatcher(new FileSystemWatcher(this)) +{ + connect(target->project(), &CompilationDatabaseProject::rootProjectDirectoryChanged, + this, [this] { + m_projectFileHash.clear(); + m_parseDelay->start(); + }); + + connect(m_parseDelay, &QTimer::timeout, this, &CompilationDatabaseBuildSystem::reparseProject); + + m_parseDelay->setSingleShot(true); + m_parseDelay->setInterval(1000); + m_parseDelay->start(); + + connect(project(), &Project::projectFileIsDirty, this, &CompilationDatabaseBuildSystem::reparseProject); + + connect(m_deployFileWatcher, &FileSystemWatcher::fileChanged, + this, &CompilationDatabaseBuildSystem::updateDeploymentData); + connect(target->project(), &Project::activeTargetChanged, + this, &CompilationDatabaseBuildSystem::updateDeploymentData); +} + +CompilationDatabaseBuildSystem::~CompilationDatabaseBuildSystem() +{ + m_parserWatcher.cancel(); + m_parserWatcher.waitForFinished(); +} + +void CompilationDatabaseBuildSystem::triggerParsing() +{ + reparseProject(); +} + +void CompilationDatabaseBuildSystem::buildTreeAndProjectParts() { - ProjectExplorer::KitInfo kitInfo(this); + ProjectExplorer::KitInfo kitInfo(project()); QTC_ASSERT(kitInfo.isValid(), return); // Reset toolchains to pick them based on the database entries. kitInfo.cToolChain = nullptr; @@ -349,6 +386,7 @@ void CompilationDatabaseProject::buildTreeAndProjectParts() QTC_ASSERT(m_parser, return); const DbContents dbContents = m_parser->dbContents(); const DbEntry *prevEntry = nullptr; + Kit *kit = static_cast<CompilationDatabaseProject *>(project())->kit(); for (const DbEntry &entry : dbContents.entries) { if (prevEntry && prevEntry->flags == entry.flags) { rpps.back().files.append(entry.fileName.toString()); @@ -358,7 +396,7 @@ void CompilationDatabaseProject::buildTreeAndProjectParts() prevEntry = &entry; RawProjectPart rpp = makeRawProjectPart(projectFilePath(), - m_kit.get(), + kit, kitInfo, entry.workingDir, entry.fileName, @@ -381,7 +419,7 @@ void CompilationDatabaseProject::buildTreeAndProjectParts() auto root = std::make_unique<ProjectNode>(projectDirectory()); - createTree(root, rootProjectDirectory(), rpps, m_parser->scannedFiles()); + createTree(root, project()->rootProjectDirectory(), rpps, m_parser->scannedFiles()); root->addNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project)); @@ -389,43 +427,26 @@ void CompilationDatabaseProject::buildTreeAndProjectParts() root->addNode(std::make_unique<FileNode>(Utils::FilePath::fromString(dbContents.extraFileName), FileType::Project)); - setRootProjectNode(std::move(root)); + project()->setRootProjectNode(std::move(root)); - m_cppCodeModelUpdater->update({this, kitInfo, activeParseEnvironment(), rpps}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), rpps}); updateDeploymentData(); } CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FilePath &projectFile) : Project(Constants::COMPILATIONDATABASEMIMETYPE, projectFile) - , m_cppCodeModelUpdater(std::make_unique<CppTools::CppProjectUpdater>()) - , m_parseDelay(new QTimer(this)) - , m_deployFileWatcher(new FileSystemWatcher(this)) { setId(Constants::COMPILATIONDATABASEPROJECT_ID); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(projectDirectory().fileName()); + setBuildSystemCreator([](Target *t) { return new CompilationDatabaseBuildSystem(t); }); + m_kit.reset(KitManager::defaultKit()->clone()); addTargetForKit(m_kit.get()); - connect(this, &CompilationDatabaseProject::rootProjectDirectoryChanged, - this, [this] { - m_projectFileHash.clear(); - m_parseDelay->start(); - }); - setExtraProjectFiles( {projectFile.stringAppended(Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX)}); - connect(m_parseDelay, &QTimer::timeout, this, &CompilationDatabaseProject::reparseProject); - - m_parseDelay->setSingleShot(true); - m_parseDelay->setInterval(1000); - - connect(this, &Project::projectFileIsDirty, this, &CompilationDatabaseProject::reparseProject); - connect(m_deployFileWatcher, &FileSystemWatcher::fileChanged, - this, &CompilationDatabaseProject::updateDeploymentData); - connect(this, &Project::activeTargetChanged, - this, &CompilationDatabaseProject::updateDeploymentData); } Utils::FilePath CompilationDatabaseProject::rootPathFromSettings() const @@ -442,26 +463,19 @@ Project::RestoreResult CompilationDatabaseProject::fromMap(const QVariantMap &ma QString *errorMessage) { Project::RestoreResult result = Project::fromMap(map, errorMessage); - if (result == Project::RestoreResult::Ok) { - const Utils::FilePath rootPath = rootPathFromSettings(); - if (rootPath.isEmpty()) - changeRootProjectDirectory(); // This triggers reparse itself. - else - reparseProject(); - } - return result; } -void CompilationDatabaseProject::reparseProject() +void CompilationDatabaseBuildSystem::reparseProject() { if (m_parser) { QTC_CHECK(isParsing()); m_parser->stop(); } - m_parser = new CompilationDbParser(displayName(), + const FilePath rootPath = static_cast<CompilationDatabaseProject *>(project())->rootPathFromSettings(); + m_parser = new CompilationDbParser(project()->displayName(), projectFilePath(), - rootPathFromSettings(), + rootPath, m_mimeBinaryCache, guardParsingRun(), this); @@ -475,17 +489,14 @@ void CompilationDatabaseProject::reparseProject() m_parser->start(); } -void CompilationDatabaseProject::updateDeploymentData() +void CompilationDatabaseBuildSystem::updateDeploymentData() { - Target * const target = activeTarget(); - if (!target) - return; const Utils::FilePath deploymentFilePath = projectDirectory() .pathAppended("QtCreatorDeployment.txt"); DeploymentData deploymentData; deploymentData.addFilesFromDeploymentFile(deploymentFilePath.toString(), projectDirectory().toString()); - target->setDeploymentData(deploymentData); + setDeploymentData(deploymentData); if (m_deployFileWatcher->files() != QStringList(deploymentFilePath.toString())) { m_deployFileWatcher->removeFiles(m_deployFileWatcher->files()); m_deployFileWatcher->addFile(deploymentFilePath.toString(), @@ -493,12 +504,6 @@ void CompilationDatabaseProject::updateDeploymentData() } } -CompilationDatabaseProject::~CompilationDatabaseProject() -{ - m_parserWatcher.cancel(); - m_parserWatcher.waitForFinished(); -} - static TextEditor::TextDocument *createCompilationDatabaseDocument() { auto doc = new TextEditor::TextDocument; diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h index 900f7d36756..98ff726a19b 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h @@ -28,8 +28,11 @@ #include "compilationdatabaseutils.h" #include <projectexplorer/buildconfiguration.h> +#include <projectexplorer/buildsystem.h> #include <projectexplorer/project.h> + #include <texteditor/texteditor.h> + #include <utils/filesystemwatcher.h> #include <QFutureWatcher> @@ -52,20 +55,31 @@ class CompilationDatabaseProject : public ProjectExplorer::Project public: explicit CompilationDatabaseProject(const Utils::FilePath &filename); - ~CompilationDatabaseProject() override; + bool needsConfiguration() const override { return false; } + Utils::FilePath rootPathFromSettings() const; + ProjectExplorer::Kit *kit() const { return m_kit.get(); } + private: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; + std::unique_ptr<ProjectExplorer::Kit> m_kit; +}; + +class CompilationDatabaseBuildSystem : public ProjectExplorer::BuildSystem +{ +public: + explicit CompilationDatabaseBuildSystem(ProjectExplorer::Target *target); + ~CompilationDatabaseBuildSystem(); + + void triggerParsing() final; void reparseProject(); void updateDeploymentData(); void buildTreeAndProjectParts(); - Utils::FilePath rootPathFromSettings() const; QFutureWatcher<void> m_parserWatcher; std::unique_ptr<CppTools::CppProjectUpdater> m_cppCodeModelUpdater; - std::unique_ptr<ProjectExplorer::Kit> m_kit; MimeBinaryCache m_mimeBinaryCache; QByteArray m_projectFileHash; QTimer * const m_parseDelay; diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 374c245b23b..1505dffa1a7 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -48,7 +48,7 @@ CompilationDbParser::CompilationDbParser(const QString &projectName, const FilePath &projectPath, const FilePath &rootPath, MimeBinaryCache &mimeBinaryCache, - ProjectExplorer::Project::ParseGuard &&guard, + BuildSystem::ParseGuard &&guard, QObject *parent) : QObject(parent) , m_projectName(projectName) diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h index ac5fbb0afb3..dd126d9fd1c 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.h @@ -27,7 +27,7 @@ #include "compilationdatabaseutils.h" -#include <projectexplorer/project.h> +#include <projectexplorer/buildsystem.h> #include <utils/fileutils.h> @@ -56,7 +56,7 @@ public: const Utils::FilePath &projectPath, const Utils::FilePath &rootPath, MimeBinaryCache &mimeBinaryCache, - ProjectExplorer::Project::ParseGuard &&guard, + ProjectExplorer::BuildSystem::ParseGuard &&guard, QObject *parent = nullptr); @@ -91,7 +91,7 @@ private: QByteArray m_projectFileContents; QByteArray m_projectFileHash; - ProjectExplorer::Project::ParseGuard m_guard; + ProjectExplorer::BuildSystem::ParseGuard m_guard; }; } // namespace Internal diff --git a/src/plugins/designer/codemodelhelpers.cpp b/src/plugins/designer/codemodelhelpers.cpp index 5f3422e4121..f57f1081d28 100644 --- a/src/plugins/designer/codemodelhelpers.cpp +++ b/src/plugins/designer/codemodelhelpers.cpp @@ -27,15 +27,19 @@ #include <cpptools/cppmodelmanager.h> +#include <projectexplorer/buildsystem.h> #include <projectexplorer/project.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/session.h> +#include <projectexplorer/target.h> #include <QCoreApplication> #include <QDebug> // Debug helpers for code model. @todo: Move to some CppTools library? +using namespace ProjectExplorer; + typedef QMap<QString, QStringList> DependencyMap; typedef CPlusPlus::Document::Ptr DocumentPtr; typedef QList<CPlusPlus::Symbol *> SymbolList; @@ -46,11 +50,15 @@ static const char setupUiC[] = "setupUi"; // Find the generated "ui_form.h" header of the form via project. static QString generatedHeaderOf(const QString &uiFileName) { - if (const ProjectExplorer::Project *uiProject = - ProjectExplorer::SessionManager::projectForFile(Utils::FilePath::fromString(uiFileName))) { - QStringList files = uiProject->filesGeneratedFrom(uiFileName); - if (!files.isEmpty()) // There should be at most one header generated from a .ui - return files.front(); + if (const Project *uiProject = + SessionManager::projectForFile(Utils::FilePath::fromString(uiFileName))) { + if (Target *t = uiProject->activeTarget()) { + if (BuildSystem *bs = t->buildSystem()) { + QStringList files = bs->filesGeneratedFrom(uiFileName); + if (!files.isEmpty()) // There should be at most one header generated from a .ui + return files.front(); + } + } } return QString(); } diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 312a9cfb1ea..7a7e7c56e9e 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -120,9 +120,11 @@ private: class GenericBuildSystem : public BuildSystem { public: - explicit GenericBuildSystem(Project *project); + explicit GenericBuildSystem(Target *target); ~GenericBuildSystem(); + void triggerParsing() final; + bool supportsAction(Node *, ProjectAction action, const Node *) const final { return action == AddNewFile @@ -136,8 +138,6 @@ public: bool renameFile(Node *, const QString &filePath, const QString &newFilePath) final; bool addFiles(Node *, const QStringList &filePaths, QStringList *) final; - GenericProject *project() const { return static_cast<GenericProject *>(BuildSystem::project()); } - FilePath filesFilePath() const { return ::FilePath::fromString(m_filesFileName); } void refresh(RefreshOptions options); @@ -172,7 +172,9 @@ private: CppTools::CppProjectUpdaterInterface *m_cppCodeModelUpdater = nullptr; - Utils::FileSystemWatcher * const m_deployFileWatcher = nullptr; + Utils::FileSystemWatcher m_deployFileWatcher; + + ParseGuard m_guard; }; @@ -194,11 +196,11 @@ GenericProject::GenericProject(const Utils::FilePath &fileName) setId(Constants::GENERICPROJECT_ID); setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(fileName.toFileInfo().completeBaseName()); - setBuildSystemCreator([](Project *p) { return new GenericBuildSystem(p); }); + setBuildSystemCreator([](Target *t) { return new GenericBuildSystem(t); }); } -GenericBuildSystem::GenericBuildSystem(Project *project) - : BuildSystem(project) +GenericBuildSystem::GenericBuildSystem(Target *target) + : BuildSystem(target) { QObject *projectUpdaterFactory = ExtensionSystem::PluginManager::getObjectByName( "CppProjectUpdaterFactory"); @@ -211,7 +213,7 @@ GenericBuildSystem::GenericBuildSystem(Project *project) QTC_CHECK(successFullyCreatedProjectUpdater); } - connect(project, &Project::projectFileIsDirty, this, [this](const FilePath &p) { + connect(target->project(), &Project::projectFileIsDirty, this, [this](const FilePath &p) { if (p.endsWith(".files")) refresh(Files); else if (p.endsWith(".includes") || p.endsWith(".config") || p.endsWith(".cxxflags") @@ -242,18 +244,16 @@ GenericBuildSystem::GenericBuildSystem(Project *project) QTC_CHECK(writeFile(m_cflagsFileName, Constants::GENERICPROJECT_CFLAGS_FILE_TEMPLATE)); } - project->setExtraProjectFiles({FilePath::fromString(m_filesFileName), - FilePath::fromString(m_includesFileName), - FilePath::fromString(m_configFileName), - FilePath::fromString(m_cxxflagsFileName), - FilePath::fromString(m_cflagsFileName)}); + project()->setExtraProjectFiles({FilePath::fromString(m_filesFileName), + FilePath::fromString(m_includesFileName), + FilePath::fromString(m_configFileName), + FilePath::fromString(m_cxxflagsFileName), + FilePath::fromString(m_cflagsFileName)}); - connect(m_deployFileWatcher, &FileSystemWatcher::fileChanged, + connect(&m_deployFileWatcher, &FileSystemWatcher::fileChanged, this, &GenericBuildSystem::updateDeploymentData); - connect(project, &Project::activeTargetChanged, this, [this] { refresh(Everything); }); - - connect(project, &Project::activeBuildConfigurationChanged, this, [this] { refresh(Everything); }); + connect(target, &Target::activeBuildConfigurationChanged, this, [this] { refresh(Everything); }); } GenericBuildSystem::~GenericBuildSystem() @@ -261,6 +261,12 @@ GenericBuildSystem::~GenericBuildSystem() delete m_cppCodeModelUpdater; } +void GenericBuildSystem::triggerParsing() +{ + m_guard = guardParsingRun(); + refresh(Everything); +} + static QStringList readLines(const QString &absoluteFileName) { QStringList lines; @@ -455,7 +461,7 @@ FilePath GenericBuildSystem::findCommonSourceRoot() void GenericBuildSystem::refresh(RefreshOptions options) { - Project::ParseGuard guard = project()->guardParsingRun(); + ParseGuard guard = guardParsingRun(); parse(options); if (options & Files) { @@ -504,9 +510,7 @@ void GenericBuildSystem::refresh(RefreshOptions options) QStringList GenericBuildSystem::processEntries(const QStringList &paths, QHash<QString, QString> *map) const { - Target *target = project()->activeTarget(); - const BuildConfiguration *const buildConfig = target ? target->activeBuildConfiguration() - : nullptr; + const BuildConfiguration *const buildConfig = target()->activeBuildConfiguration(); const Utils::Environment buildEnv = buildConfig ? buildConfig->environment() : Utils::Environment::systemEnvironment(); @@ -514,8 +518,8 @@ QStringList GenericBuildSystem::processEntries(const QStringList &paths, const Utils::MacroExpander *expander = project()->macroExpander(); if (buildConfig) expander = buildConfig->macroExpander(); - else if (target) - expander = target->macroExpander(); + else + expander = target()->macroExpander(); const QDir projectDir(projectDirectory().toString()); @@ -560,7 +564,7 @@ void GenericBuildSystem::refreshCppCodeModel() rpp.setFlagsForC({nullptr, m_cflags}); rpp.setFiles(m_files); - m_cppCodeModelUpdater->update({project(), kitInfo, project()->activeParseEnvironment(), {rpp}}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), {rpp}}); } void GenericBuildSystem::updateDeploymentData() @@ -581,11 +585,11 @@ void GenericBuildSystem::updateDeploymentData() DeploymentData deploymentData; deploymentData.addFilesFromDeploymentFile(deploymentFilePath.toString(), projectDirectory().toString()); - project()->activeTarget()->setDeploymentData(deploymentData); - if (m_deployFileWatcher->files() != QStringList(deploymentFilePath.toString())) { - m_deployFileWatcher->removeFiles(m_deployFileWatcher->files()); - m_deployFileWatcher->addFile(deploymentFilePath.toString(), - FileSystemWatcher::WatchModifiedDate); + setDeploymentData(deploymentData); + if (m_deployFileWatcher.files() != QStringList(deploymentFilePath.toString())) { + m_deployFileWatcher.removeFiles(m_deployFileWatcher.files()); + m_deployFileWatcher.addFile(deploymentFilePath.toString(), + FileSystemWatcher::WatchModifiedDate); } } } @@ -622,7 +626,9 @@ Project::RestoreResult GenericProject::fromMap(const QVariantMap &map, QString * t->addRunConfiguration(new CustomExecutableRunConfiguration(t)); } - static_cast<GenericBuildSystem *>(buildSystem())->refresh(Everything); + if (Target *t = activeTarget()) + static_cast<GenericBuildSystem *>(t->buildSystem())->refresh(Everything); + return RestoreResult::Ok; } @@ -637,7 +643,10 @@ bool GenericProjectFile::reload(QString *errorString, IDocument::ReloadFlag flag Q_UNUSED(flag) if (type == TypePermissions) return true; - static_cast<GenericBuildSystem *>(m_project->buildSystem())->refresh(m_options); + + if (Target *t = m_project->activeTarget()) + static_cast<GenericBuildSystem *>(t->buildSystem())->refresh(m_options); + return true; } @@ -646,14 +655,18 @@ void GenericProject::editFilesTriggered() SelectableFilesDialogEditFiles sfd(projectDirectory(), files(Project::AllFiles), ICore::mainWindow()); - if (sfd.exec() == QDialog::Accepted) - static_cast<GenericBuildSystem *>(buildSystem()) - ->setFiles(transform(sfd.selectedFiles(), &FilePath::toString)); + if (sfd.exec() == QDialog::Accepted) { + if (Target *t = activeTarget()) { + auto bs = static_cast<GenericBuildSystem *>(t->buildSystem()); + bs->setFiles(transform(sfd.selectedFiles(), &FilePath::toString)); + } + } } void GenericProject::removeFilesTriggered(const QStringList &filesToRemove) { - static_cast<GenericBuildSystem *>(buildSystem())->removeFiles(filesToRemove); + if (Target *t = activeTarget()) + static_cast<GenericBuildSystem *>(t->buildSystem())->removeFiles(filesToRemove); } } // namespace Internal diff --git a/src/plugins/ios/iosrunconfiguration.cpp b/src/plugins/ios/iosrunconfiguration.cpp index fb1389b9692..96b6d17bc16 100644 --- a/src/plugins/ios/iosrunconfiguration.cpp +++ b/src/plugins/ios/iosrunconfiguration.cpp @@ -139,19 +139,17 @@ void IosRunConfiguration::updateDisplayNames() aspect<ExecutableAspect>()->setExecutable(localExecutable()); } -void IosRunConfiguration::updateEnabledState() +bool IosRunConfiguration::isEnabled() const { Core::Id devType = DeviceTypeKitAspect::deviceTypeId(target()->kit()); - if (devType != Constants::IOS_DEVICE_TYPE && devType != Constants::IOS_SIMULATOR_TYPE) { - setEnabled(false); - return; - } + if (devType != Constants::IOS_DEVICE_TYPE && devType != Constants::IOS_SIMULATOR_TYPE) + return false; + IDevice::ConstPtr dev = DeviceKitAspect::device(target()->kit()); - if (dev.isNull() || dev->deviceState() != IDevice::DeviceReadyToUse) { - setEnabled(false); - return; - } - return RunConfiguration::updateEnabledState(); + if (dev.isNull() || dev->deviceState() != IDevice::DeviceReadyToUse) + return false; + + return true; } QString IosRunConfiguration::applicationName() const diff --git a/src/plugins/ios/iosrunconfiguration.h b/src/plugins/ios/iosrunconfiguration.h index b9b44ecf5c5..11746fd316b 100644 --- a/src/plugins/ios/iosrunconfiguration.h +++ b/src/plugins/ios/iosrunconfiguration.h @@ -55,7 +55,7 @@ public: private: friend class IosDeviceTypeAspect; void updateDisplayNames(); - void updateEnabledState() final; + bool isEnabled() const final; IosDeviceTypeAspect *m_deviceTypeAspect = nullptr; }; diff --git a/src/plugins/nim/nimconstants.h b/src/plugins/nim/nimconstants.h index 61b281fbc7f..a8c3863ca8f 100644 --- a/src/plugins/nim/nimconstants.h +++ b/src/plugins/nim/nimconstants.h @@ -40,10 +40,6 @@ const char C_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("OpenWith::Editors", "Nim const char C_NIMTOOLCHAIN_TYPEID[] = "Nim.NimToolChain"; const char C_NIMTOOLCHAIN_COMPILER_COMMAND_KEY[] = "Nim.NimToolChain.CompilerCommand"; -// NimbleProject -const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks"; -const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata"; - // NimProject const char C_NIMPROJECT_EXCLUDEDFILES[] = "Nim.NimProjectExcludedFiles"; diff --git a/src/plugins/nim/project/nimblebuildconfiguration.cpp b/src/plugins/nim/project/nimblebuildconfiguration.cpp index 8b947ce3cc0..14e134672f9 100644 --- a/src/plugins/nim/project/nimblebuildconfiguration.cpp +++ b/src/plugins/nim/project/nimblebuildconfiguration.cpp @@ -24,9 +24,11 @@ ****************************************************************************/ #include "nimblebuildconfiguration.h" + #include "nimconstants.h" #include "nimblebuildstep.h" #include "nimbleproject.h" +#include "nimblebuildsystem.h" #include <projectexplorer/buildinfo.h> #include <projectexplorer/buildstep.h> @@ -52,10 +54,8 @@ NimbleBuildConfiguration::NimbleBuildConfiguration(Target *target, Core::Id id) setConfigWidgetHasFrame(true); setBuildDirectorySettingsKey("Nim.NimbleBuildConfiguration.BuildDirectory"); - m_nimbleProject = dynamic_cast<NimbleProject*>(project()); - QTC_ASSERT(m_nimbleProject, return); - QObject::connect(m_nimbleProject, &NimbleProject::metadataChanged, this, &NimbleBuildConfiguration::updateApplicationTargets); - updateApplicationTargets(); + m_nimbleBuildSystem = dynamic_cast<NimbleBuildSystem *>(buildSystem()); + QTC_ASSERT(m_nimbleBuildSystem, return); } BuildConfiguration::BuildType NimbleBuildConfiguration::buildType() const @@ -72,35 +72,13 @@ void NimbleBuildConfiguration::initialize() setBuildDirectory(project()->projectDirectory()); // Don't add a nimble build step when the package has no binaries (i.e a library package) - if (!m_nimbleProject->metadata().bin.empty()) + if (!m_nimbleBuildSystem->metadata().bin.empty()) { BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); buildSteps->appendStep(new NimbleBuildStep(buildSteps)); } } -void NimbleBuildConfiguration::updateApplicationTargets() -{ - QTC_ASSERT(m_nimbleProject, return); - - const NimbleMetadata &metaData = m_nimbleProject->metadata(); - const FilePath &projectDir = project()->projectDirectory(); - const FilePath binDir = projectDir.pathAppended(metaData.binDir); - const FilePath srcDir = projectDir.pathAppended("src"); - - QList<BuildTargetInfo> targets = Utils::transform(metaData.bin, [&](const QString &bin){ - BuildTargetInfo info = {}; - info.displayName = bin; - info.targetFilePath = binDir.pathAppended(HostOsInfo::withExecutableSuffix(bin)); - info.projectFilePath = srcDir.pathAppended(bin).stringAppended(".nim"); - info.workingDirectory = binDir; - info.buildKey = bin; - return info; - }); - - target()->setApplicationTargets(std::move(targets)); -} - bool NimbleBuildConfiguration::fromMap(const QVariantMap &map) { m_buildType = static_cast<BuildType>(map[Constants::C_NIMBLEBUILDCONFIGURATION_BUILDTYPE].toInt()); diff --git a/src/plugins/nim/project/nimblebuildconfiguration.h b/src/plugins/nim/project/nimblebuildconfiguration.h index 5ba6b5c2180..f7e7dc4dc7a 100644 --- a/src/plugins/nim/project/nimblebuildconfiguration.h +++ b/src/plugins/nim/project/nimblebuildconfiguration.h @@ -30,7 +30,7 @@ namespace Nim { -class NimbleProject; +class NimbleBuildSystem; class NimbleBuildConfiguration : public ProjectExplorer::BuildConfiguration { @@ -49,10 +49,8 @@ class NimbleBuildConfiguration : public ProjectExplorer::BuildConfiguration protected: void initialize() override; - void updateApplicationTargets(); - private: - NimbleProject *m_nimbleProject = nullptr; + NimbleBuildSystem *m_nimbleBuildSystem = nullptr; BuildType m_buildType; }; diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp index d968b503916..2ec092bd568 100644 --- a/src/plugins/nim/project/nimblebuildsystem.cpp +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -26,6 +26,8 @@ #include "nimblebuildsystem.h" #include "nimbleproject.h" +#include <projectexplorer/target.h> + #include <utils/algorithm.h> #include <utils/qtcassert.h> @@ -38,6 +40,9 @@ using namespace Utils; namespace { +const char C_NIMBLEPROJECT_TASKS[] = "Nim.NimbleProject.Tasks"; +const char C_NIMBLEPROJECT_METADATA[] = "Nim.NimbleProject.Metadata"; + std::vector<NimbleTask> parseTasks(const QString &nimblePath, const QString &workingDirectory) { QProcess process; @@ -102,28 +107,25 @@ NimbleMetadata parseMetadata(const QString &nimblePath, const QString &workingDi } -NimbleBuildSystem::NimbleBuildSystem(Project *project) - : NimBuildSystem(project) +NimbleBuildSystem::NimbleBuildSystem(Target *target) + : NimBuildSystem(target) { // Not called in parseProject due to nimble behavior to create temporary // files in project directory. This creation in turn stimulate the fs watcher // that in turn causes project parsing (thus a loop if invoke in parseProject). // For this reason we call this function manually during project creation // See https://github.com/nim-lang/nimble/issues/720 - m_directoryWatcher.addFile(this->project()->projectFilePath().toString(), - FileSystemWatcher::WatchModifiedDate); + m_directoryWatcher.addFile(projectFilePath().toString(), FileSystemWatcher::WatchModifiedDate); + connect(&m_directoryWatcher, &FileSystemWatcher::fileChanged, this, [this](const QString &path) { - if (path == this->project()->projectFilePath().toString()) { + if (path == project()->projectFilePath().toString()) { updateProject(); } }); + updateProject(); } -void NimbleBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) -{ - NimBuildSystem::parseProject(std::move(ctx)); -} void NimbleBuildSystem::updateProject() { @@ -133,14 +135,82 @@ void NimbleBuildSystem::updateProject() void NimbleBuildSystem::updateProjectTasks() { - auto prj = dynamic_cast<NimbleProject*>(project()); - QTC_ASSERT(prj, return); - prj->setTasks(parseTasks(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); + setTasks(parseTasks(QStandardPaths::findExecutable("nimble"), projectDirectory().toString())); } void NimbleBuildSystem::updateProjectMetaData() { - auto prj = dynamic_cast<NimbleProject*>(project()); - QTC_ASSERT(prj, return); - prj->setMetadata(parseMetadata(QStandardPaths::findExecutable("nimble"), project()->projectDirectory().toString())); + setMetadata(parseMetadata(QStandardPaths::findExecutable("nimble"), projectDirectory().toString())); +} + +void NimbleBuildSystem::updateApplicationTargets() +{ + const NimbleMetadata &metaData = metadata(); + const FilePath &projectDir = project()->projectDirectory(); + const FilePath binDir = projectDir.pathAppended(metaData.binDir); + const FilePath srcDir = projectDir.pathAppended("src"); + + QList<BuildTargetInfo> targets = Utils::transform(metaData.bin, [&](const QString &bin){ + BuildTargetInfo info = {}; + info.displayName = bin; + info.targetFilePath = binDir.pathAppended(HostOsInfo::withExecutableSuffix(bin)); + info.projectFilePath = srcDir.pathAppended(bin).stringAppended(".nim"); + info.workingDirectory = binDir; + info.buildKey = bin; + return info; + }); + + setApplicationTargets(std::move(targets)); +} + +std::vector<NimbleTask> NimbleBuildSystem::tasks() const +{ + return m_tasks; +} + +NimbleMetadata NimbleBuildSystem::metadata() const +{ + return m_metadata; +} + +void NimbleBuildSystem::setTasks(std::vector<NimbleTask> tasks) +{ + if (tasks == m_tasks) + return; + m_tasks = std::move(tasks); + emit tasksChanged(); + emit target()->targetPropertiesChanged(); +} + +void NimbleBuildSystem::setMetadata(NimbleMetadata metadata) +{ + if (m_metadata == metadata) + return; + m_metadata = std::move(metadata); + + updateApplicationTargets(); +} + +void NimbleBuildSystem::saveSettings() +{ + QStringList result; + for (const NimbleTask &task : m_tasks) { + result.push_back(task.name); + result.push_back(task.description); + } + + project()->setNamedSettings(C_NIMBLEPROJECT_TASKS, result); +} + +void NimbleBuildSystem::loadSettings() +{ + QStringList list = project()->namedSettings(C_NIMBLEPROJECT_TASKS).toStringList(); + + m_tasks.clear(); + if (list.size() % 2 != 0) + return; + + std::vector<NimbleTask> result; + for (int i = 0; i < list.size(); i += 2) + result.push_back({list[i], list[i + 1]}); } diff --git a/src/plugins/nim/project/nimblebuildsystem.h b/src/plugins/nim/project/nimblebuildsystem.h index 45c540598e5..36beb27e91d 100644 --- a/src/plugins/nim/project/nimblebuildsystem.h +++ b/src/plugins/nim/project/nimblebuildsystem.h @@ -29,19 +29,55 @@ namespace Nim { +struct NimbleTask +{ + QString name; + QString description; + + bool operator==(const NimbleTask &o) const { + return name == o.name && description == o.description; + } +}; + +struct NimbleMetadata +{ + QStringList bin; + QString binDir; + QString srcDir; + + bool operator==(const NimbleMetadata &o) const { + return bin == o.bin && binDir == o.binDir && srcDir == o.srcDir; + } +}; + class NimbleBuildSystem : public NimBuildSystem { Q_OBJECT public: - NimbleBuildSystem(ProjectExplorer::Project *project); + NimbleBuildSystem(ProjectExplorer::Target *target); + + std::vector<NimbleTask> tasks() const; + + NimbleMetadata metadata() const; -protected: - void parseProject(ParsingContext &&ctx) override; + void setTasks(std::vector<NimbleTask> tasks); + void setMetadata(NimbleMetadata metadata); + +signals: + void tasksChanged(); + +private: + void loadSettings() override; + void saveSettings() override; void updateProject(); void updateProjectTasks(); void updateProjectMetaData(); + void updateApplicationTargets(); + + NimbleMetadata m_metadata; + std::vector<NimbleTask> m_tasks; }; } diff --git a/src/plugins/nim/project/nimbleproject.cpp b/src/plugins/nim/project/nimbleproject.cpp index 9003e55a930..cc77d94f367 100644 --- a/src/plugins/nim/project/nimbleproject.cpp +++ b/src/plugins/nim/project/nimbleproject.cpp @@ -41,70 +41,7 @@ NimbleProject::NimbleProject(const Utils::FilePath &fileName) setDisplayName(fileName.toFileInfo().completeBaseName()); // ensure debugging is enabled (Nim plugin translates nim code to C code) setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); - setBuildSystemCreator([] (Project *p) { return new NimbleBuildSystem(p); }); + setBuildSystemCreator([] (Target *t) { return new NimbleBuildSystem(t); }); } -std::vector<NimbleTask> NimbleProject::tasks() const -{ - return m_tasks; -} - -NimbleMetadata NimbleProject::metadata() const -{ - return m_metadata; -} - -void NimbleProject::setTasks(std::vector<NimbleTask> tasks) -{ - if (tasks == m_tasks) - return; - m_tasks = std::move(tasks); - emit tasksChanged(m_tasks); -} - -void NimbleProject::setMetadata(NimbleMetadata metadata) -{ - if (m_metadata == metadata) - return; - m_metadata = std::move(metadata); - emit metadataChanged(m_metadata); -} -QVariantMap NimbleProject::toMap() const -{ - QVariantMap result = Project::toMap(); - result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = static_cast<NimBuildSystem *>(buildSystem()) - ->excludedFiles(); - result[Constants::C_NIMBLEPROJECT_TASKS] = toStringList(m_tasks); - return result; -} - -Project::RestoreResult NimbleProject::fromMap(const QVariantMap &map, QString *errorMessage) -{ - static_cast<NimBuildSystem *>(buildSystem()) - ->setExcludedFiles(map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList()); - Project::RestoreResult result = Project::RestoreResult::Error; - std::tie(result, m_tasks) = fromStringList(map.value(Constants::C_NIMBLEPROJECT_TASKS).toStringList()); - return result == Project::RestoreResult::Ok ? Project::fromMap(map, errorMessage) : result; -} - -QStringList NimbleProject::toStringList(const std::vector<NimbleTask> &tasks) -{ - QStringList result; - for (const NimbleTask &task : tasks) { - result.push_back(task.name); - result.push_back(task.description); - } - return result; -} - -std::tuple<Project::RestoreResult, std::vector<NimbleTask>> NimbleProject::fromStringList(const QStringList &list) -{ - if (list.size() % 2 != 0) - return std::make_tuple(Project::RestoreResult::Error, std::vector<NimbleTask>()); - - std::vector<NimbleTask> result; - for (int i = 0; i < list.size(); i += 2) - result.push_back({list[i], list[i + 1]}); - return std::make_tuple(Project::RestoreResult::Ok, result); -} diff --git a/src/plugins/nim/project/nimbleproject.h b/src/plugins/nim/project/nimbleproject.h index e3c7cf9358d..5ace87a47f8 100644 --- a/src/plugins/nim/project/nimbleproject.h +++ b/src/plugins/nim/project/nimbleproject.h @@ -25,64 +25,17 @@ #pragma once +#include <projectexplorer/buildsystem.h> #include <projectexplorer/project.h> namespace Nim { -struct NimbleTask -{ - QString name; - QString description; - - bool operator==(const NimbleTask &o) const { - return name == o.name && description == o.description; - } -}; - -struct NimbleMetadata -{ - QStringList bin; - QString binDir; - QString srcDir; - - bool operator==(const NimbleMetadata &o) const { - return bin == o.bin && binDir == o.binDir && srcDir == o.srcDir; - } -}; - class NimbleProject : public ProjectExplorer::Project { Q_OBJECT public: NimbleProject(const Utils::FilePath &filename); - - std::vector<NimbleTask> tasks() const; - - NimbleMetadata metadata() const; - - void setTasks(std::vector<NimbleTask> tasks); - - void setMetadata(NimbleMetadata metadata); - - // Keep for compatibility with Qt Creator 4.10 - QVariantMap toMap() const final; - -signals: - void tasksChanged(std::vector<NimbleTask>); - void metadataChanged(NimbleMetadata); - -protected: - // Keep for compatibility with Qt Creator 4.10 - RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; - -private: - static QStringList toStringList(const std::vector<NimbleTask> &tasks); - - static std::tuple<RestoreResult, std::vector<NimbleTask>> fromStringList(const QStringList &list); - - NimbleMetadata m_metadata; - std::vector<NimbleTask> m_tasks; }; } diff --git a/src/plugins/nim/project/nimblerunconfiguration.cpp b/src/plugins/nim/project/nimblerunconfiguration.cpp index 867f22469ba..b9f80152387 100644 --- a/src/plugins/nim/project/nimblerunconfiguration.cpp +++ b/src/plugins/nim/project/nimblerunconfiguration.cpp @@ -43,20 +43,15 @@ using namespace ProjectExplorer; NimbleRunConfiguration::NimbleRunConfiguration(ProjectExplorer::Target *target, Core::Id id) : RunConfiguration(target, id) { - auto project = dynamic_cast<NimbleProject*>(target->project()); - QTC_ASSERT(project, return); - addAspect<LocalEnvironmentAspect>(target); addAspect<ExecutableAspect>(); addAspect<ArgumentsAspect>(); addAspect<WorkingDirectoryAspect>(); addAspect<TerminalAspect>(); - connect(project, &Project::parsingFinished, - this, &NimbleRunConfiguration::updateTargetInformation); - connect(project, &NimbleProject::metadataChanged, + connect(target, &Target::parsingFinished, this, &NimbleRunConfiguration::updateTargetInformation); - connect(project, &NimbleProject::tasksChanged, + connect(target, &Target::targetPropertiesChanged, this, &NimbleRunConfiguration::updateTargetInformation); updateTargetInformation(); @@ -85,14 +80,6 @@ QString NimbleRunConfiguration::disabledReason() const return RunConfiguration::disabledReason(); } -void NimbleRunConfiguration::updateEnabledState() -{ - if (!isBuildTargetValid()) - setEnabled(false); - else - RunConfiguration::updateEnabledState(); -} - NimbleRunConfigurationFactory::NimbleRunConfigurationFactory() : RunConfigurationFactory() { diff --git a/src/plugins/nim/project/nimblerunconfiguration.h b/src/plugins/nim/project/nimblerunconfiguration.h index 8e370d32cc4..1daa5e22845 100644 --- a/src/plugins/nim/project/nimblerunconfiguration.h +++ b/src/plugins/nim/project/nimblerunconfiguration.h @@ -38,9 +38,6 @@ public: QString disabledReason() const override; -protected: - void updateEnabledState() override; - private: void updateTargetInformation(); diff --git a/src/plugins/nim/project/nimbletaskstep.cpp b/src/plugins/nim/project/nimbletaskstep.cpp index 8a6ce49de9e..0608be59154 100644 --- a/src/plugins/nim/project/nimbletaskstep.cpp +++ b/src/plugins/nim/project/nimbletaskstep.cpp @@ -104,10 +104,10 @@ bool NimbleTaskStep::validate() if (m_taskName.isEmpty()) return true; - auto nimbleProject = dynamic_cast<NimbleProject*>(project()); - QTC_ASSERT(nimbleProject, return false); + auto nimbleBuildSystem = dynamic_cast<NimbleBuildSystem*>(buildSystem()); + QTC_ASSERT(nimbleBuildSystem, return false); - if (!Utils::contains(nimbleProject->tasks(), [this](const NimbleTask &task){ return task.name == m_taskName; })) { + if (!Utils::contains(nimbleBuildSystem->tasks(), [this](const NimbleTask &task){ return task.name == m_taskName; })) { emit addTask(Task(Task::Error, tr("Nimble task %1 not found").arg(m_taskName), Utils::FilePath(), -1, diff --git a/src/plugins/nim/project/nimbletaskstepwidget.cpp b/src/plugins/nim/project/nimbletaskstepwidget.cpp index 6d33fdcbe61..0b44cddc9a6 100644 --- a/src/plugins/nim/project/nimbletaskstepwidget.cpp +++ b/src/plugins/nim/project/nimbletaskstepwidget.cpp @@ -40,14 +40,14 @@ NimbleTaskStepWidget::NimbleTaskStepWidget(NimbleTaskStep *bs) { ui->setupUi(this); - auto project = dynamic_cast<NimbleProject*>(bs->project()); - QTC_ASSERT(project, return); + auto buildSystem = dynamic_cast<NimbleBuildSystem *>(bs->buildSystem()); + QTC_ASSERT(buildSystem, return); ui->taskList->setModel(&m_tasks); QObject::connect(&m_tasks, &QAbstractItemModel::dataChanged, this, &NimbleTaskStepWidget::onDataChanged); - updateTaskList(project->tasks()); - QObject::connect(project, &NimbleProject::tasksChanged, this, &NimbleTaskStepWidget::updateTaskList); + updateTaskList(); + QObject::connect(buildSystem, &NimbleBuildSystem::tasksChanged, this, &NimbleTaskStepWidget::updateTaskList); selectTask(bs->taskName()); QObject::connect(bs, &NimbleTaskStep::taskNameChanged, this, &NimbleTaskStepWidget::selectTask); @@ -73,8 +73,12 @@ NimbleTaskStepWidget::~NimbleTaskStepWidget() delete ui; } -void NimbleTaskStepWidget::updateTaskList(const std::vector<NimbleTask> &tasks) +void NimbleTaskStepWidget::updateTaskList() { + auto buildSystem = dynamic_cast<NimbleBuildSystem *>(step()->buildSystem()); + QTC_ASSERT(buildSystem, return); + const std::vector<NimbleTask> &tasks = buildSystem->tasks(); + QSet<QString> newTasks; for (const NimbleTask &t : tasks) newTasks.insert(t.name); diff --git a/src/plugins/nim/project/nimbletaskstepwidget.h b/src/plugins/nim/project/nimbletaskstepwidget.h index 73e15dcd05f..a8eed556187 100644 --- a/src/plugins/nim/project/nimbletaskstepwidget.h +++ b/src/plugins/nim/project/nimbletaskstepwidget.h @@ -28,6 +28,7 @@ #include <projectexplorer/buildstep.h> #include <nim/project/nimbleproject.h> +#include <nim/project/nimblebuildsystem.h> #include <QStandardItemModel> @@ -50,7 +51,7 @@ signals: void selectedTaskChanged(const QString &name); private: - void updateTaskList(const std::vector<NimbleTask> &tasks); + void updateTaskList(); void selectTask(const QString &name); diff --git a/src/plugins/nim/project/nimbuildconfiguration.cpp b/src/plugins/nim/project/nimbuildconfiguration.cpp index c6c745f9e65..e082f2e7e9a 100644 --- a/src/plugins/nim/project/nimbuildconfiguration.cpp +++ b/src/plugins/nim/project/nimbuildconfiguration.cpp @@ -78,7 +78,7 @@ void NimBuildConfiguration::initialize() { BuildConfiguration::initialize(); - auto bs = qobject_cast<NimBuildSystem *>(project()->buildSystem()); + auto bs = qobject_cast<NimBuildSystem *>(buildSystem()); QTC_ASSERT(bs, return ); // Create the build configuration and initialize it from build info diff --git a/src/plugins/nim/project/nimbuildsystem.cpp b/src/plugins/nim/project/nimbuildsystem.cpp index 2c7d97041fb..f342a742c8c 100644 --- a/src/plugins/nim/project/nimbuildsystem.cpp +++ b/src/plugins/nim/project/nimbuildsystem.cpp @@ -25,9 +25,12 @@ #include "nimbuildsystem.h" +#include "nimproject.h" #include "nimbleproject.h" #include "nimprojectnode.h" +#include <projectexplorer/target.h> + #include <utils/algorithm.h> #include <utils/fileutils.h> #include <utils/qtcassert.h> @@ -42,11 +45,11 @@ namespace Nim { const char SETTINGS_KEY[] = "Nim.BuildSystem"; const char EXCLUDED_FILES_KEY[] = "ExcludedFiles"; -NimBuildSystem::NimBuildSystem(Project *project) - : BuildSystem(project) +NimBuildSystem::NimBuildSystem(Target *target) + : BuildSystem(target) { - connect(project, &Project::settingsLoaded, this, &NimBuildSystem::loadSettings); - connect(project, &Project::aboutToSaveSettings, this, &NimBuildSystem::saveSettings); + connect(target->project(), &Project::settingsLoaded, this, &NimBuildSystem::loadSettings); + connect(target->project(), &Project::aboutToSaveSettings, this, &NimBuildSystem::saveSettings); connect(&m_scanner, &TreeScanner::finished, this, &NimBuildSystem::updateProject); m_scanner.setFilter([this](const Utils::MimeType &, const Utils::FilePath &fp) { @@ -64,17 +67,16 @@ NimBuildSystem::NimBuildSystem(Project *project) bool NimBuildSystem::addFiles(const QStringList &filePaths) { - m_excludedFiles = Utils::filtered(m_excludedFiles, [&](const QString & f) { + setExcludedFiles(Utils::filtered(excludedFiles(), [&](const QString & f) { return !filePaths.contains(f); - }); + })); requestParse(); return true; } bool NimBuildSystem::removeFiles(const QStringList &filePaths) { - m_excludedFiles.append(filePaths); - m_excludedFiles = Utils::filteredUnique(m_excludedFiles); + setExcludedFiles(Utils::filteredUnique(excludedFiles() + filePaths)); requestParse(); return true; } @@ -82,27 +84,27 @@ bool NimBuildSystem::removeFiles(const QStringList &filePaths) bool NimBuildSystem::renameFile(const QString &filePath, const QString &newFilePath) { Q_UNUSED(filePath) - m_excludedFiles.removeOne(newFilePath); + QStringList files = excludedFiles(); + files.removeOne(newFilePath); + setExcludedFiles(files); requestParse(); return true; } void NimBuildSystem::setExcludedFiles(const QStringList &list) { - m_excludedFiles = list; + static_cast<NimProject *>(project())->setExcludedFiles(list); } QStringList NimBuildSystem::excludedFiles() { - return m_excludedFiles; + return static_cast<NimProject *>(project())->excludedFiles(); } -void NimBuildSystem::parseProject(BuildSystem::ParsingContext &&ctx) +void NimBuildSystem::triggerParsing() { - QTC_ASSERT(!m_currentContext.project, return ); - m_currentContext = std::move(ctx); - QTC_CHECK(m_currentContext.project); - m_scanner.asyncScanForFiles(m_currentContext.project->projectDirectory()); + m_guard = guardParsingRun(); + m_scanner.asyncScanForFiles(projectDirectory()); } const FilePathList NimBuildSystem::nimFiles() const @@ -116,7 +118,7 @@ void NimBuildSystem::loadSettings() { QVariantMap settings = project()->namedSettings(SETTINGS_KEY).toMap(); if (settings.contains(EXCLUDED_FILES_KEY)) - m_excludedFiles = settings.value(EXCLUDED_FILES_KEY, m_excludedFiles).toStringList(); + setExcludedFiles(settings.value(EXCLUDED_FILES_KEY, excludedFiles()).toStringList()); requestParse(); } @@ -124,7 +126,7 @@ void NimBuildSystem::loadSettings() void NimBuildSystem::saveSettings() { QVariantMap settings; - settings.insert(EXCLUDED_FILES_KEY, m_excludedFiles); + settings.insert(EXCLUDED_FILES_KEY, excludedFiles()); project()->setNamedSettings(SETTINGS_KEY, settings); } @@ -156,8 +158,8 @@ void NimBuildSystem::updateProject() } // Complete scan - m_currentContext.guard.markAsSuccess(); - m_currentContext = {}; + m_guard.markAsSuccess(); + m_guard = {}; // Trigger destructor of previous object, emitting parsingFinished() } bool NimBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const diff --git a/src/plugins/nim/project/nimbuildsystem.h b/src/plugins/nim/project/nimbuildsystem.h index 686bab3aca9..9ea9a337c4c 100644 --- a/src/plugins/nim/project/nimbuildsystem.h +++ b/src/plugins/nim/project/nimbuildsystem.h @@ -37,7 +37,7 @@ class NimBuildSystem : public ProjectExplorer::BuildSystem Q_OBJECT public: - explicit NimBuildSystem(ProjectExplorer::Project *project); + explicit NimBuildSystem(ProjectExplorer::Target *target); bool addFiles(const QStringList &filePaths); bool removeFiles(const QStringList &filePaths); @@ -58,22 +58,20 @@ public: void setExcludedFiles(const QStringList &list); // Keep for compatibility with Qt Creator 4.10 QStringList excludedFiles(); // Make private when no longer supporting Qt Creator 4.10 - void parseProject(ParsingContext &&ctx) override; + void triggerParsing(); const Utils::FilePathList nimFiles() const; protected: - void loadSettings(); - void saveSettings(); + virtual void loadSettings(); + virtual void saveSettings(); void collectProjectFiles(); void updateProject(); - QStringList m_excludedFiles; - ProjectExplorer::TreeScanner m_scanner; - ParsingContext m_currentContext; + ParseGuard m_guard; Utils::FileSystemWatcher m_directoryWatcher; }; diff --git a/src/plugins/nim/project/nimcompilerbuildstep.cpp b/src/plugins/nim/project/nimcompilerbuildstep.cpp index d9cd7599b2c..389d6b80d20 100644 --- a/src/plugins/nim/project/nimcompilerbuildstep.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstep.cpp @@ -271,8 +271,8 @@ void NimCompilerBuildStep::updateTargetNimFile() { if (!m_targetNimFile.isEmpty()) return; - const Utils::FilePathList nimFiles = static_cast<NimBuildSystem *>(project()->buildSystem()) - ->nimFiles(); + const Utils::FilePathList nimFiles = + static_cast<NimBuildSystem *>(buildConfiguration()->buildSystem())->nimFiles(); if (!nimFiles.isEmpty()) setTargetNimFile(nimFiles.at(0)); } diff --git a/src/plugins/nim/project/nimcompilerbuildstepconfigwidget.cpp b/src/plugins/nim/project/nimcompilerbuildstepconfigwidget.cpp index 01e9e23ca6b..1e69022628d 100644 --- a/src/plugins/nim/project/nimcompilerbuildstepconfigwidget.cpp +++ b/src/plugins/nim/project/nimcompilerbuildstepconfigwidget.cpp @@ -116,7 +116,7 @@ void NimCompilerBuildStepConfigWidget::updateTargetComboBox() { QTC_ASSERT(m_buildStep, return ); - const auto bs = qobject_cast<NimBuildSystem *>(m_buildStep->project()->buildSystem()); + const auto bs = qobject_cast<NimBuildSystem *>(m_buildStep->buildConfiguration()->buildSystem()); QTC_ASSERT(bs, return ); // Re enter the files diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 7fb17f2c366..1c17b250c16 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -45,7 +45,7 @@ NimProject::NimProject(const FilePath &fileName) : Project(Constants::C_NIM_MIME // ensure debugging is enabled (Nim plugin translates nim code to C code) setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); - setBuildSystemCreator([](Project *p) { return new NimBuildSystem(p); }); + setBuildSystemCreator([](Target *t) { return new NimBuildSystem(t); }); } Tasks NimProject::projectIssues(const Kit *k) const @@ -65,17 +65,25 @@ Tasks NimProject::projectIssues(const Kit *k) const QVariantMap NimProject::toMap() const { QVariantMap result = Project::toMap(); - result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = static_cast<NimBuildSystem *>(buildSystem()) - ->excludedFiles(); + result[Constants::C_NIMPROJECT_EXCLUDEDFILES] = m_excludedFiles; return result; } Project::RestoreResult NimProject::fromMap(const QVariantMap &map, QString *errorMessage) { auto result = Project::fromMap(map, errorMessage); - static_cast<NimBuildSystem *>(buildSystem()) - ->setExcludedFiles(map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList()); + m_excludedFiles = map.value(Constants::C_NIMPROJECT_EXCLUDEDFILES).toStringList(); return result; } +QStringList NimProject::excludedFiles() const +{ + return m_excludedFiles; +} + +void NimProject::setExcludedFiles(const QStringList &excludedFiles) +{ + m_excludedFiles = excludedFiles; +} + } // namespace Nim diff --git a/src/plugins/nim/project/nimproject.h b/src/plugins/nim/project/nimproject.h index afe33cf9403..540d2129bba 100644 --- a/src/plugins/nim/project/nimproject.h +++ b/src/plugins/nim/project/nimproject.h @@ -48,9 +48,14 @@ public: // Keep for compatibility with Qt Creator 4.10 QVariantMap toMap() const final; + QStringList excludedFiles() const; + void setExcludedFiles(const QStringList &excludedFiles); + protected: // Keep for compatibility with Qt Creator 4.10 RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; + + QStringList m_excludedFiles; }; } // namespace Nim diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index d1e6225b980..b312e0fb7ea 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -28,6 +28,8 @@ #include "buildenvironmentwidget.h" #include "buildinfo.h" #include "buildsteplist.h" +#include "buildstepspage.h" +#include "buildsystem.h" #include "namedwidget.h" #include "kit.h" #include "kitinformation.h" @@ -89,6 +91,7 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) : ProjectConfiguration(target, id), d(new Internal::BuildConfigurationPrivate) { QTC_CHECK(target && target == this->target()); + Utils::MacroExpander *expander = macroExpander(); expander->setDisplayName(tr("Build Settings")); expander->setAccumulating(true); @@ -128,8 +131,8 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) this->target()->buildEnvironmentChanged(this); }); - connect(project(), &Project::parsingStarted, this, &BuildConfiguration::enabledChanged); - connect(project(), &Project::parsingFinished, this, &BuildConfiguration::enabledChanged); + connect(target, &Target::parsingStarted, this, &BuildConfiguration::enabledChanged); + connect(target, &Target::parsingFinished, this, &BuildConfiguration::enabledChanged); connect(this, &BuildConfiguration::enabledChanged, this, [this] { if (isActive() && project() == SessionManager::startupProject()) { @@ -164,6 +167,19 @@ void BuildConfiguration::setBuildDirectory(const Utils::FilePath &dir) emitBuildDirectoryChanged(); } +void BuildConfiguration::addConfigWidgets(const std::function<void(NamedWidget *)> &adder) +{ + if (NamedWidget *generalConfigWidget = createConfigWidget()) + adder(generalConfigWidget); + + adder(new Internal::BuildStepListWidget(stepList(Constants::BUILDSTEPS_BUILD))); + adder(new Internal::BuildStepListWidget(stepList(Constants::BUILDSTEPS_CLEAN))); + + QList<NamedWidget *> subConfigWidgets = createSubConfigWidgets(); + foreach (NamedWidget *subConfigWidget, subConfigWidgets) + adder(subConfigWidget); +} + NamedWidget *BuildConfiguration::createConfigWidget() { NamedWidget *named = new NamedWidget(d->m_configWidgetDisplayName); @@ -203,6 +219,12 @@ QList<NamedWidget *> BuildConfiguration::createSubConfigWidgets() return {new BuildEnvironmentWidget(this)}; } +BuildSystem *BuildConfiguration::buildSystem() const +{ + QTC_CHECK(target()->fallbackBuildSystem()); + return target()->fallbackBuildSystem(); +} + QList<Core::Id> BuildConfiguration::knownStepLists() const { return Utils::transform(d->m_stepLists, &BuildStepList::id); @@ -368,14 +390,14 @@ void BuildConfiguration::setUserEnvironmentChanges(const Utils::EnvironmentItems bool BuildConfiguration::isEnabled() const { - return !project()->isParsing() && project()->hasParsingData(); + return !buildSystem()->isParsing() && buildSystem()->hasParsingData(); } QString BuildConfiguration::disabledReason() const { - if (project()->isParsing()) + if (buildSystem()->isParsing()) return (tr("The project is currently being parsed.")); - if (!project()->hasParsingData()) + if (!buildSystem()->hasParsingData()) return (tr("The project was not parsed successfully.")); return QString(); } diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h index 6160e3b6a4a..2a57fb58589 100644 --- a/src/plugins/projectexplorer/buildconfiguration.h +++ b/src/plugins/projectexplorer/buildconfiguration.h @@ -38,6 +38,7 @@ namespace Internal { class BuildConfigurationPrivate; } class BaseStringAspect; class BuildInfo; +class BuildSystem; class BuildStepList; class Kit; class NamedWidget; @@ -59,6 +60,8 @@ public: Utils::FilePath rawBuildDirectory() const; void setBuildDirectory(const Utils::FilePath &dir); + virtual BuildSystem *buildSystem() const; + virtual NamedWidget *createConfigWidget(); virtual QList<NamedWidget *> createSubConfigWidgets(); @@ -110,6 +113,8 @@ public: void setConfigWidgetHasFrame(bool configWidgetHasFrame); void setBuildDirectorySettingsKey(const QString &key); + void addConfigWidgets(const std::function<void (NamedWidget *)> &adder); + signals: void environmentChanged(); void buildDirectoryChanged(); diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index 468d4751ac9..f5d33a7b4e7 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -139,6 +139,7 @@ BuildSettingsWidget::BuildSettingsWidget(Target *target) : void BuildSettingsWidget::addSubWidget(NamedWidget *widget) { + widget->setParent(this); widget->setContentsMargins(0, 10, 0, 0); auto label = new QLabel(this); @@ -192,23 +193,8 @@ void BuildSettingsWidget::updateBuildSettings() m_renameButton->setEnabled(!bcs.isEmpty()); m_cloneButton->setEnabled(!bcs.isEmpty()); - if (!m_buildConfiguration) - return; - - // Add pages - NamedWidget *generalConfigWidget = m_buildConfiguration->createConfigWidget(); - if (generalConfigWidget) - addSubWidget(generalConfigWidget); - - BuildStepList *buildSteps = m_buildConfiguration->stepList(Constants::BUILDSTEPS_BUILD); - addSubWidget(new BuildStepListWidget(buildSteps, this)); - - BuildStepList *cleanSteps = m_buildConfiguration->stepList(Constants::BUILDSTEPS_CLEAN); - addSubWidget(new BuildStepListWidget(cleanSteps, this)); - - QList<NamedWidget *> subConfigWidgets = m_buildConfiguration->createSubConfigWidgets(); - foreach (NamedWidget *subConfigWidget, subConfigWidgets) - addSubWidget(subConfigWidget); + if (m_buildConfiguration) + m_buildConfiguration->addConfigWidgets([this](NamedWidget *w) { addSubWidget(w); }); } void BuildSettingsWidget::currentIndexChanged(int index) diff --git a/src/plugins/projectexplorer/buildstep.cpp b/src/plugins/projectexplorer/buildstep.cpp index fb8c1f3848a..ba0bfa221a3 100644 --- a/src/plugins/projectexplorer/buildstep.cpp +++ b/src/plugins/projectexplorer/buildstep.cpp @@ -204,6 +204,13 @@ ProjectConfiguration *BuildStep::projectConfiguration() const return static_cast<ProjectConfiguration *>(parent()->parent()); } +BuildSystem *BuildStep::buildSystem() const +{ + if (auto bc = buildConfiguration()) + return bc->buildSystem(); + return target()->buildSystem(); +} + void BuildStep::reportRunResult(QFutureInterface<bool> &fi, bool success) { fi.reportResult(success); diff --git a/src/plugins/projectexplorer/buildstep.h b/src/plugins/projectexplorer/buildstep.h index f9fb6fbec68..0c9a85e9b3c 100644 --- a/src/plugins/projectexplorer/buildstep.h +++ b/src/plugins/projectexplorer/buildstep.h @@ -44,6 +44,7 @@ class BuildConfiguration; class BuildStepConfigWidget; class BuildStepFactory; class BuildStepList; +class BuildSystem; class DeployConfiguration; class Target; class Task; @@ -75,6 +76,8 @@ public: DeployConfiguration *deployConfiguration() const; ProjectConfiguration *projectConfiguration() const; + BuildSystem *buildSystem() const; + enum class OutputFormat { Stdout, Stderr, // These are for forwarded output from external tools NormalMessage, ErrorMessage // These are for messages from Creator itself diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index 76fadceb68d..ea795fec1a7 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -191,9 +191,9 @@ BuildStepsWidgetData::~BuildStepsWidgetData() // We do not own the step } -BuildStepListWidget::BuildStepListWidget(BuildStepList *bsl, QWidget *parent) +BuildStepListWidget::BuildStepListWidget(BuildStepList *bsl) //: %1 is the name returned by BuildStepList::displayName - : NamedWidget(tr("%1 Steps").arg(bsl->displayName()), parent), m_buildStepList(bsl) + : NamedWidget(tr("%1 Steps").arg(bsl->displayName())), m_buildStepList(bsl) { setupUi(); diff --git a/src/plugins/projectexplorer/buildstepspage.h b/src/plugins/projectexplorer/buildstepspage.h index 7eade2d663e..9fef567a1f7 100644 --- a/src/plugins/projectexplorer/buildstepspage.h +++ b/src/plugins/projectexplorer/buildstepspage.h @@ -97,7 +97,7 @@ class BuildStepListWidget : public NamedWidget Q_OBJECT public: - BuildStepListWidget(BuildStepList *bsl, QWidget *parent = nullptr); + explicit BuildStepListWidget(BuildStepList *bsl); ~BuildStepListWidget() override; private: diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 496f9cc9f48..e6e6ad9677d 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -26,10 +26,14 @@ #include "buildsystem.h" #include "buildconfiguration.h" +#include "runconfiguration.h" +#include "runcontrol.h" #include "target.h" #include <utils/qtcassert.h> +#include <QTimer> + using namespace Utils; namespace ProjectExplorer { @@ -38,77 +42,129 @@ namespace ProjectExplorer { // BuildSystem: // -------------------------------------------------------------------- -BuildSystem::BuildSystem(Project *project) - : m_project(project) +class BuildSystemPrivate +{ +public: + Target *m_target = nullptr; + BuildConfiguration *m_buildConfiguration = nullptr; + + QTimer m_delayedParsingTimer; + + bool m_isParsing = false; + bool m_hasParsingData = false; + + DeploymentData m_deploymentData; + QList<BuildTargetInfo> m_appTargets; +}; + +BuildSystem::BuildSystem(BuildConfiguration *bc) + : BuildSystem(bc->target()) +{ + d->m_buildConfiguration = bc; +} + +BuildSystem::BuildSystem(Target *target) + : d(new BuildSystemPrivate) { - QTC_CHECK(project); + QTC_CHECK(target); + d->m_target = target; // Timer: - m_delayedParsingTimer.setSingleShot(true); + d->m_delayedParsingTimer.setSingleShot(true); - connect(&m_delayedParsingTimer, &QTimer::timeout, this, &BuildSystem::triggerParsing); + connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, &BuildSystem::triggerParsing); +} + +BuildSystem::~BuildSystem() +{ + delete d; } Project *BuildSystem::project() const { - return m_project; + return d->m_target->project(); +} + +Target *BuildSystem::target() const +{ + return d->m_target; +} + +void BuildSystem::emitParsingStarted() +{ + QTC_ASSERT(!d->m_isParsing, return); + + d->m_isParsing = true; + d->m_hasParsingData = false; + emit d->m_target->parsingStarted(); +} + +void BuildSystem::emitParsingFinished(bool success) +{ + // Intentionally no return, as we currently get start - start - end - end + // sequences when switching qmake targets quickly. + QTC_CHECK(d->m_isParsing); + + d->m_isParsing = false; + d->m_hasParsingData = success; + emit d->m_target->parsingFinished(success); } FilePath BuildSystem::projectFilePath() const { - return m_project->projectFilePath(); + return d->m_target->project()->projectFilePath(); } FilePath BuildSystem::projectDirectory() const { - return m_project->projectDirectory(); + return d->m_target->project()->projectDirectory(); } bool BuildSystem::isWaitingForParse() const { - return m_delayedParsingTimer.isActive(); + return d->m_delayedParsingTimer.isActive(); } void BuildSystem::requestParse() { - requestParse(0); + requestParseHelper(0); } void BuildSystem::requestDelayedParse() { - requestParse(1000); + requestParseHelper(1000); } -void BuildSystem::requestParse(int delay) +bool BuildSystem::isParsing() const { - m_delayedParsingTimer.setInterval(delay); - m_delayedParsingTimer.start(); + return d->m_isParsing; } -void BuildSystem::triggerParsing() +bool BuildSystem::hasParsingData() const { - QTC_ASSERT(!project()->isParsing(), return ); - - Project *p = project(); - Target *t = p->activeTarget(); - BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr; + return d->m_hasParsingData; +} - MacroExpander *e = nullptr; +Environment BuildSystem::activeParseEnvironment() const +{ + const BuildConfiguration *const bc = d->m_target->activeBuildConfiguration(); if (bc) - e = bc->macroExpander(); - else if (t) - e = t->macroExpander(); - else - e = p->macroExpander(); + return bc->environment(); - Utils::Environment env = p->activeParseEnvironment(); + const RunConfiguration *const rc = d->m_target->activeRunConfiguration(); + if (rc) + return rc->runnable().environment; - ParsingContext ctx(p->guardParsingRun(), p, bc, e, env); + Environment result = Utils::Environment::systemEnvironment(); + d->m_target->kit()->addToEnvironment(result); - QTC_ASSERT(ctx.guard.guardsProject(), return ); + return result; +} - if (validateParsingContext(ctx)) - parseProject(std::move(ctx)); +void BuildSystem::requestParseHelper(int delay) +{ + d->m_delayedParsingTimer.setInterval(delay); + d->m_delayedParsingTimer.start(); } bool BuildSystem::addFiles(Node *, const QStringList &filePaths, QStringList *notAdded) @@ -157,4 +213,103 @@ bool BuildSystem::supportsAction(Node *, ProjectAction, const Node *) const return false; } +QStringList BuildSystem::filesGeneratedFrom(const QString &sourceFile) const +{ + Q_UNUSED(sourceFile) + return {}; +} + +QVariant BuildSystem::additionalData(Core::Id id) const +{ + Q_UNUSED(id) + return {}; +} + +// ParseGuard + +BuildSystem::ParseGuard::ParseGuard(BuildSystem::ParseGuard &&other) + : m_buildSystem{std::move(other.m_buildSystem)} + , m_success{std::move(other.m_success)} +{ + // No need to release this as this is invalid anyway:-) + other.m_buildSystem = nullptr; +} + +BuildSystem::ParseGuard::ParseGuard(BuildSystem *p) + : m_buildSystem(p) +{ + if (m_buildSystem && !m_buildSystem->isParsing()) + m_buildSystem->emitParsingStarted(); + else + m_buildSystem = nullptr; +} + +void BuildSystem::ParseGuard::release() +{ + if (m_buildSystem) + m_buildSystem->emitParsingFinished(m_success); + m_buildSystem = nullptr; +} + +BuildSystem::ParseGuard &BuildSystem::ParseGuard::operator=(BuildSystem::ParseGuard &&other) +{ + release(); + + m_buildSystem = std::move(other.m_buildSystem); + m_success = std::move(other.m_success); + + other.m_buildSystem = nullptr; + return *this; +} + +void BuildSystem::setDeploymentData(const DeploymentData &deploymentData) +{ + if (d->m_deploymentData != deploymentData) { + d->m_deploymentData = deploymentData; + emit deploymentDataChanged(); + emit applicationTargetsChanged(); + emit target()->deploymentDataChanged(); + emit target()->applicationTargetsChanged(); + } +} + +DeploymentData BuildSystem::deploymentData() const +{ + return d->m_deploymentData; +} + +void BuildSystem::setApplicationTargets(const QList<BuildTargetInfo> &appTargets) +{ + if (Utils::toSet(appTargets) != Utils::toSet(d->m_appTargets)) { + d->m_appTargets = appTargets; + emit applicationTargetsChanged(); + emit target()->applicationTargetsChanged(); + } +} + +const QList<BuildTargetInfo> BuildSystem::applicationTargets() const +{ + return d->m_appTargets; +} + +BuildTargetInfo BuildSystem::buildTarget(const QString &buildKey) const +{ + return Utils::findOrDefault(d->m_appTargets, [&buildKey](const BuildTargetInfo &ti) { + return ti.buildKey == buildKey; + }); +} + +QString BuildSystem::disabledReason(const QString &buildKey) const +{ + if (hasParsingData()) { + QString msg = isParsing() ? tr("The project is currently being parsed.") + : tr("The project could not be fully parsed."); + const FilePath projectFilePath = buildTarget(buildKey).projectFilePath; + if (!projectFilePath.isEmpty() && !projectFilePath.exists()) + msg += '\n' + tr("The project file \"%1\" does not exist.").arg(projectFilePath.toString()); + return msg; + } + return {}; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index 9bd5de66390..b73b459b7b1 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -27,15 +27,15 @@ #include "projectexplorer_export.h" +#include "buildtargetinfo.h" #include "project.h" #include "treescanner.h" -#include <QTimer> +#include <QObject> namespace ProjectExplorer { class BuildConfiguration; -class ExtraCompiler; class Node; // -------------------------------------------------------------------- @@ -47,11 +47,13 @@ class PROJECTEXPLORER_EXPORT BuildSystem : public QObject Q_OBJECT public: - explicit BuildSystem(Project *project); - - BuildSystem(const BuildSystem &other) = delete; + explicit BuildSystem(Target *target); + explicit BuildSystem(BuildConfiguration *bc); + ~BuildSystem() override; Project *project() const; + Target *target() const; + Utils::FilePath projectFilePath() const; Utils::FilePath projectDirectory() const; @@ -60,6 +62,11 @@ public: void requestParse(); void requestDelayedParse(); + bool isParsing() const; + bool hasParsingData() const; + + Utils::Environment activeParseEnvironment() const; + virtual bool addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded = nullptr); virtual RemovedFilesFromProject removeFiles(Node *context, const QStringList &filePaths, QStringList *notRemoved = nullptr); @@ -69,69 +76,64 @@ public: virtual bool addDependencies(Node *context, const QStringList &dependencies); virtual bool supportsAction(Node *context, ProjectAction action, const Node *node) const; -protected: - class ParsingContext + virtual QStringList filesGeneratedFrom(const QString &sourceFile) const; + virtual QVariant additionalData(Core::Id id) const; + + void setDeploymentData(const DeploymentData &deploymentData); + DeploymentData deploymentData() const; + + void setApplicationTargets(const QList<BuildTargetInfo> &appTargets); + const QList<BuildTargetInfo> applicationTargets() const; + BuildTargetInfo buildTarget(const QString &buildKey) const; + + class ParseGuard { + friend class BuildSystem; + explicit ParseGuard(BuildSystem *p); + + void release(); + public: - ParsingContext() = default; - - ParsingContext(const ParsingContext &other) = delete; - ParsingContext &operator=(const ParsingContext &other) = delete; - ParsingContext(ParsingContext &&other) - : guard{std::move(other.guard)} - , project{std::move(other.project)} - , buildConfiguration{std::move(other.buildConfiguration)} - , expander{std::move(other.expander)} - , environment{std::move(other.environment)} - {} - ParsingContext &operator=(ParsingContext &&other) - { - guard = std::move(other.guard); - project = std::move(other.project); - buildConfiguration = std::move(other.buildConfiguration); - expander = std::move(other.expander); - environment = std::move(other.environment); - return *this; - } - - Project::ParseGuard guard; - - Project *project = nullptr; - BuildConfiguration *buildConfiguration = nullptr; - Utils::MacroExpander *expander = nullptr; - Utils::Environment environment; + ParseGuard() = default; + ~ParseGuard() { release(); } - private: - ParsingContext(Project::ParseGuard &&g, - Project *p, - BuildConfiguration *bc, - Utils::MacroExpander *e, - Utils::Environment &env) - : guard(std::move(g)) - , project(p) - , buildConfiguration(bc) - , expander(e) - , environment(env) - {} + void markAsSuccess() const { m_success = true; } + bool isSuccess() const { return m_success; } + bool guardsProject() const { return m_buildSystem; } - friend class BuildSystem; + ParseGuard(const ParseGuard &other) = delete; + ParseGuard &operator=(const ParseGuard &other) = delete; + ParseGuard(ParseGuard &&other); + ParseGuard &operator=(ParseGuard &&other); + + private: + BuildSystem *m_buildSystem = nullptr; + mutable bool m_success = false; }; - virtual bool validateParsingContext(const ParsingContext &ctx) - { - Q_UNUSED(ctx) - return true; - } +public: + // FIXME: Make this private and the BuildSystem a friend + ParseGuard guardParsingRun() { return ParseGuard(this); } - virtual void parseProject(ParsingContext &&) {} // actual code to parse project + QString disabledReason(const QString &buildKey) const; -private: - void requestParse(int delay); // request a (delayed!) parser run. - void triggerParsing(); + virtual void triggerParsing() = 0; + +signals: + void deploymentDataChanged(); + void applicationTargetsChanged(); - QTimer m_delayedParsingTimer; +protected: + // Helper methods to manage parsing state and signalling + // Call in GUI thread before the actual parsing starts + void emitParsingStarted(); + // Call in GUI thread right after the actual parsing is done + void emitParsingFinished(bool success); + +private: + void requestParseHelper(int delay); // request a (delayed!) parser run. - Project *m_project; + class BuildSystemPrivate *d = nullptr; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index ef198bea92f..62ba2eace55 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -246,6 +246,11 @@ bool CustomExecutableRunConfiguration::isConfigured() const return !rawExecutable().isEmpty(); } +bool CustomExecutableRunConfiguration::isEnabled() const +{ + return true; +} + Runnable CustomExecutableRunConfiguration::runnable() const { FilePath workingDirectory = diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.h b/src/plugins/projectexplorer/customexecutablerunconfiguration.h index 6abd0f3185e..bcd7b3b9bae 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.h +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.h @@ -45,6 +45,7 @@ public: /** Returns whether this runconfiguration ever was configured with an executable */ bool isConfigured() const override; + bool isEnabled() const override; ConfigurationState ensureConfigured(QString *errorMessage) override; QString defaultDisplayName() const; diff --git a/src/plugins/projectexplorer/deploymentdataview.cpp b/src/plugins/projectexplorer/deploymentdataview.cpp index f620cf4a5b5..8796c897db1 100644 --- a/src/plugins/projectexplorer/deploymentdataview.cpp +++ b/src/plugins/projectexplorer/deploymentdataview.cpp @@ -25,9 +25,11 @@ #include "deploymentdataview.h" +#include "buildsystem.h" #include "deploymentdata.h" #include "target.h" +#include <utils/qtcassert.h> #include <utils/treemodel.h> #include <QAbstractTableModel> @@ -78,7 +80,8 @@ DeploymentDataView::DeploymentDataView(Target *target) auto updatModel = [this, target, model, view] { model->clear(); - for (const DeployableFile &file : target->deploymentData().allFiles()) + QTC_ASSERT(target->buildSystem(), return); + for (const DeployableFile &file : target->buildSystem()->deploymentData().allFiles()) model->rootItem()->appendChild(new DeploymentDataItem(file)); QHeaderView *header = view->header(); diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.cpp b/src/plugins/projectexplorer/desktoprunconfiguration.cpp index a3f1f735ac4..616bf19f70d 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.cpp +++ b/src/plugins/projectexplorer/desktoprunconfiguration.cpp @@ -78,7 +78,7 @@ DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Core::Id id, Ki if (kind == Qbs) { - connect(project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, envAspect, &EnvironmentAspect::environmentChanged); connect(target, &Target::deploymentDataChanged, @@ -95,12 +95,15 @@ DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Core::Id id, Ki } - connect(target->project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &DesktopRunConfiguration::updateTargetInformation); } void DesktopRunConfiguration::updateTargetInformation() { + if (!activeBuildSystem()) + return; + BuildTargetInfo bti = buildTargetInfo(); auto terminalAspect = aspect<TerminalAspect>(); @@ -184,28 +187,6 @@ Utils::FilePath DesktopRunConfiguration::executableToRun(const BuildTargetInfo & return appInLocalInstallDir.exists() ? appInLocalInstallDir : appInBuildDir; } -bool DesktopRunConfiguration::isBuildTargetValid() const -{ - return Utils::anyOf(target()->applicationTargets(), [this](const BuildTargetInfo &bti) { - return bti.buildKey == buildKey(); - }); -} - -void DesktopRunConfiguration::updateEnabledState() -{ - if (m_kind == CMake && !isBuildTargetValid()) - setEnabled(false); - else - RunConfiguration::updateEnabledState(); -} - -QString DesktopRunConfiguration::disabledReason() const -{ - if (m_kind == CMake && !isBuildTargetValid()) - return tr("The project no longer builds the target associated with this run configuration."); - return RunConfiguration::disabledReason(); -} - // Factory class DesktopQmakeRunConfiguration : public DesktopRunConfiguration diff --git a/src/plugins/projectexplorer/desktoprunconfiguration.h b/src/plugins/projectexplorer/desktoprunconfiguration.h index 4063337ef1c..065014edf71 100644 --- a/src/plugins/projectexplorer/desktoprunconfiguration.h +++ b/src/plugins/projectexplorer/desktoprunconfiguration.h @@ -43,14 +43,10 @@ protected: private: void doAdditionalSetup(const RunConfigurationCreationInfo &info) final; bool fromMap(const QVariantMap &map) final; - void updateEnabledState() final; void updateTargetInformation(); Utils::FilePath executableToRun(const BuildTargetInfo &targetInfo) const; - QString disabledReason() const override; - - bool isBuildTargetValid() const; const Kind m_kind; }; diff --git a/src/plugins/projectexplorer/makestep.cpp b/src/plugins/projectexplorer/makestep.cpp index 64834f190b1..8358ea4df38 100644 --- a/src/plugins/projectexplorer/makestep.cpp +++ b/src/plugins/projectexplorer/makestep.cpp @@ -443,7 +443,7 @@ MakeStepConfigWidget::MakeStepConfigWidget(MakeStep *makeStep) this, &MakeStepConfigWidget::updateDetails); connect(m_makeStep->buildConfiguration(), &BuildConfiguration::buildDirectoryChanged, this, &MakeStepConfigWidget::updateDetails); - connect(m_makeStep->project(), &Project::parsingFinished, + connect(m_makeStep->target(), &Target::parsingFinished, this, &MakeStepConfigWidget::updateDetails); Core::VariableChooser::addSupportForChildWidgets(this, m_makeStep->macroExpander()); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 2e75cd3caf5..4f084bc7fac 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -176,14 +176,15 @@ public: ~ProjectPrivate(); Core::Id m_id; - bool m_isParsing = false; - bool m_hasParsingData = false; bool m_needsInitialExpansion = false; bool m_canBuildProducts = false; bool m_knowsAllBuildExecutables = true; bool m_hasMakeInstallEquivalent = false; bool m_needsBuildConfigurations = true; - std::unique_ptr<BuildSystem> m_buildSystem; + bool m_needsDeployConfigurations = true; + + std::function<BuildSystem *(Target *)> m_buildSystemCreator; + std::unique_ptr<Core::IDocument> m_document; std::vector<std::unique_ptr<Core::IDocument>> m_extraProjectDocuments; std::unique_ptr<ProjectNode> m_rootProjectNode; @@ -255,9 +256,9 @@ bool Project::canBuildProducts() const return d->m_canBuildProducts; } -BuildSystem *Project::buildSystem() const +BuildSystem *Project::createBuildSystem(Target *target) const { - return d->m_buildSystem.get(); + return d->m_buildSystemCreator ? d->m_buildSystemCreator(target) : nullptr; } Utils::FilePath Project::projectFilePath() const @@ -341,8 +342,6 @@ void Project::setActiveTarget(Target *target) (target && Utils::contains(d->m_targets, target))) { d->m_activeTarget = target; emit activeTargetChanged(d->m_activeTarget); - emit activeBuildConfigurationChanged( - d->m_activeTarget ? d->m_activeTarget->activeBuildConfiguration() : nullptr); } } @@ -506,33 +505,14 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) bool Project::setupTarget(Target *t) { - if (needsBuildConfigurations()) + if (d->m_needsBuildConfigurations) t->updateDefaultBuildConfigurations(); - t->updateDefaultDeployConfigurations(); + if (d->m_needsDeployConfigurations) + t->updateDefaultDeployConfigurations(); t->updateDefaultRunConfigurations(); return true; } -void Project::emitParsingStarted() -{ - QTC_ASSERT(!d->m_isParsing, return); - - d->m_isParsing = true; - d->m_hasParsingData = false; - emit parsingStarted(); -} - -void Project::emitParsingFinished(bool success) -{ - // Intentionally no return, as we currently get start - start - end - end - // sequences when switching qmake targets quickly. - QTC_CHECK(d->m_isParsing); - - d->m_isParsing = false; - d->m_hasParsingData = success; - emit parsingFinished(success); -} - void Project::setDisplayName(const QString &name) { if (name == d->m_displayName) @@ -596,9 +576,6 @@ void Project::saveSettings() Project::RestoreResult Project::restoreSettings(QString *errorMessage) { - BuildConfiguration *oldBc = activeTarget() ? activeTarget()->activeBuildConfiguration() - : nullptr; - if (!d->m_accessor) d->m_accessor = std::make_unique<Internal::UserFileAccessor>(this); QVariantMap map(d->m_accessor->restoreSettings(Core::ICore::mainWindow())); @@ -606,10 +583,6 @@ Project::RestoreResult Project::restoreSettings(QString *errorMessage) if (result == RestoreResult::Ok) emit settingsLoaded(); - BuildConfiguration *bc = activeTarget() ? activeTarget()->activeBuildConfiguration() : nullptr; - if (bc != oldBc) - emit activeBuildConfigurationChanged(bc); - return result; } @@ -798,12 +771,6 @@ EditorConfiguration *Project::editorConfiguration() const return &d->m_editorConfiguration; } -QStringList Project::filesGeneratedFrom(const QString &file) const -{ - Q_UNUSED(file) - return QStringList(); -} - bool Project::isKnownFile(const Utils::FilePath &filename) const { if (d->m_sortedNodeList.empty()) @@ -852,10 +819,6 @@ void Project::setHasMakeInstallEquivalent(bool enabled) d->m_hasMakeInstallEquivalent = enabled; } -void Project::projectLoaded() -{ -} - void Project::setKnowsAllBuildExecutables(bool value) { d->m_knowsAllBuildExecutables = value; @@ -866,31 +829,19 @@ void Project::setNeedsBuildConfigurations(bool value) d->m_needsBuildConfigurations = value; } -Task Project::createProjectTask(Task::TaskType type, const QString &description) +void Project::setNeedsDeployConfigurations(bool value) { - return Task(type, description, Utils::FilePath(), -1, Core::Id()); + d->m_needsDeployConfigurations = value; } -Utils::Environment Project::activeParseEnvironment() const +Task Project::createProjectTask(Task::TaskType type, const QString &description) { - const Target *const t = activeTarget(); - const BuildConfiguration *const bc = t ? t->activeBuildConfiguration() : nullptr; - if (bc) - return bc->environment(); - - const RunConfiguration *const rc = t ? t->activeRunConfiguration() : nullptr; - if (rc) - return rc->runnable().environment; - - Utils::Environment result = Utils::Environment::systemEnvironment(); - if (t) - t->kit()->addToEnvironment(result); - return result; + return Task(type, description, Utils::FilePath(), -1, Core::Id()); } -void Project::setBuildSystemCreator(const std::function<BuildSystem *(Project *)> &creator) +void Project::setBuildSystemCreator(const std::function<BuildSystem *(Target *)> &creator) { - d->m_buildSystem.reset(creator(this)); + d->m_buildSystemCreator = creator; } Core::Context Project::projectContext() const @@ -988,23 +939,6 @@ Utils::MacroExpander *Project::macroExpander() const return &d->m_macroExpander; } -QVariant Project::additionalData(Core::Id id, const Target *target) const -{ - Q_UNUSED(id) - Q_UNUSED(target) - return QVariant(); -} - -bool Project::isParsing() const -{ - return d->m_isParsing; -} - -bool Project::hasParsingData() const -{ - return d->m_hasParsingData; -} - ProjectNode *Project::findNodeForBuildKey(const QString &buildKey) const { if (!d->m_rootProjectNode) @@ -1072,6 +1006,14 @@ const QString TEST_PROJECT_MIMETYPE = "application/vnd.test.qmakeprofile"; const QString TEST_PROJECT_DISPLAYNAME = "testProjectFoo"; const char TEST_PROJECT_ID[] = "Test.Project.Id"; +class TestBuildSystem : public BuildSystem +{ +public: + using BuildSystem::BuildSystem; + + void triggerParsing() {} +}; + class TestProject : public Project { public: @@ -1079,9 +1021,17 @@ public: { setId(TEST_PROJECT_ID); setDisplayName(TEST_PROJECT_DISPLAYNAME); + setBuildSystemCreator([](Target *t) { return new TestBuildSystem(t); }); + setNeedsBuildConfigurations(false); + setNeedsDeployConfigurations(false); + + target = addTargetForKit(&testKit); } bool needsConfiguration() const final { return false; } + + Kit testKit; + Target *target = nullptr; }; void ProjectExplorerPlugin::testProject_setup() @@ -1108,8 +1058,8 @@ void ProjectExplorerPlugin::testProject_setup() QCOMPARE(project.id(), Core::Id(TEST_PROJECT_ID)); - QVERIFY(!project.isParsing()); - QVERIFY(!project.hasParsingData()); + QVERIFY(!project.target->buildSystem()->isParsing()); + QVERIFY(!project.target->buildSystem()->hasParsingData()); } void ProjectExplorerPlugin::testProject_changeDisplayName() @@ -1132,16 +1082,16 @@ void ProjectExplorerPlugin::testProject_parsingSuccess() { TestProject project; - QSignalSpy startSpy(&project, &Project::parsingStarted); - QSignalSpy stopSpy(&project, &Project::parsingFinished); + QSignalSpy startSpy(project.target, &Target::parsingStarted); + QSignalSpy stopSpy(project.target, &Target::parsingFinished); { - Project::ParseGuard guard = project.guardParsingRun(); + BuildSystem::ParseGuard guard = project.target->buildSystem()->guardParsingRun(); QCOMPARE(startSpy.count(), 1); QCOMPARE(stopSpy.count(), 0); - QVERIFY(project.isParsing()); - QVERIFY(!project.hasParsingData()); + QVERIFY(project.target->buildSystem()->isParsing()); + QVERIFY(!project.target->buildSystem()->hasParsingData()); guard.markAsSuccess(); } @@ -1150,32 +1100,32 @@ void ProjectExplorerPlugin::testProject_parsingSuccess() QCOMPARE(stopSpy.count(), 1); QCOMPARE(stopSpy.at(0), {QVariant(true)}); - QVERIFY(!project.isParsing()); - QVERIFY(project.hasParsingData()); + QVERIFY(!project.target->buildSystem()->isParsing()); + QVERIFY(project.target->buildSystem()->hasParsingData()); } void ProjectExplorerPlugin::testProject_parsingFail() { TestProject project; - QSignalSpy startSpy(&project, &Project::parsingStarted); - QSignalSpy stopSpy(&project, &Project::parsingFinished); + QSignalSpy startSpy(project.target, &Target::parsingStarted); + QSignalSpy stopSpy(project.target, &Target::parsingFinished); { - Project::ParseGuard guard = project.guardParsingRun(); + BuildSystem::ParseGuard guard = project.target->buildSystem()->guardParsingRun(); QCOMPARE(startSpy.count(), 1); QCOMPARE(stopSpy.count(), 0); - QVERIFY(project.isParsing()); - QVERIFY(!project.hasParsingData()); + QVERIFY(project.target->buildSystem()->isParsing()); + QVERIFY(!project.target->buildSystem()->hasParsingData()); } QCOMPARE(startSpy.count(), 1); QCOMPARE(stopSpy.count(), 1); QCOMPARE(stopSpy.at(0), {QVariant(false)}); - QVERIFY(!project.isParsing()); - QVERIFY(!project.hasParsingData()); + QVERIFY(!project.target->buildSystem()->isParsing()); + QVERIFY(!project.target->buildSystem()->hasParsingData()); } std::unique_ptr<ProjectNode> createFileTree(Project *project) diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 326763bf8cd..243d9a079fe 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -50,6 +50,7 @@ namespace ProjectExplorer { class BuildInfo; class BuildSystem; +class BuildConfiguration; class ContainerNode; class EditorConfiguration; class FolderNode; @@ -64,7 +65,6 @@ class Target; class PROJECTEXPLORER_EXPORT Project : public QObject { friend class SessionManager; // for setActiveTarget - friend class ProjectExplorerPlugin; // for projectLoaded Q_OBJECT public: @@ -84,7 +84,7 @@ public: QString mimeType() const; bool canBuildProducts() const; - BuildSystem *buildSystem() const; + BuildSystem *createBuildSystem(Target *target) const; Utils::FilePath projectFilePath() const; Utils::FilePath projectDirectory() const; @@ -124,7 +124,6 @@ public: static const NodeMatcher GeneratedFiles; Utils::FilePathList files(const NodeMatcher &matcher) const; - virtual QStringList filesGeneratedFrom(const QString &sourceFile) const; bool isKnownFile(const Utils::FilePath &filename) const; virtual QVariantMap toMap() const; @@ -155,81 +154,20 @@ public: void setup(const QList<BuildInfo> &infoList); Utils::MacroExpander *macroExpander() const; - virtual QVariant additionalData(Core::Id id, const Target *target) const; - - bool isParsing() const; - bool hasParsingData() const; - ProjectNode *findNodeForBuildKey(const QString &buildKey) const; bool needsInitialExpansion() const; void setNeedsInitialExpansion(bool needsInitialExpansion); - class ParseGuard - { - public: - ParseGuard() - : ParseGuard(nullptr) - {} - - ~ParseGuard() { release(); } - - void markAsSuccess() const { m_success = true; } - bool isSuccess() const { return m_success; } - bool guardsProject() const { return m_project; } - - ParseGuard(const ParseGuard &other) = delete; - ParseGuard &operator=(const ParseGuard &other) = delete; - ParseGuard(ParseGuard &&other) - : m_project{std::move(other.m_project)} - , m_success{std::move(other.m_success)} - { - // No need to release this as this is invalid anyway:-) - other.m_project = nullptr; - } - ParseGuard &operator=(ParseGuard &&other) - { - release(); - - m_project = std::move(other.m_project); - m_success = std::move(other.m_success); - - other.m_project = nullptr; - return *this; - } - - private: - ParseGuard(Project *p) - : m_project(p) - { - if (m_project && !m_project->isParsing()) - m_project->emitParsingStarted(); - else - m_project = nullptr; - } - - void release() - { - if (m_project) - m_project->emitParsingFinished(m_success); - m_project = nullptr; - } - - Project *m_project = nullptr; - mutable bool m_success = false; - - friend class Project; - }; - - // FIXME: Make this private and the BuildSystem a friend - ParseGuard guardParsingRun() { return ParseGuard(this); } void setRootProjectNode(std::unique_ptr<ProjectNode> &&root); // Set project files that will be watched and trigger the same callback // as the main project file. void setExtraProjectFiles(const QVector<Utils::FilePath> &projectDocumentPaths); - Utils::Environment activeParseEnvironment() const; + void setDisplayName(const QString &name); + void setProjectLanguage(Core::Id id, bool enabled); + void addProjectLanguage(Core::Id id); signals: void projectFileIsDirty(const Utils::FilePath &path); @@ -243,11 +181,6 @@ signals: void removedProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc); void addedProjectConfiguration(ProjectExplorer::ProjectConfiguration *pc); - // *ANY* active build configuration changed somewhere in the tree. This might not be - // the one that would get started right now, since some part of the tree in between might - // not be active. - void activeBuildConfigurationChanged(ProjectExplorer::ProjectConfiguration *bc); - void aboutToRemoveTarget(ProjectExplorer::Target *target); void removedTarget(ProjectExplorer::Target *target); void addedTarget(ProjectExplorer::Target *target); @@ -257,8 +190,8 @@ signals: void projectLanguagesUpdated(); - void parsingStarted(); - void parsingFinished(bool success); + void anyParsingStarted(Target *target); + void anyParsingFinished(Target *target, bool success); void rootProjectDirectoryChanged(); @@ -267,7 +200,6 @@ protected: void createTargetFromMap(const QVariantMap &map, int index); virtual bool setupTarget(Target *t); - void setDisplayName(const QString &name); // Used to pre-check kits in the TargetSetupPage. RequiredKitPredicate // is used to select kits available in the TargetSetupPage void setPreferredKitPredicate(const Kit::Predicate &predicate); @@ -278,35 +210,26 @@ protected: void setId(Core::Id id); void setProjectLanguages(Core::Context language); - void addProjectLanguage(Core::Id id); void removeProjectLanguage(Core::Id id); - void setProjectLanguage(Core::Id id, bool enabled); void setHasMakeInstallEquivalent(bool enabled); - virtual void projectLoaded(); // Called when the project is fully loaded. void setKnowsAllBuildExecutables(bool value); void setNeedsBuildConfigurations(bool value); + void setNeedsDeployConfigurations(bool value); static ProjectExplorer::Task createProjectTask(ProjectExplorer::Task::TaskType type, const QString &description); - void setBuildSystemCreator(const std::function<BuildSystem *(Project *)> &creator); + void setBuildSystemCreator(const std::function<BuildSystem *(Target *)> &creator); private: - // Helper methods to manage parsing state and signalling - // Call in GUI thread before the actual parsing starts - void emitParsingStarted(); - // Call in GUI thread right after the actual parsing is done - void emitParsingFinished(bool success); - void addTarget(std::unique_ptr<Target> &&target); void handleSubTreeChanged(FolderNode *node); void setActiveTarget(Target *target); - ProjectPrivate *d; - friend class ContainerNode; + ProjectPrivate *d; }; } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4d7aee5fc83..93f003b7b29 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2046,7 +2046,6 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProject(cons return result; dd->addToRecentProjects(fileName, project->displayName()); SessionManager::setStartupProject(project); - project->projectLoaded(); return result; } @@ -2113,9 +2112,6 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con appendError(errorString, tr("Failed opening project \"%1\": Project is not a file.").arg(fileName)); } else if (Project *pro = ProjectManager::openProject(mt, filePath)) { - QObject::connect(pro, &Project::parsingFinished, [pro]() { - emit SessionManager::instance()->projectFinishedParsing(pro); - }); QString restoreError; Project::RestoreResult restoreResult = pro->restoreSettings(&restoreError); if (restoreResult == Project::RestoreResult::Ok) { diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp index 76fe5ed9dc9..007fe38e21a 100644 --- a/src/plugins/projectexplorer/projectmodels.cpp +++ b/src/plugins/projectexplorer/projectmodels.cpp @@ -25,6 +25,7 @@ #include "projectmodels.h" +#include "buildsystem.h" #include "project.h" #include "projectnodes.h" #include "projectexplorer.h" @@ -119,6 +120,8 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const const FolderNode * const folderNode = node->asFolderNode(); const ContainerNode * const containerNode = node->asContainerNode(); const Project * const project = containerNode ? containerNode->project() : nullptr; + const Target * const target = project ? project->activeTarget() : nullptr; + const BuildSystem * const bs = target ? target->buildSystem() : nullptr; switch (role) { case Qt::DisplayRole: @@ -128,7 +131,7 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const case Qt::ToolTipRole: { QString tooltip = node->tooltip(); if (project) { - if (project->activeTarget()) { + if (target) { QString projectIssues = toHtml(project->projectIssues(project->activeTarget()->kit())); if (!projectIssues.isEmpty()) tooltip += "<p>" + projectIssues; @@ -148,10 +151,9 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const static QIcon emptyIcon = Utils::Icons::EMPTY16.icon(); if (project->needsConfiguration()) return warnIcon; - if (project->isParsing()) + if (bs && bs->isParsing()) return emptyIcon; - if (!project->activeTarget() - || !project->projectIssues(project->activeTarget()->kit()).isEmpty()) + if (!target || !project->projectIssues(target->kit()).isEmpty()) return warnIcon; return containerNode->rootProjectNode() ? containerNode->rootProjectNode()->icon() : folderNode->icon(); @@ -167,7 +169,7 @@ QVariant FlatModel::data(const QModelIndex &index, int role) const case Project::FilePathRole: return node->filePath().toString(); case Project::isParsingRole: - return project ? project->isParsing() && !project->needsConfiguration() : false; + return project && bs ? bs->isParsing() && !project->needsConfiguration() : false; } return QVariant(); @@ -359,12 +361,12 @@ void FlatModel::handleProjectAdded(Project *project) { QTC_ASSERT(project, return); - connect(project, &Project::parsingStarted, + connect(project, &Project::anyParsingStarted, this, [this, project]() { if (nodeForProject(project)) parsingStateChanged(project); }); - connect(project, &Project::parsingFinished, + connect(project, &Project::anyParsingFinished, this, [this, project]() { if (nodeForProject(project)) parsingStateChanged(project); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index dd3783ebe02..09fb24520d2 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -25,10 +25,12 @@ #include "projectnodes.h" +#include "buildconfiguration.h" #include "buildsystem.h" #include "project.h" #include "projectexplorerconstants.h" #include "projecttree.h" +#include "target.h" #include <coreplugin/fileiconprovider.h> #include <coreplugin/icore.h> @@ -988,7 +990,8 @@ void ProjectNode::setFallbackData(Core::Id key, const QVariant &value) BuildSystem *ProjectNode::buildSystem() const { Project *p = getProject(); - return p ? p->buildSystem() : nullptr; + Target *t = p ? p->activeTarget() : nullptr; + return t ? t->buildSystem() : nullptr; } bool FolderNode::isEmpty() const diff --git a/src/plugins/projectexplorer/projecttree.cpp b/src/plugins/projectexplorer/projecttree.cpp index 8fda8340d71..b42da7ad66c 100644 --- a/src/plugins/projectexplorer/projecttree.cpp +++ b/src/plugins/projectexplorer/projecttree.cpp @@ -30,6 +30,7 @@ #include "projectnodes.h" #include "projecttreewidget.h" #include "session.h" +#include "target.h" #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/actionmanager.h> @@ -104,6 +105,18 @@ Project *ProjectTree::currentProject() return s_instance->m_currentProject; } +Target *ProjectTree::currentTarget() +{ + Project *p = currentProject(); + return p ? p->activeTarget() : nullptr; +} + +BuildSystem *ProjectTree::currentBuildSystem() +{ + Target *t = currentTarget(); + return t ? t->buildSystem() : nullptr; +} + Node *ProjectTree::currentNode() { s_instance->update(); diff --git a/src/plugins/projectexplorer/projecttree.h b/src/plugins/projectexplorer/projecttree.h index 4adcaa75713..bf1335e5be5 100644 --- a/src/plugins/projectexplorer/projecttree.h +++ b/src/plugins/projectexplorer/projecttree.h @@ -34,12 +34,14 @@ namespace Utils { class FilePath; } namespace ProjectExplorer { +class BuildSystem; class FileNode; class FolderNode; class Node; class Project; class ProjectNode; class SessionNode; +class Target; namespace Internal { class ProjectTreeWidget; } @@ -53,6 +55,8 @@ public: static ProjectTree *instance(); static Project *currentProject(); + static Target *currentTarget(); + static BuildSystem *currentBuildSystem(); static Node *currentNode(); static Utils::FilePath currentFilePath(); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 4629e0bc22c..7c40d8bc41e 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -27,6 +27,7 @@ #include "abi.h" #include "buildconfiguration.h" +#include "buildsystem.h" #include "environmentaspect.h" #include "kitinformation.h" #include "kitinformation.h" @@ -168,8 +169,7 @@ RunConfiguration::RunConfiguration(Target *target, Core::Id id) : ProjectConfiguration(target, id) { QTC_CHECK(target && target == this->target()); - connect(target->project(), &Project::parsingFinished, - this, [this]() { updateEnabledState(); }); + connect(target, &Target::parsingFinished, this, [this] { updateEnabledState(); }); connect(target, &Target::addedRunConfiguration, this, [this](const RunConfiguration *rc) { @@ -224,25 +224,16 @@ bool RunConfiguration::isActive() const return target()->isActive() && target()->activeRunConfiguration() == this; } -void RunConfiguration::setEnabled(bool enabled) +QString RunConfiguration::disabledReason() const { - if (enabled == m_isEnabled) - return; - m_isEnabled = enabled; - emit enabledChanged(); + BuildSystem *bs = activeBuildSystem(); + return bs ? bs->disabledReason(m_buildKey) : tr("No build system active"); } -QString RunConfiguration::disabledReason() const +bool RunConfiguration::isEnabled() const { - if (!project()->hasParsingData()) { - QString msg = project()->isParsing() ? tr("The project is currently being parsed.") - : tr("The project could not be fully parsed."); - const FilePath projectFilePath = buildTargetInfo().projectFilePath; - if (!projectFilePath.isEmpty() && !projectFilePath.exists()) - msg += '\n' + tr("The project file \"%1\" does not exist.").arg(projectFilePath.toString()); - return msg; - } - return QString(); + BuildSystem *bs = activeBuildSystem(); + return bs && bs->hasParsingData(); } QWidget *RunConfiguration::createConfigurationWidget() @@ -266,7 +257,7 @@ QWidget *RunConfiguration::createConfigurationWidget() void RunConfiguration::updateEnabledState() { - setEnabled(project()->hasParsingData()); + emit enabledChanged(); } void RunConfiguration::addAspectFactory(const AspectFactory &aspectFactory) @@ -312,11 +303,14 @@ RunConfiguration::ConfigurationState RunConfiguration::ensureConfigured(QString BuildConfiguration *RunConfiguration::activeBuildConfiguration() const { - if (!target()) - return nullptr; return target()->activeBuildConfiguration(); } +BuildSystem *RunConfiguration::activeBuildSystem() const +{ + return target()->buildSystem(); +} + QVariantMap RunConfiguration::toMap() const { QVariantMap map = ProjectConfiguration::toMap(); @@ -344,7 +338,9 @@ CommandLine RunConfiguration::commandLine() const BuildTargetInfo RunConfiguration::buildTargetInfo() const { - return target()->buildTarget(m_buildKey); + BuildSystem *bs = target()->buildSystem(); + QTC_ASSERT(bs, return {}); + return bs->buildTarget(m_buildKey); } bool RunConfiguration::fromMap(const QVariantMap &map) diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 78175e6156a..ae6ad9e2d65 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -43,6 +43,7 @@ namespace Utils { class OutputFormatter; } namespace ProjectExplorer { class BuildConfiguration; +class BuildSystem; class GlobalOrProjectAspect; class Runnable; class RunConfigurationFactory; @@ -126,10 +127,8 @@ public: bool isActive() const override; - bool isEnabled() const { return m_isEnabled; } - void setEnabled(bool enabled); - virtual QString disabledReason() const; + virtual bool isEnabled() const; virtual QWidget *createConfigurationWidget(); @@ -182,6 +181,7 @@ protected: /// convenience function to get current build configuration. BuildConfiguration *activeBuildConfiguration() const; + BuildSystem *activeBuildSystem() const; virtual void updateEnabledState(); virtual void doAdditionalSetup(const RunConfigurationCreationInfo &) {} @@ -193,7 +193,6 @@ private: friend class RunConfigurationFactory; QString m_buildKey; - bool m_isEnabled = false; CommandLineGetter m_commandLineGetter; }; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index b4a50d0099b..ec775c72dff 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -376,7 +376,7 @@ void RunControl::setTarget(Target *target) QTC_CHECK(!d->target); d->target = target; - if (!d->buildKey.isEmpty()) + if (!d->buildKey.isEmpty() && target->buildSystem()) d->buildTargetInfo = target->buildTarget(d->buildKey); if (auto bc = target->activeBuildConfiguration()) { diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index f224bce49eb..858ceb815c9 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -381,6 +381,17 @@ Project *SessionManager::startupProject() return d->m_startupProject; } +Target *SessionManager::startupTarget() +{ + return d->m_startupProject ? d->m_startupProject->activeTarget() : nullptr; +} + +BuildSystem *SessionManager::startupBuildSystem() +{ + Target *t = startupTarget(); + return t ? t->buildSystem() : nullptr; +} + void SessionManager::addProject(Project *pro) { QTC_ASSERT(pro, return); diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 782079f9d77..dfc403bc429 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -42,7 +42,9 @@ namespace ProjectExplorer { class Project; class Target; class BuildConfiguration; +class BuildSystem; class DeployConfiguration; + enum class SetActive { Cascade, NoCascade }; class PROJECTEXPLORER_EXPORT SessionManager : public QObject @@ -96,6 +98,8 @@ public: static Utils::FilePath sessionNameToFileName(const QString &session); static Project *startupProject(); + static Target *startupTarget(); + static BuildSystem *startupBuildSystem(); static const QList<Project *> projects(); static bool hasProjects(); @@ -119,6 +123,8 @@ public: static bool loadingSession(); signals: + void targetAdded(ProjectExplorer::Target *target); + void targetRemoved(ProjectExplorer::Target *target); void projectAdded(ProjectExplorer::Project *project); void aboutToRemoveProject(ProjectExplorer::Project *project); void projectDisplayNameChanged(ProjectExplorer::Project *project); diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index f8a0da25e71..dd9d98fd826 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -29,6 +29,7 @@ #include "buildconfiguration.h" #include "buildinfo.h" #include "buildmanager.h" +#include "buildsystem.h" #include "buildtargetinfo.h" #include "deployconfiguration.h" #include "deploymentdata.h" @@ -98,20 +99,24 @@ public: m_runConfigurationModel(t) { } + ~TargetPrivate() + { + delete m_buildSystem; + } + QIcon m_overlayIcon; QList<BuildConfiguration *> m_buildConfigurations; - BuildConfiguration *m_activeBuildConfiguration = nullptr; + QPointer<BuildConfiguration> m_activeBuildConfiguration; QList<DeployConfiguration *> m_deployConfigurations; DeployConfiguration *m_activeDeployConfiguration = nullptr; QList<RunConfiguration *> m_runConfigurations; RunConfiguration* m_activeRunConfiguration = nullptr; - DeploymentData m_deploymentData; - QList<BuildTargetInfo> m_appTargets; QVariantMap m_pluginSettings; Kit *const m_kit; MacroExpander m_macroExpander; + BuildSystem *m_buildSystem = nullptr; ProjectConfigurationModel m_buildConfigurationModel; ProjectConfigurationModel m_deployConfigurationModel; @@ -123,13 +128,24 @@ Target::Target(Project *project, Kit *k, _constructor_tag) : QObject(project), d(std::make_unique<TargetPrivate>(this, k)) { + // Note: nullptr is a valid state for the per-buildConfig systems. + d->m_buildSystem = project->createBuildSystem(this); + QTC_CHECK(d->m_kit); connect(DeviceManager::instance(), &DeviceManager::updated, this, &Target::updateDeviceState); - connect(project, &Project::parsingFinished, this, [this](bool success) { - if (success && this->project() == SessionManager::startupProject() - && this == this->project()->activeTarget()) { + + connect(this, &Target::parsingStarted, this, [this, project] { + project->anyParsingStarted(this); + }); + + connect(this, &Target::parsingFinished, this, [this, project](bool success) { + if (success && project == SessionManager::startupProject() + && this == project->activeTarget()) { updateDefaultRunConfigurations(); } + // For testing. + emit SessionManager::instance()->projectFinishedParsing(project); + project->anyParsingFinished(this, success); }, Qt::QueuedConnection); // Must wait for run configs to change their enabled state. KitManager *km = KitManager::instance(); @@ -193,6 +209,37 @@ Kit *Target::kit() const return d->m_kit; } +BuildSystem *Target::buildSystem() const +{ + if (d->m_activeBuildConfiguration) + return d->m_activeBuildConfiguration->buildSystem(); + + return d->m_buildSystem; +} + +BuildSystem *Target::fallbackBuildSystem() const +{ + return d->m_buildSystem; +} + +DeploymentData Target::deploymentData() const +{ + QTC_ASSERT(buildSystem(), return {}); + return buildSystem()->deploymentData(); +} + +const QList<BuildTargetInfo> Target::applicationTargets() const +{ + QTC_ASSERT(buildSystem(), return {}); + return buildSystem()->applicationTargets(); +} + +BuildTargetInfo Target::buildTarget(const QString &buildKey) const +{ + QTC_ASSERT(buildSystem(), return {}); + return buildSystem()->buildTarget(buildKey); +} + Core::Id Target::id() const { return d->m_kit->id(); @@ -277,7 +324,6 @@ void Target::setActiveBuildConfiguration(BuildConfiguration *bc) (bc && d->m_buildConfigurations.contains(bc) && bc != d->m_activeBuildConfiguration)) { d->m_activeBuildConfiguration = bc; - project()->activeBuildConfigurationChanged(d->m_activeBuildConfiguration); emit activeBuildConfigurationChanged(d->m_activeBuildConfiguration); } } @@ -353,49 +399,6 @@ void Target::setActiveDeployConfiguration(DeployConfiguration *dc) updateDeviceState(); } -void Target::setDeploymentData(const DeploymentData &deploymentData) -{ - if (d->m_deploymentData != deploymentData) { - d->m_deploymentData = deploymentData; - emit deploymentDataChanged(); - emit applicationTargetsChanged(); - } -} - -DeploymentData Target::deploymentData() const -{ - return d->m_deploymentData; -} - -void Target::setApplicationTargets(const QList<BuildTargetInfo> &appTargets) -{ - if (Utils::toSet(appTargets) != Utils::toSet(d->m_appTargets)) { - d->m_appTargets = appTargets; - emit applicationTargetsChanged(); - } -} - -const QList<BuildTargetInfo> Target::applicationTargets() const -{ - return d->m_appTargets; -} - -BuildTargetInfo Target::buildTarget(const QString &buildKey) const -{ - return Utils::findOrDefault(d->m_appTargets, [&buildKey](const BuildTargetInfo &ti) { - return ti.buildKey == buildKey; - }); -} - -QList<ProjectConfiguration *> Target::projectConfigurations() const -{ - QList<ProjectConfiguration *> result; - result.append(Utils::static_container_cast<ProjectConfiguration *>(buildConfigurations())); - result.append(Utils::static_container_cast<ProjectConfiguration *>(deployConfigurations())); - result.append(Utils::static_container_cast<ProjectConfiguration *>(runConfigurations())); - return result; -} - QList<RunConfiguration *> Target::runConfigurations() const { return d->m_runConfigurations; @@ -716,7 +719,7 @@ void Target::setNamedSettings(const QString &name, const QVariant &value) QVariant Target::additionalData(Core::Id id) const { - return project()->additionalData(id, this); + return buildSystem()->additionalData(id); } MakeInstallCommand Target::makeInstallCommand(const QString &installRoot) const diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h index 612adcef759..247b0e04251 100644 --- a/src/plugins/projectexplorer/target.h +++ b/src/plugins/projectexplorer/target.h @@ -35,6 +35,7 @@ QT_FORWARD_DECLARE_CLASS(QIcon) namespace ProjectExplorer { class BuildConfiguration; class BuildTargetInfo; +class BuildSystem; class DeployConfiguration; class DeploymentData; class Kit; @@ -60,6 +61,7 @@ public: Project *project() const; Kit *kit() const; + BuildSystem *buildSystem() const; Core::Id id() const; QString displayName() const; @@ -79,15 +81,6 @@ public: QList<DeployConfiguration *> deployConfigurations() const; DeployConfiguration *activeDeployConfiguration() const; - void setDeploymentData(const DeploymentData &deploymentData); - DeploymentData deploymentData() const; - - void setApplicationTargets(const QList<BuildTargetInfo> &appTargets); - const QList<BuildTargetInfo> applicationTargets() const; - BuildTargetInfo buildTarget(const QString &buildKey) const; - - QList<ProjectConfiguration *> projectConfigurations() const; - // Running QList<RunConfiguration *> runConfigurations() const; void addRunConfiguration(RunConfiguration *rc); @@ -119,12 +112,20 @@ public: ProjectConfigurationModel *deployConfigurationModel() const; ProjectConfigurationModel *runConfigurationModel() const; + BuildSystem *fallbackBuildSystem() const; + + DeploymentData deploymentData() const; + const QList<BuildTargetInfo> applicationTargets() const; + BuildTargetInfo buildTarget(const QString &buildKey) const; + signals: void targetEnabled(bool); void iconChanged(); void overlayIconChanged(); void kitChanged(); + void parsingStarted(); + void parsingFinished(bool); // TODO clean up signal names // might be better to also have aboutToRemove signals @@ -143,6 +144,7 @@ signals: void deploymentDataChanged(); void applicationTargetsChanged(); + void targetPropertiesChanged(); private: bool fromMap(const QVariantMap &map); diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 892b9f144f8..357438dbb83 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -39,6 +39,7 @@ #include <QJsonObject> #include <QProcessEnvironment> #include <QRegularExpression> +#include <QTimer> #include <coreplugin/documentmanager.h> #include <coreplugin/icontext.h> @@ -57,7 +58,7 @@ namespace Internal { class PythonBuildSystem : public BuildSystem { public: - explicit PythonBuildSystem(Project *project); + explicit PythonBuildSystem(Target *target); bool supportsAction(Node *context, ProjectAction action, const Node *node) const override; bool addFiles(Node *, const QStringList &filePaths, QStringList *) override; @@ -74,11 +75,9 @@ public: bool writePyProjectFile(const QString &fileName, QString &content, const QStringList &rawList, QString *errorMessage); - void refresh(); + void triggerParsing() final; private: - PythonProject *project() const; - QStringList m_rawFileList; QStringList m_files; QHash<QString, QString> m_rawListEntries; @@ -191,12 +190,12 @@ PythonProject::PythonProject(const FilePath &fileName) setDisplayName(fileName.toFileInfo().completeBaseName()); setNeedsBuildConfigurations(false); - setBuildSystemCreator([](Project *p) { return new PythonBuildSystem(p); }); + setBuildSystemCreator([](Target *t) { return new PythonBuildSystem(t); }); } -void PythonBuildSystem::refresh() +void PythonBuildSystem::triggerParsing() { - Project::ParseGuard guard = project()->guardParsingRun(); + ParseGuard guard = guardParsingRun(); parse(); const QDir baseDir(projectDirectory().toString()); @@ -225,8 +224,7 @@ void PythonBuildSystem::refresh() } project()->setRootProjectNode(std::move(newRoot)); - if (Target *target = project()->activeTarget()) - target->setApplicationTargets(appTargets); + setApplicationTargets(appTargets); guard.markAsSuccess(); } @@ -423,27 +421,16 @@ Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *e if (res == RestoreResult::Ok) { if (!activeTarget()) addTargetForDefaultKit(); - - if (auto bs = dynamic_cast<PythonBuildSystem *>(buildSystem())) - bs->refresh(); } return res; } -bool PythonProject::setupTarget(Target *t) +PythonBuildSystem::PythonBuildSystem(Target *target) + : BuildSystem(target) { - bool res = Project::setupTarget(t); - if (auto bs = dynamic_cast<PythonBuildSystem *>(buildSystem())) - QTimer::singleShot(0, bs, &PythonBuildSystem::refresh); - return res; -} - -PythonBuildSystem::PythonBuildSystem(Project *project) - : BuildSystem(project) -{ - connect(project, &Project::projectFileIsDirty, this, [this]() { refresh(); }); - QTimer::singleShot(0, this, &PythonBuildSystem::refresh); + connect(target->project(), &Project::projectFileIsDirty, this, [this]() { triggerParsing(); }); + QTimer::singleShot(0, this, &PythonBuildSystem::triggerParsing); } bool PythonBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const @@ -460,10 +447,5 @@ bool PythonBuildSystem::supportsAction(Node *context, ProjectAction action, cons return BuildSystem::supportsAction(context, action, node); } -PythonProject *PythonBuildSystem::project() const -{ - return static_cast<PythonProject *>(BuildSystem::project()); -} - } // namespace Internal } // namespace Python diff --git a/src/plugins/python/pythonproject.h b/src/plugins/python/pythonproject.h index d030c92dcdc..38b7dc27910 100644 --- a/src/plugins/python/pythonproject.h +++ b/src/plugins/python/pythonproject.h @@ -43,7 +43,6 @@ public: bool needsConfiguration() const final { return false; } private: RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; - bool setupTarget(ProjectExplorer::Target *t) override; }; } // namespace Internal diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 8af7e2f1b24..eca2d7e7ef2 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -279,7 +279,7 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Core::Id id) connect(target, &Target::applicationTargetsChanged, this, &PythonRunConfiguration::updateTargetInformation); - connect(target->project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &PythonRunConfiguration::updateTargetInformation); } diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp index 93cbde2eb10..eeab2c51f77 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.cpp @@ -52,6 +52,7 @@ #include <utils/qtcprocess.h> #include <QCoreApplication> +#include <QCryptographicHash> using namespace ProjectExplorer; using namespace Utils; @@ -92,6 +93,18 @@ QbsBuildConfiguration::QbsBuildConfiguration(Target *target, Core::Id id) this, &QbsBuildConfiguration::triggerReparseIfActive); connect(this, &QbsBuildConfiguration::qbsConfigurationChanged, this, &QbsBuildConfiguration::triggerReparseIfActive); + + m_buildSystem = new QbsBuildSystem(this); +} + +QbsBuildConfiguration::~QbsBuildConfiguration() +{ + delete m_buildSystem; +} + +BuildSystem *QbsBuildConfiguration::buildSystem() const +{ + return m_buildSystem; } void QbsBuildConfiguration::initialize() @@ -119,7 +132,15 @@ void QbsBuildConfiguration::initialize() + Utils::FileUtils::fileSystemFriendlyName(initialDisplayName()); } - m_configurationName->setValue(configName); + const Kit *kit = target()->kit(); + const QString kitName = kit->displayName(); + const QByteArray kitHash = QCryptographicHash::hash(kitName.toUtf8(), QCryptographicHash::Sha1); + + const QString uniqueConfigName = configName + + '_' + kit->fileSystemFriendlyName().left(8) + + '_' + kitHash.toHex().left(16); + + m_configurationName->setValue(uniqueConfigName); BuildStepList *buildSteps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); auto bs = new QbsBuildStep(buildSteps); @@ -137,7 +158,7 @@ void QbsBuildConfiguration::initialize() void QbsBuildConfiguration::triggerReparseIfActive() { if (isActive()) - qbsProject()->delayParsing(); + m_buildSystem->delayParsing(); } bool QbsBuildConfiguration::fromMap(const QVariantMap &map) @@ -169,11 +190,6 @@ QVariantMap QbsBuildConfiguration::qbsConfiguration() const return config; } -Internal::QbsProject *QbsBuildConfiguration::qbsProject() const -{ - return qobject_cast<Internal::QbsProject *>(project()); -} - BuildConfiguration::BuildType QbsBuildConfiguration::buildType() const { QString variant; diff --git a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h index 0dbd442efb1..a19c52fd997 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h +++ b/src/plugins/qbsprojectmanager/qbsbuildconfiguration.h @@ -46,15 +46,15 @@ class QbsBuildConfiguration : public ProjectExplorer::BuildConfiguration friend class ProjectExplorer::BuildConfigurationFactory; QbsBuildConfiguration(ProjectExplorer::Target *target, Core::Id id); + ~QbsBuildConfiguration() final; public: - void initialize() override; + ProjectExplorer::BuildSystem *buildSystem() const final; + void initialize() final; QbsBuildStep *qbsStep() const; QVariantMap qbsConfiguration() const; - Internal::QbsProject *qbsProject() const; - BuildType buildType() const override; void setChangedFiles(const QStringList &files); @@ -67,7 +67,6 @@ public: QStringList products() const; QString configurationName() const; - QString equivalentCommandLine(const ProjectExplorer::BuildStep *buildStep) const; signals: @@ -80,7 +79,8 @@ private: QStringList m_changedFiles; QStringList m_activeFileTags; QStringList m_products; - ProjectExplorer::BaseStringAspect *m_configurationName; + ProjectExplorer::BaseStringAspect *m_configurationName = nullptr; + QbsBuildSystem *m_buildSystem = nullptr; }; class QbsBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp index 25d16c08ad0..f58f63207ef 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.cpp @@ -170,7 +170,7 @@ QbsBuildStep::~QbsBuildStep() bool QbsBuildStep::init() { - if (project()->isParsing() || m_job) + if (qbsBuildSystem()->isParsing() || m_job) return false; auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration()); @@ -212,7 +212,7 @@ ProjectExplorer::BuildStepConfigWidget *QbsBuildStep::createConfigWidget() void QbsBuildStep::doCancel() { if (m_parsingProject) - qbsProject()->cancelParsing(); + qbsBuildSystem()->cancelParsing(); else if (m_job) m_job->cancel(); } @@ -238,10 +238,8 @@ QVariantMap QbsBuildStep::qbsConfiguration(VariableHandling variableHandling) co void QbsBuildStep::setQbsConfiguration(const QVariantMap &config) { - auto pro = static_cast<QbsProject *>(project()); - QVariantMap tmp = config; - tmp.insert(Constants::QBS_CONFIG_PROFILE_KEY, pro->profileForTarget(target())); + tmp.insert(Constants::QBS_CONFIG_PROFILE_KEY, qbsBuildSystem()->profile()); if (!tmp.contains(Constants::QBS_CONFIG_VARIANT_KEY)) tmp.insert(Constants::QBS_CONFIG_VARIANT_KEY, QString::fromLatin1(Constants::QBS_VARIANT_DEBUG)); @@ -347,14 +345,12 @@ void QbsBuildStep::buildingDone(bool success) createTaskAndOutput(ProjectExplorer::Task::Error, item.description(), item.codeLocation().filePath(), item.codeLocation().line()); - auto pro = static_cast<QbsProject *>(project()); - // Building can uncover additional target artifacts. - pro->updateAfterBuild(); + qbsBuildSystem()->updateAfterBuild(); // The reparsing, if it is necessary, has to be done before finished() is emitted, as // otherwise a potential additional build step could conflict with the parsing step. - if (pro->parsingScheduled()) + if (qbsBuildSystem()->parsingScheduled()) parseProject(); else finish(); @@ -362,7 +358,7 @@ void QbsBuildStep::buildingDone(bool success) void QbsBuildStep::reparsingDone(bool success) { - disconnect(project(), &Project::parsingFinished, this, &QbsBuildStep::reparsingDone); + disconnect(target(), &Target::parsingFinished, this, &QbsBuildStep::reparsingDone); m_parsingProject = false; if (m_job) { // This was a scheduled reparsing after building. finish(); @@ -431,6 +427,11 @@ QString QbsBuildStep::buildVariant() const return qbsConfiguration(PreserveVariables).value(Constants::QBS_CONFIG_VARIANT_KEY).toString(); } +QbsBuildSystem *QbsBuildStep::qbsBuildSystem() const +{ + return static_cast<QbsBuildSystem *>(buildConfiguration()->buildSystem()); +} + void QbsBuildStep::setBuildVariant(const QString &variant) { if (m_qbsConfiguration.value(Constants::QBS_CONFIG_VARIANT_KEY).toString() == variant) @@ -490,8 +491,8 @@ void QbsBuildStep::setCleanInstallRoot(bool clean) void QbsBuildStep::parseProject() { m_parsingProject = true; - connect(project(), &Project::parsingFinished, this, &QbsBuildStep::reparsingDone); - qbsProject()->parseCurrentBuildConfiguration(); + connect(target(), &Target::parsingFinished, this, &QbsBuildStep::reparsingDone); + qbsBuildSystem()->parseCurrentBuildConfiguration(); } void QbsBuildStep::build() @@ -503,7 +504,7 @@ void QbsBuildStep::build() options.setLogElapsedTime(!qEnvironmentVariableIsEmpty(Constants::QBS_PROFILING_ENV)); QString error; - m_job = qbsProject()->build(options, m_products, error); + m_job = qbsBuildSystem()->build(options, m_products, error); if (!m_job) { emit addOutput(error, OutputFormat::ErrorMessage); emit finished(false); diff --git a/src/plugins/qbsprojectmanager/qbsbuildstep.h b/src/plugins/qbsprojectmanager/qbsbuildstep.h index 913bf61268e..7258b6347cf 100644 --- a/src/plugins/qbsprojectmanager/qbsbuildstep.h +++ b/src/plugins/qbsprojectmanager/qbsbuildstep.h @@ -79,6 +79,8 @@ public: } bool isQmlDebuggingEnabled() const { return m_enableQmlDebugging; } + QbsBuildSystem *qbsBuildSystem() const; + signals: void qbsConfigurationChanged(); void qbsBuildOptionsChanged(); diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.cpp b/src/plugins/qbsprojectmanager/qbscleanstep.cpp index 7b64b888cec..5e46e166e90 100644 --- a/src/plugins/qbsprojectmanager/qbscleanstep.cpp +++ b/src/plugins/qbsprojectmanager/qbscleanstep.cpp @@ -81,7 +81,7 @@ QbsCleanStep::~QbsCleanStep() bool QbsCleanStep::init() { - if (project()->isParsing() || m_job) + if (buildSystem()->isParsing() || m_job) return false; auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration()); @@ -95,13 +95,12 @@ bool QbsCleanStep::init() void QbsCleanStep::doRun() { - auto pro = static_cast<QbsProject *>(project()); qbs::CleanOptions options; options.setDryRun(m_dryRunAspect->value()); options.setKeepGoing(m_keepGoingAspect->value()); QString error; - m_job = pro->clean(options, m_products, error); + m_job = qbsBuildSystem()->clean(options, m_products, error); if (!m_job) { emit addOutput(error, OutputFormat::ErrorMessage); emit finished(false); @@ -157,6 +156,11 @@ void QbsCleanStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, con emit addOutput(message, OutputFormat::Stdout); } +QbsBuildSystem *QbsCleanStep::qbsBuildSystem() const +{ + return static_cast<QbsBuildSystem *>(buildSystem()); +} + // -------------------------------------------------------------------- // QbsCleanStepFactory: // -------------------------------------------------------------------- diff --git a/src/plugins/qbsprojectmanager/qbscleanstep.h b/src/plugins/qbsprojectmanager/qbscleanstep.h index fa07d35292b..df2dccbf13b 100644 --- a/src/plugins/qbsprojectmanager/qbscleanstep.h +++ b/src/plugins/qbsprojectmanager/qbscleanstep.h @@ -62,6 +62,8 @@ private: ProjectExplorer::BaseBoolAspect *m_dryRunAspect = nullptr; ProjectExplorer::BaseBoolAspect *m_keepGoingAspect = nullptr; + QbsBuildSystem *qbsBuildSystem() const; + QStringList m_products; qbs::CleanJob *m_job = nullptr; diff --git a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp index 648d4c3e8ee..49ce7c84848 100644 --- a/src/plugins/qbsprojectmanager/qbsinstallstep.cpp +++ b/src/plugins/qbsprojectmanager/qbsinstallstep.cpp @@ -109,14 +109,14 @@ QbsInstallStep::~QbsInstallStep() bool QbsInstallStep::init() { - QTC_ASSERT(!project()->isParsing() && !m_job, return false); + QTC_ASSERT(!buildConfiguration()->buildSystem()->isParsing() && !m_job, return false); return true; } void QbsInstallStep::doRun() { - auto pro = static_cast<QbsProject *>(project()); - m_job = pro->install(m_qbsInstallOptions); + auto bs = static_cast<QbsBuildSystem *>(buildSystem()); + m_job = bs->install(m_qbsInstallOptions); if (!m_job) { emit finished(false); @@ -336,7 +336,7 @@ QbsInstallStepConfigWidget::QbsInstallStepConfigWidget(QbsInstallStep *step) : connect(m_keepGoingCheckBox, &QAbstractButton::toggled, this, &QbsInstallStepConfigWidget::changeKeepGoing); - connect(m_step->project(), &Project::parsingFinished, + connect(m_step->target(), &Target::parsingFinished, this, &QbsInstallStepConfigWidget::updateState); updateState(); diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp index 002ebe77fbb..8ec0669cd31 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp @@ -54,35 +54,6 @@ using namespace ProjectExplorer; namespace QbsProjectManager { namespace Internal { -static const QbsProjectNode *parentQbsProjectNode(const ProjectExplorer::Node *node) -{ - for (const ProjectExplorer::FolderNode *pn = node->managingProject(); pn; pn = pn->parentProjectNode()) { - const auto prjNode = dynamic_cast<const QbsProjectNode *>(pn); - if (prjNode) - return prjNode; - } - return nullptr; -} - -static const QbsProductNode *parentQbsProductNode(const ProjectExplorer::Node *node) -{ - for (; node; node = node->parentFolderNode()) { - const auto prdNode = dynamic_cast<const QbsProductNode *>(node); - if (prdNode) - return prdNode; - } - return nullptr; -} - -static qbs::GroupData findMainQbsGroup(const qbs::ProductData &productData) -{ - foreach (const qbs::GroupData &grp, productData.groups()) { - if (grp.name() == productData.name() && grp.location() == productData.location()) - return grp; - } - return qbs::GroupData(); -} - class FileTreeNode { public: explicit FileTreeNode(const QString &n = QString(), FileTreeNode *p = nullptr, bool f = false) : @@ -212,16 +183,6 @@ public: }; -static bool supportsNodeAction(ProjectAction action, const Node *node) -{ - const QbsProject * const project = parentQbsProjectNode(node)->project(); - if (!project->isProjectEditable()) - return false; - if (action == RemoveFile || action == Rename) - return node->asFileNode(); - return false; -} - // -------------------------------------------------------------------- // QbsGroupNode: // -------------------------------------------------------------------- @@ -337,16 +298,11 @@ QbsProjectNode::QbsProjectNode(const Utils::FilePath &projectDirectory) : setIcon(projectIcon); } -QbsProject *QbsProjectNode::project() const +Project *QbsProjectNode::project() const { return static_cast<QbsProjectNode *>(parentFolderNode())->project(); } -const qbs::Project QbsProjectNode::qbsProject() const -{ - return project()->qbsProject(); -} - void QbsProjectNode::setProjectData(const qbs::ProjectData &data) { m_projectData = data; @@ -356,156 +312,11 @@ void QbsProjectNode::setProjectData(const qbs::ProjectData &data) // QbsRootProjectNode: // -------------------------------------------------------------------- -QbsRootProjectNode::QbsRootProjectNode(QbsProject *project) : +QbsRootProjectNode::QbsRootProjectNode(Project *project) : QbsProjectNode(project->projectDirectory()), m_project(project) { } -// -------------------------------------------------------------------- -// QbsBuildSystem: -// -------------------------------------------------------------------- - -QbsBuildSystem::QbsBuildSystem(Project *project) - : BuildSystem(project) -{ -} - -bool QbsBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const -{ - if (dynamic_cast<QbsGroupNode *>(context)) { - if (action == AddNewFile || action == AddExistingFile) - return true; - } - - if (dynamic_cast<QbsProductNode *>(context)) { - if (action == AddNewFile || action == AddExistingFile) - return true; - } - - return supportsNodeAction(action, node); -} - -bool QbsBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) -{ - if (auto n = dynamic_cast<QbsGroupNode *>(context)) { - QStringList notAddedDummy; - if (!notAdded) - notAdded = ¬AddedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notAdded += filePaths; - return false; - } - - const QbsProductNode *prdNode = parentQbsProductNode(n); - if (!prdNode || !prdNode->qbsProductData().isValid()) { - *notAdded += filePaths; - return false; - } - - return prjNode->project()->addFilesToProduct(filePaths, prdNode->qbsProductData(), - n->m_qbsGroupData, notAdded); - } - - if (auto n = dynamic_cast<QbsProductNode *>(context)) { - QStringList notAddedDummy; - if (!notAdded) - notAdded = ¬AddedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notAdded += filePaths; - return false; - } - - qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); - if (grp.isValid()) - return prjNode->project()->addFilesToProduct(filePaths, n->qbsProductData(), grp, notAdded); - - QTC_ASSERT(false, return false); - } - - return BuildSystem::addFiles(context, filePaths, notAdded); -} - -RemovedFilesFromProject QbsBuildSystem::removeFiles(Node *context, const QStringList &filePaths, - QStringList *notRemoved) -{ - if (auto n = dynamic_cast<QbsGroupNode *>(context)) { - QStringList notRemovedDummy; - if (!notRemoved) - notRemoved = ¬RemovedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - const QbsProductNode *prdNode = parentQbsProductNode(n); - if (!prdNode || !prdNode->qbsProductData().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - return project()->removeFilesFromProduct(filePaths, prdNode->qbsProductData(), - n->m_qbsGroupData, notRemoved); - } - - if (auto n = dynamic_cast<QbsProductNode *>(context)) { - QStringList notRemovedDummy; - if (!notRemoved) - notRemoved = ¬RemovedDummy; - - const QbsProjectNode *prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) { - *notRemoved += filePaths; - return RemovedFilesFromProject::Error; - } - - qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); - if (grp.isValid()) { - return prjNode->project()->removeFilesFromProduct(filePaths, n->qbsProductData(), grp, - notRemoved); - } - - QTC_ASSERT(false, return RemovedFilesFromProject::Error); - } - - return BuildSystem::removeFiles(context, filePaths, notRemoved); -} - -bool QbsBuildSystem::renameFile(Node *context, const QString &filePath, const QString &newFilePath) -{ - if (auto *n = dynamic_cast<QbsGroupNode *>(context)) { - const QbsProjectNode *prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) - return false; - const QbsProductNode *prdNode = parentQbsProductNode(n); - if (!prdNode || !prdNode->qbsProductData().isValid()) - return false; - - return project()->renameFileInProduct(filePath, newFilePath, - prdNode->qbsProductData(), n->m_qbsGroupData); - } - - if (auto *n = dynamic_cast<QbsProductNode *>(context)) { - const QbsProjectNode * prjNode = parentQbsProjectNode(n); - if (!prjNode || !prjNode->qbsProject().isValid()) - return false; - const qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); - QTC_ASSERT(grp.isValid(), return false); - return prjNode->project()->renameFileInProduct(filePath, newFilePath, n->qbsProductData(), grp); - } - - return BuildSystem::renameFile(context, filePath, newFilePath); -} - -QbsProject *QbsBuildSystem::project() const -{ - return static_cast<QbsProject *>(BuildSystem::project()); -} } // namespace Internal } // namespace QbsProjectManager diff --git a/src/plugins/qbsprojectmanager/qbsnodes.h b/src/plugins/qbsprojectmanager/qbsnodes.h index a2439dcdb62..74a571bac6a 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.h +++ b/src/plugins/qbsprojectmanager/qbsnodes.h @@ -35,26 +35,7 @@ namespace Internal { class QbsNodeTreeBuilder; class QbsProject; - -class QbsBuildSystem : public ProjectExplorer::BuildSystem -{ -public: - explicit QbsBuildSystem(ProjectExplorer::Project *project); - - bool supportsAction(ProjectExplorer::Node *context, - ProjectExplorer::ProjectAction action, - const ProjectExplorer::Node *node) const final; - bool addFiles(ProjectExplorer::Node *context, - const QStringList &filePaths, - QStringList *notAdded = nullptr) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, - const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool renameFile(ProjectExplorer::Node *context, - const QString &filePath, const QString &newFilePath) override; - - QbsProject *project() const; -}; +class QbsBuildSystem; // -------------------------------------------------------------------- // QbsGroupNode: @@ -106,8 +87,7 @@ class QbsProjectNode : public ProjectExplorer::ProjectNode public: explicit QbsProjectNode(const Utils::FilePath &projectDirectory); - virtual QbsProject *project() const; - const qbs::Project qbsProject() const; + virtual ProjectExplorer::Project *project() const; const qbs::ProjectData qbsProjectData() const { return m_projectData; } void setProjectData(const qbs::ProjectData &data); // FIXME: Needed? @@ -125,12 +105,12 @@ private: class QbsRootProjectNode : public QbsProjectNode { public: - explicit QbsRootProjectNode(QbsProject *project); + explicit QbsRootProjectNode(ProjectExplorer::Project *project); - QbsProject *project() const override { return m_project; } + ProjectExplorer::Project *project() const override { return m_project; } private: - QbsProject *const m_project; + ProjectExplorer::Project *const m_project; }; diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index f7bbde2a138..cc6e7e54db8 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -203,19 +203,19 @@ QStringList unreferencedBuildSystemFiles(const qbs::Project &p) } // namespace -std::unique_ptr<QbsRootProjectNode> QbsNodeTreeBuilder::buildTree(QbsProject *project) +std::unique_ptr<QbsRootProjectNode> QbsNodeTreeBuilder::buildTree(QbsBuildSystem *buildSystem) { - if (!project->qbsProjectData().isValid()) + if (!buildSystem->qbsProjectData().isValid()) return {}; - auto root = std::make_unique<QbsRootProjectNode>(project); - setupProjectNode(root.get(), project->qbsProjectData(), project->qbsProject()); + auto root = std::make_unique<QbsRootProjectNode>(buildSystem->project()); + setupProjectNode(root.get(), buildSystem->qbsProjectData(), buildSystem->qbsProject()); - auto buildSystemFiles = std::make_unique<FolderNode>(project->projectDirectory()); + auto buildSystemFiles = std::make_unique<FolderNode>(buildSystem->projectDirectory()); buildSystemFiles->setDisplayName(QCoreApplication::translate("QbsRootProjectNode", "Qbs files")); - const FilePath base = project->projectDirectory(); - const QStringList files = unreferencedBuildSystemFiles(project->qbsProject()); + const FilePath base = buildSystem->projectDirectory(); + const QStringList files = unreferencedBuildSystemFiles(buildSystem->qbsProject()); for (const QString &f : files) { const FilePath filePath = FilePath::fromString(f); if (filePath.isChildOf(base)) diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h index 4834dd00d19..3568cda7c6f 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.h @@ -39,7 +39,7 @@ namespace Internal { class QbsNodeTreeBuilder { public: - static std::unique_ptr<QbsRootProjectNode> buildTree(QbsProject *project); + static std::unique_ptr<QbsRootProjectNode> buildTree(QbsBuildSystem *project); }; } // namespace Internal diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index ade70195c99..381bb9ce6e8 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -127,45 +127,98 @@ private: QbsProject::QbsProject(const FilePath &fileName) : Project(Constants::MIME_TYPE, fileName) - , m_cppCodeModelUpdater(new CppTools::CppProjectUpdater) { - m_parsingDelay.setInterval(1000); // delay parsing by 1s. - setId(Constants::PROJECT_ID); setProjectLanguages(Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setCanBuildProducts(); + setDisplayName(fileName.toFileInfo().completeBaseName()); +} - setBuildSystemCreator([](Project *p) { return new QbsBuildSystem(p); }); +QbsProject::~QbsProject() +{ + delete m_importer; +} - rebuildProjectTree(); +ProjectImporter *QbsProject::projectImporter() const +{ + if (!m_importer) + m_importer = new QbsProjectImporter(projectFilePath()); + return m_importer; +} - connect(this, &Project::activeTargetChanged, this, &QbsProject::changeActiveTarget); - connect(this, &Project::addedTarget, this, [this](Target *t) { - m_qbsProjects.insert(t, qbs::Project()); - }); - connect(this, &Project::removedTarget, this, [this](Target *t) { - const auto it = m_qbsProjects.find(t); - QTC_ASSERT(it != m_qbsProjects.end(), return); - if (it.value() == m_qbsProject) { - m_qbsProject = qbs::Project(); - m_projectData = qbs::ProjectData(); - } - m_qbsProjects.erase(it); - }); +// -------------------------------------------------------------------- +// QbsBuildSystem: +// -------------------------------------------------------------------- + +static const QbsProjectNode *parentQbsProjectNode(const ProjectExplorer::Node *node) +{ + for (const ProjectExplorer::FolderNode *pn = node->managingProject(); pn; pn = pn->parentProjectNode()) { + const auto prjNode = dynamic_cast<const QbsProjectNode *>(pn); + if (prjNode) + return prjNode; + } + return nullptr; +} - connect(this, &Project::activeBuildConfigurationChanged, - this, &QbsProject::delayParsing); +static const QbsProductNode *parentQbsProductNode(const ProjectExplorer::Node *node) +{ + for (; node; node = node->parentFolderNode()) { + const auto prdNode = dynamic_cast<const QbsProductNode *>(node); + if (prdNode) + return prdNode; + } + return nullptr; +} - connect(&m_parsingDelay, &QTimer::timeout, this, &QbsProject::startParsing); +static bool supportsNodeAction(ProjectAction action, const Node *node) +{ + const Project * const project = parentQbsProjectNode(node)->project(); + Target *t = project ? project->activeTarget() : nullptr; + QbsBuildSystem *bs = t ? static_cast<QbsBuildSystem *>(t->buildSystem()) : nullptr; + if (!bs) + return false; + if (!bs->isProjectEditable()) + return false; + if (action == RemoveFile || action == Rename) + return node->asFileNode(); + return false; +} - connect(this, &QbsProject::projectFileIsDirty, this, &QbsProject::delayParsing); +static qbs::GroupData findMainQbsGroup(const qbs::ProductData &productData) +{ + foreach (const qbs::GroupData &grp, productData.groups()) { + if (grp.name() == productData.name() && grp.location() == productData.location()) + return grp; + } + return qbs::GroupData(); } -QbsProject::~QbsProject() +QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc) + : BuildSystem(bc->target()), + m_cppCodeModelUpdater(new CppTools::CppProjectUpdater), + m_buildConfiguration(bc) + +{ + m_parsingDelay.setInterval(1000); // delay parsing by 1s. + delayParsing(); + + connect(bc->project(), &Project::activeTargetChanged, + this, &QbsBuildSystem::changeActiveTarget); + + connect(bc->target(), &Target::activeBuildConfigurationChanged, + this, &QbsBuildSystem::delayParsing); + + connect(&m_parsingDelay, &QTimer::timeout, this, &QbsBuildSystem::triggerParsing); + + connect(bc->project(), &Project::projectFileIsDirty, this, &QbsBuildSystem::delayParsing); + + rebuildProjectTree(); +} + +QbsBuildSystem::~QbsBuildSystem() { delete m_cppCodeModelUpdater; delete m_qbsProjectParser; - delete m_importer; if (m_qbsUpdateFutureInterface) { m_qbsUpdateFutureInterface->reportCanceled(); m_qbsUpdateFutureInterface->reportFinished(); @@ -175,24 +228,141 @@ QbsProject::~QbsProject() qDeleteAll(m_extraCompilers); } -void QbsProject::projectLoaded() +bool QbsBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const { - m_parsingDelay.start(0); + if (dynamic_cast<QbsGroupNode *>(context)) { + if (action == AddNewFile || action == AddExistingFile) + return true; + } + + if (dynamic_cast<QbsProductNode *>(context)) { + if (action == AddNewFile || action == AddExistingFile) + return true; + } + + return supportsNodeAction(action, node); } -ProjectImporter *QbsProject::projectImporter() const +bool QbsBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) { - if (!m_importer) - m_importer = new QbsProjectImporter(projectFilePath()); - return m_importer; + if (auto n = dynamic_cast<QbsGroupNode *>(context)) { + QStringList notAddedDummy; + if (!notAdded) + notAdded = ¬AddedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) { + *notAdded += filePaths; + return false; + } + + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) { + *notAdded += filePaths; + return false; + } + + return addFilesToProduct(filePaths, prdNode->qbsProductData(), n->m_qbsGroupData, notAdded); + } + + if (auto n = dynamic_cast<QbsProductNode *>(context)) { + QStringList notAddedDummy; + if (!notAdded) + notAdded = ¬AddedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) { + *notAdded += filePaths; + return false; + } + + qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + if (grp.isValid()) + return addFilesToProduct(filePaths, n->qbsProductData(), grp, notAdded); + + QTC_ASSERT(false, return false); + } + + return BuildSystem::addFiles(context, filePaths, notAdded); } -QVariant QbsProject::additionalData(Id id, const Target *target) const +RemovedFilesFromProject QbsBuildSystem::removeFiles(Node *context, const QStringList &filePaths, + QStringList *notRemoved) +{ + if (auto n = dynamic_cast<QbsGroupNode *>(context)) { + QStringList notRemovedDummy; + if (!notRemoved) + notRemoved = ¬RemovedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + return removeFilesFromProduct(filePaths, prdNode->qbsProductData(), + n->m_qbsGroupData, notRemoved); + } + + if (auto n = dynamic_cast<QbsProductNode *>(context)) { + QStringList notRemovedDummy; + if (!notRemoved) + notRemoved = ¬RemovedDummy; + + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) { + *notRemoved += filePaths; + return RemovedFilesFromProject::Error; + } + + qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + if (grp.isValid()) { + return removeFilesFromProduct(filePaths, n->qbsProductData(), grp, notRemoved); + } + + QTC_ASSERT(false, return RemovedFilesFromProject::Error); + } + + return BuildSystem::removeFiles(context, filePaths, notRemoved); +} + +bool QbsBuildSystem::renameFile(Node *context, const QString &filePath, const QString &newFilePath) +{ + if (auto *n = dynamic_cast<QbsGroupNode *>(context)) { + const QbsProjectNode *prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) + return false; + const QbsProductNode *prdNode = parentQbsProductNode(n); + if (!prdNode || !prdNode->qbsProductData().isValid()) + return false; + + return renameFileInProduct(filePath, newFilePath, + prdNode->qbsProductData(), n->m_qbsGroupData); + } + + if (auto *n = dynamic_cast<QbsProductNode *>(context)) { + const QbsProjectNode * prjNode = parentQbsProjectNode(n); + if (!prjNode || !qbsProject().isValid()) + return false; + const qbs::GroupData grp = findMainQbsGroup(n->qbsProductData()); + QTC_ASSERT(grp.isValid(), return false); + return renameFileInProduct(filePath, newFilePath, n->qbsProductData(), grp); + } + + return BuildSystem::renameFile(context, filePath, newFilePath); +} + +QVariant QbsBuildSystem::additionalData(Id id) const { if (id == "QmlDesignerImportPath") { - const qbs::Project qbsProject = m_qbsProjects.value(const_cast<Target *>(target)); - const qbs::ProjectData projectData = qbsProject.isValid() - ? qbsProject.projectData() : qbs::ProjectData(); + const qbs::ProjectData projectData = m_qbsProject.isValid() + ? m_qbsProject.projectData() : qbs::ProjectData(); QStringList designerImportPaths; foreach (const qbs::ProductData &product, projectData.allProducts()) { designerImportPaths << product.properties() @@ -200,7 +370,7 @@ QVariant QbsProject::additionalData(Id id, const Target *target) const } return designerImportPaths; } - return Project::additionalData(id, target); + return BuildSystem::additionalData(id); } ProjectExplorer::DeploymentKnowledge QbsProject::deploymentKnowledge() const @@ -208,7 +378,7 @@ ProjectExplorer::DeploymentKnowledge QbsProject::deploymentKnowledge() const return DeploymentKnowledge::Perfect; } -QStringList QbsProject::filesGeneratedFrom(const QString &sourceFile) const +QStringList QbsBuildSystem::filesGeneratedFrom(const QString &sourceFile) const { QStringList generated; foreach (const qbs::ProductData &data, m_projectData.allProducts()) @@ -216,12 +386,12 @@ QStringList QbsProject::filesGeneratedFrom(const QString &sourceFile) const return generated; } -bool QbsProject::isProjectEditable() const +bool QbsBuildSystem::isProjectEditable() const { return m_qbsProject.isValid() && !isParsing() && !BuildManager::isBuilding(); } -bool QbsProject::ensureWriteableQbsFile(const QString &file) +bool QbsBuildSystem::ensureWriteableQbsFile(const QString &file) { // Ensure that the file is not read only QFileInfo fi(file); @@ -242,9 +412,9 @@ bool QbsProject::ensureWriteableQbsFile(const QString &file) return true; } -bool QbsProject::addFilesToProduct(const QStringList &filePaths, - const qbs::ProductData productData, - const qbs::GroupData groupData, QStringList *notAdded) +bool QbsBuildSystem::addFilesToProduct(const QStringList &filePaths, + const qbs::ProductData productData, + const qbs::GroupData groupData, QStringList *notAdded) { QTC_ASSERT(m_qbsProject.isValid(), return false); QStringList allPaths = groupData.allFilePaths(); @@ -267,10 +437,10 @@ bool QbsProject::addFilesToProduct(const QStringList &filePaths, return notAdded->isEmpty(); } -RemovedFilesFromProject QbsProject::removeFilesFromProduct(const QStringList &filePaths, - const qbs::ProductData &productData, - const qbs::GroupData &groupData, - QStringList *notRemoved) +RemovedFilesFromProject QbsBuildSystem::removeFilesFromProduct(const QStringList &filePaths, + const qbs::ProductData &productData, + const qbs::GroupData &groupData, + QStringList *notRemoved) { QTC_ASSERT(m_qbsProject.isValid(), return RemovedFilesFromProject::Error); @@ -313,9 +483,9 @@ RemovedFilesFromProject QbsProject::removeFilesFromProduct(const QStringList &fi return RemovedFilesFromProject::Ok; } -bool QbsProject::renameFileInProduct(const QString &oldPath, const QString &newPath, - const qbs::ProductData productData, - const qbs::GroupData groupData) +bool QbsBuildSystem::renameFileInProduct(const QString &oldPath, const QString &newPath, + const qbs::ProductData productData, + const qbs::GroupData groupData) { if (newPath.isEmpty()) return false; @@ -326,7 +496,7 @@ bool QbsProject::renameFileInProduct(const QString &oldPath, const QString &newP } qbs::ProductData newProductData; foreach (const qbs::ProductData &p, m_projectData.allProducts()) { - if (uniqueProductName(p) == uniqueProductName(productData)) { + if (QbsProject::uniqueProductName(p) == QbsProject::uniqueProductName(productData)) { newProductData = p; break; } @@ -365,8 +535,8 @@ static qbs::AbstractJob *doBuildOrClean(const qbs::Project &project, } template<typename Options> -qbs::AbstractJob *QbsProject::buildOrClean(const Options &opts, const QStringList &productNames, - QString &error) +qbs::AbstractJob *QbsBuildSystem::buildOrClean(const Options &opts, const QStringList &productNames, + QString &error) { QTC_ASSERT(qbsProject().isValid(), return nullptr); QTC_ASSERT(!isParsing(), return nullptr); @@ -375,7 +545,7 @@ qbs::AbstractJob *QbsProject::buildOrClean(const Options &opts, const QStringLis foreach (const QString &productName, productNames) { bool found = false; foreach (const qbs::ProductData &data, qbsProjectData().allProducts()) { - if (uniqueProductName(data) == productName) { + if (QbsProject::uniqueProductName(data) == productName) { found = true; products.append(data); break; @@ -391,41 +561,41 @@ qbs::AbstractJob *QbsProject::buildOrClean(const Options &opts, const QStringLis return doBuildOrClean(qbsProject(), products, opts); } -qbs::BuildJob *QbsProject::build(const qbs::BuildOptions &opts, QStringList productNames, - QString &error) +qbs::BuildJob *QbsBuildSystem::build(const qbs::BuildOptions &opts, QStringList productNames, + QString &error) { return static_cast<qbs::BuildJob *>(buildOrClean(opts, productNames, error)); } -qbs::CleanJob *QbsProject::clean(const qbs::CleanOptions &opts, const QStringList &productNames, - QString &error) +qbs::CleanJob *QbsBuildSystem::clean(const qbs::CleanOptions &opts, const QStringList &productNames, + QString &error) { return static_cast<qbs::CleanJob *>(buildOrClean(opts, productNames, error)); } -qbs::InstallJob *QbsProject::install(const qbs::InstallOptions &opts) +qbs::InstallJob *QbsBuildSystem::install(const qbs::InstallOptions &opts) { if (!qbsProject().isValid()) return nullptr; return qbsProject().installAllProducts(opts); } -QString QbsProject::profileForTarget(const Target *t) const +QString QbsBuildSystem::profile() const { - return QbsManager::profileForKit(t->kit()); + return QbsManager::profileForKit(target()->kit()); } -qbs::Project QbsProject::qbsProject() const +qbs::Project QbsBuildSystem::qbsProject() const { return m_qbsProject; } -qbs::ProjectData QbsProject::qbsProjectData() const +qbs::ProjectData QbsBuildSystem::qbsProjectData() const { return m_projectData; } -bool QbsProject::checkCancelStatus() +bool QbsBuildSystem::checkCancelStatus() { const CancelStatus cancelStatus = m_cancelStatus; m_cancelStatus = CancelStatusNone; @@ -439,7 +609,7 @@ bool QbsProject::checkCancelStatus() return true; } -void QbsProject::updateAfterParse() +void QbsBuildSystem::updateAfterParse() { qCDebug(qbsPmLog) << "Updating data after parse"; OpTimer opTimer("updateAfterParse"); @@ -448,27 +618,24 @@ void QbsProject::updateAfterParse() updateBuildTargetData(); updateCppCodeModel(); updateQmlJsCodeModel(); - emit fileListChanged(); + emit project()->fileListChanged(); m_envCache.clear(); - emit dataChanged(); } -void QbsProject::delayedUpdateAfterParse() +void QbsBuildSystem::delayedUpdateAfterParse() { - QTimer::singleShot(0, this, &QbsProject::updateAfterParse); + QTimer::singleShot(0, this, &QbsBuildSystem::updateAfterParse); } -void QbsProject::updateProjectNodes() +void QbsBuildSystem::updateProjectNodes() { OpTimer opTimer("updateProjectNodes"); rebuildProjectTree(); } -FilePath QbsProject::installRoot() +FilePath QbsBuildSystem::installRoot() { - if (!activeTarget()) - return FilePath(); - const auto dc = activeTarget()->activeDeployConfiguration(); + const auto dc = target()->activeDeployConfiguration(); if (dc) { const QList<BuildStep *> steps = dc->stepList()->steps(); for (const BuildStep * const step : steps) { @@ -478,15 +645,11 @@ FilePath QbsProject::installRoot() return FilePath::fromString(qbsInstallStep->installRoot()); } } - const auto * const bc - = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration()); - if (!bc) - return FilePath(); - const QbsBuildStep * const buildStep = bc->qbsStep(); + const QbsBuildStep * const buildStep = m_buildConfiguration->qbsStep(); return buildStep && buildStep->install() ? buildStep->installRoot() : FilePath(); } -void QbsProject::handleQbsParsingDone(bool success) +void QbsBuildSystem::handleQbsParsingDone(bool success) { QTC_ASSERT(m_qbsProjectParser, return); QTC_ASSERT(m_qbsUpdateFutureInterface, return); @@ -499,7 +662,6 @@ void QbsProject::handleQbsParsingDone(bool success) generateErrors(m_qbsProjectParser->error()); m_qbsProject = m_qbsProjectParser->qbsProject(); - m_qbsProjects.insert(activeTarget(), m_qbsProject); bool dataChanged = false; bool envChanged = m_lastParseEnv != m_qbsProjectParser->environment(); m_lastParseEnv = m_qbsProjectParser->environment(); @@ -528,14 +690,14 @@ void QbsProject::handleQbsParsingDone(bool success) m_guard = {}; } -void QbsProject::rebuildProjectTree() +void QbsBuildSystem::rebuildProjectTree() { std::unique_ptr<QbsRootProjectNode> newRoot = Internal::QbsNodeTreeBuilder::buildTree(this); - setDisplayName(newRoot ? newRoot->displayName() : projectFilePath().toFileInfo().completeBaseName()); - setRootProjectNode(std::move(newRoot)); + project()->setDisplayName(newRoot ? newRoot->displayName() : projectFilePath().toFileInfo().completeBaseName()); + project()->setRootProjectNode(std::move(newRoot)); } -void QbsProject::handleRuleExecutionDone() +void QbsBuildSystem::handleRuleExecutionDone() { qCDebug(qbsPmLog) << "Rule execution done"; @@ -553,28 +715,17 @@ void QbsProject::handleRuleExecutionDone() updateAfterParse(); } -void QbsProject::changeActiveTarget(Target *t) +void QbsBuildSystem::changeActiveTarget(Target *t) { - bool targetFound = false; - for (auto it = m_qbsProjects.begin(); it != m_qbsProjects.end(); ++it) { - qbs::Project &qbsProjectForTarget = it.value(); - if (it.key() == t) { - m_qbsProject = qbsProjectForTarget; - targetFound = true; - } else if (qbsProjectForTarget.isValid() && !BuildManager::isBuilding(it.key())) { - qbsProjectForTarget = qbs::Project(); - } - } - QTC_ASSERT(targetFound || !t, m_qbsProject = qbs::Project()); - if (t && t->isActive()) + if (t) delayParsing(); } -void QbsProject::startParsing() +void QbsBuildSystem::triggerParsing() { // Qbs does update the build graph during the build. So we cannot // start to parse while a build is running or we will lose information. - if (BuildManager::isBuilding(this)) { + if (BuildManager::isBuilding(project())) { scheduleParsing(); return; } @@ -582,12 +733,13 @@ void QbsProject::startParsing() parseCurrentBuildConfiguration(); } -void QbsProject::delayParsing() +void QbsBuildSystem::delayParsing() { - m_parsingDelay.start(); + if (m_buildConfiguration->isActive()) + m_parsingDelay.start(); } -void QbsProject::parseCurrentBuildConfiguration() +void QbsBuildSystem::parseCurrentBuildConfiguration() { m_parsingScheduled = false; if (m_cancelStatus == CancelStatusCancelingForReparse) @@ -598,12 +750,6 @@ void QbsProject::parseCurrentBuildConfiguration() // but of course not while canceling is in progress). QTC_ASSERT(m_cancelStatus == CancelStatusNone, return); - if (!activeTarget()) - return; - auto bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration()); - if (!bc) - return; - // New parse requests override old ones. // NOTE: We need to wait for the current operation to finish, since otherwise there could // be a conflict. Consider the case where the old qbs::ProjectSetupJob is writing @@ -616,28 +762,44 @@ void QbsProject::parseCurrentBuildConfiguration() return; } - parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString(), - bc->configurationName()); + QVariantMap config = m_buildConfiguration->qbsConfiguration(); + Environment env = m_buildConfiguration->environment(); + QString dir = m_buildConfiguration->buildDirectory().toString(); + + m_guard = guardParsingRun(); + + prepareForParsing(); + + m_parsingDelay.stop(); + + QTC_ASSERT(!m_qbsProjectParser, return); + m_qbsProjectParser = new QbsProjectParser(this, m_qbsUpdateFutureInterface); + + connect(m_qbsProjectParser, &QbsProjectParser::ruleExecutionDone, + this, &QbsBuildSystem::handleRuleExecutionDone); + connect(m_qbsProjectParser, &QbsProjectParser::done, + this, &QbsBuildSystem::handleQbsParsingDone); + + QbsManager::updateProfileIfNecessary(target()->kit()); + m_qbsProjectParser->parse(config, env, dir, m_buildConfiguration->configurationName()); } -void QbsProject::cancelParsing() +void QbsBuildSystem::cancelParsing() { QTC_ASSERT(m_qbsProjectParser, return); m_cancelStatus = CancelStatusCancelingAltoghether; m_qbsProjectParser->cancel(); } -void QbsProject::updateAfterBuild() +void QbsBuildSystem::updateAfterBuild() { OpTimer opTimer("updateAfterBuild"); QTC_ASSERT(m_qbsProject.isValid(), return); const qbs::ProjectData &projectData = m_qbsProject.projectData(); if (projectData == m_projectData) { - if (activeTarget()) { - DeploymentData deploymentData = activeTarget()->deploymentData(); - deploymentData.setLocalInstallRoot(installRoot()); - activeTarget()->setDeploymentData(deploymentData); - } + DeploymentData deploymentDataTmp = deploymentData(); + deploymentDataTmp.setLocalInstallRoot(installRoot()); + setDeploymentData(deploymentDataTmp); return; } qCDebug(qbsPmLog) << "Updating data after build"; @@ -649,29 +811,9 @@ void QbsProject::updateAfterBuild() updateCppCodeModel(); } m_envCache.clear(); - emit dataChanged(); } -void QbsProject::registerQbsProjectParser(QbsProjectParser *p) -{ - m_parsingDelay.stop(); - - if (m_qbsProjectParser) { - m_qbsProjectParser->disconnect(this); - m_qbsProjectParser->deleteLater(); - } - - m_qbsProjectParser = p; - - if (p) { - connect(m_qbsProjectParser, &QbsProjectParser::ruleExecutionDone, - this, &QbsProject::handleRuleExecutionDone); - connect(m_qbsProjectParser, &QbsProjectParser::done, - this, &QbsProject::handleQbsParsingDone); - } -} - -void QbsProject::generateErrors(const qbs::ErrorInfo &e) +void QbsBuildSystem::generateErrors(const qbs::ErrorInfo &e) { foreach (const qbs::ErrorItem &item, e.items()) TaskHub::addTask(Task::Error, item.description(), @@ -697,24 +839,11 @@ void QbsProject::configureAsExampleProject() } } setup(infoList); - prepareForParsing(); -} - -void QbsProject::parse(const QVariantMap &config, const Environment &env, const QString &dir, - const QString &configName) -{ - m_guard = guardParsingRun(); - - prepareForParsing(); - QTC_ASSERT(!m_qbsProjectParser, return); - - registerQbsProjectParser(new QbsProjectParser(this, m_qbsUpdateFutureInterface)); - - QbsManager::updateProfileIfNecessary(activeTarget()->kit()); - m_qbsProjectParser->parse(config, env, dir, configName); + if (activeTarget()) + static_cast<QbsBuildSystem *>(activeTarget()->buildSystem())->prepareForParsing(); } -void QbsProject::prepareForParsing() +void QbsBuildSystem::prepareForParsing() { TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); if (m_qbsUpdateFutureInterface) { @@ -727,11 +856,11 @@ void QbsProject::prepareForParsing() m_qbsUpdateFutureInterface = new QFutureInterface<bool>(); m_qbsUpdateFutureInterface->setProgressRange(0, 0); ProgressManager::addTask(m_qbsUpdateFutureInterface->future(), - tr("Reading Project \"%1\"").arg(displayName()), "Qbs.QbsEvaluate"); + tr("Reading Project \"%1\"").arg(project()->displayName()), "Qbs.QbsEvaluate"); m_qbsUpdateFutureInterface->reportStarted(); } -void QbsProject::updateDocuments(const std::set<QString> &files) +void QbsBuildSystem::updateDocuments(const std::set<QString> &files) { OpTimer opTimer("updateDocuments"); @@ -742,7 +871,7 @@ void QbsProject::updateDocuments(const std::set<QString> &files) [buildDir](const FilePath &p) { return !p.isChildOf(buildDir); }); - setExtraProjectFiles(nonBuildDirFilePaths); + project()->setExtraProjectFiles(nonBuildDirFilePaths); } static QString getMimeType(const qbs::ArtifactData &sourceFile) @@ -870,21 +999,20 @@ static void getExpandedCompilerFlags(QStringList &cFlags, QStringList &cxxFlags, } } -void QbsProject::updateCppCodeModel() +void QbsBuildSystem::updateCppCodeModel() { OpTimer optimer("updateCppCodeModel"); if (!m_projectData.isValid()) return; - QList<ProjectExplorer::ExtraCompilerFactory *> factories = - ProjectExplorer::ExtraCompilerFactory::extraCompilerFactories(); + const QList<ExtraCompilerFactory *> factories = ExtraCompilerFactory::extraCompilerFactories(); const auto factoriesBegin = factories.constBegin(); const auto factoriesEnd = factories.constEnd(); qDeleteAll(m_extraCompilers); m_extraCompilers.clear(); - QtSupport::CppKitInfo kitInfo(this); + QtSupport::CppKitInfo kitInfo(project()); QTC_ASSERT(kitInfo.isValid(), return); RawProjectParts rpps; @@ -959,7 +1087,7 @@ void QbsProject::updateCppCodeModel() rpp.setDisplayName(grp.name()); rpp.setProjectFileLocation(grp.location().filePath(), grp.location().line(), grp.location().column()); - rpp.setBuildSystemTarget(uniqueProductName(prd)); + rpp.setBuildSystemTarget(QbsProject::uniqueProductName(prd)); rpp.setBuildTargetType(prd.isRunnable() ? ProjectExplorer::BuildTargetType::Executable : ProjectExplorer::BuildTargetType::Library); @@ -996,7 +1124,7 @@ void QbsProject::updateCppCodeModel() return Utils::FilePath::fromString(s); }); m_extraCompilers.append((*i)->create( - this, FilePath::fromString(source.filePath()), fileNames)); + project(), FilePath::fromString(source.filePath()), fileNames)); } } } @@ -1038,10 +1166,10 @@ void QbsProject::updateCppCodeModel() } CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); - m_cppCodeModelUpdater->update({this, kitInfo, activeParseEnvironment(), rpps}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), rpps}); } -void QbsProject::updateQmlJsCodeModel() +void QbsBuildSystem::updateQmlJsCodeModel() { OpTimer optimer("updateQmlJsCodeModel"); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); @@ -1049,7 +1177,7 @@ void QbsProject::updateQmlJsCodeModel() return; QmlJS::ModelManagerInterface::ProjectInfo projectInfo = - modelManager->defaultProjectInfoForProject(this); + modelManager->defaultProjectInfoForProject(project()); foreach (const qbs::ProductData &product, m_projectData.allProducts()) { static const QString propertyName = QLatin1String("qmlImportPaths"); foreach (const QString &path, product.properties().value(propertyName).toStringList()) { @@ -1058,12 +1186,12 @@ void QbsProject::updateQmlJsCodeModel() } } - setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID, + project()->setProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID, !projectInfo.sourceFiles.isEmpty()); - modelManager->updateProjectInfo(projectInfo, this); + modelManager->updateProjectInfo(projectInfo, project()); } -void QbsProject::updateApplicationTargets() +void QbsBuildSystem::updateApplicationTargets() { QList<BuildTargetInfo> applications; foreach (const qbs::ProductData &productData, m_projectData.allProducts()) { @@ -1125,11 +1253,10 @@ void QbsProject::updateApplicationTargets() applications.append(bti); } - if (activeTarget()) - activeTarget()->setApplicationTargets(applications); + setApplicationTargets(applications); } -void QbsProject::updateDeploymentInfo() +void QbsBuildSystem::updateDeploymentInfo() { DeploymentData deploymentData; if (m_qbsProject.isValid()) { @@ -1139,11 +1266,10 @@ void QbsProject::updateDeploymentInfo() } } deploymentData.setLocalInstallRoot(installRoot()); - if (activeTarget()) - activeTarget()->setDeploymentData(deploymentData); + setDeploymentData(deploymentData); } -void QbsProject::updateBuildTargetData() +void QbsBuildSystem::updateBuildTargetData() { OpTimer optimer("updateBuildTargetData"); updateApplicationTargets(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 56798792bf2..69d79c89ca1 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -41,12 +41,12 @@ #include <QHash> #include <QTimer> -namespace Core { class IDocument; } namespace CppTools { class CppProjectUpdater; } namespace QbsProjectManager { namespace Internal { +class QbsBuildConfiguration; class QbsProjectParser; class QbsProject : public ProjectExplorer::Project @@ -55,9 +55,43 @@ class QbsProject : public ProjectExplorer::Project public: explicit QbsProject(const Utils::FilePath &filename); - ~QbsProject() override; + ~QbsProject(); - QStringList filesGeneratedFrom(const QString &sourceFile) const override; + ProjectExplorer::ProjectImporter *projectImporter() const override; + + ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; + + void configureAsExampleProject() final; + + static QString uniqueProductName(const qbs::ProductData &product); + +private: + mutable ProjectExplorer::ProjectImporter *m_importer = nullptr; +}; + +class QbsBuildSystem : public ProjectExplorer::BuildSystem +{ + Q_OBJECT + +public: + explicit QbsBuildSystem(QbsBuildConfiguration *bc); + ~QbsBuildSystem() final; + + void triggerParsing() final; + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const final; + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notAdded = nullptr) final; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notRemoved = nullptr) final; + bool renameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) final; + + QStringList filesGeneratedFrom(const QString &sourceFile) const final; + QVariant additionalData(Core::Id id) const final; bool isProjectEditable() const; // qbs::ProductData and qbs::GroupData are held by the nodes in the project tree. @@ -81,39 +115,27 @@ public: static ProjectExplorer::FileType fileTypeFor(const QSet<QString> &tags); - QString profileForTarget(const ProjectExplorer::Target *t) const; + QString profile() const; void parseCurrentBuildConfiguration(); void scheduleParsing() { m_parsingScheduled = true; } bool parsingScheduled() const { return m_parsingScheduled; } void cancelParsing(); void updateAfterBuild(); - void registerQbsProjectParser(QbsProjectParser *p); - qbs::Project qbsProject() const; qbs::ProjectData qbsProjectData() const; void generateErrors(const qbs::ErrorInfo &e); - static QString uniqueProductName(const qbs::ProductData &product); - - void configureAsExampleProject() final; - void delayParsing(); -signals: - void dataChanged(); - private: + friend class QbsProject; void handleQbsParsingDone(bool success); void rebuildProjectTree(); void changeActiveTarget(ProjectExplorer::Target *t); - void startParsing(); - - void parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir, - const QString &configName); void prepareForParsing(); void updateDocuments(const std::set<QString> &files); @@ -129,19 +151,12 @@ private: void updateProjectNodes(); Utils::FilePath installRoot(); - void projectLoaded() override; - ProjectExplorer::ProjectImporter *projectImporter() const override; - QVariant additionalData(Core::Id id, const ProjectExplorer::Target *target) const final; - - ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - static bool ensureWriteableQbsFile(const QString &file); template<typename Options> qbs::AbstractJob *buildOrClean(const Options &opts, const QStringList &productNames, QString &error); - QHash<ProjectExplorer::Target *, qbs::Project> m_qbsProjects; - qbs::Project m_qbsProject; // for activeTarget() + qbs::Project m_qbsProject; qbs::ProjectData m_projectData; // Cached m_qbsProject.projectData() Utils::Environment m_lastParseEnv; @@ -158,15 +173,14 @@ private: CppTools::CppProjectUpdater *m_cppCodeModelUpdater = nullptr; - mutable ProjectExplorer::ProjectImporter *m_importer = nullptr; - QTimer m_parsingDelay; QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers; bool m_extraCompilersPending = false; QHash<QString, Utils::Environment> m_envCache; - ParseGuard m_guard; + ProjectExplorer::BuildSystem::ParseGuard m_guard; + QbsBuildConfiguration *m_buildConfiguration = nullptr; }; } // namespace Internal diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp index bc123b09c76..d7f860ec17d 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.cpp @@ -246,9 +246,9 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString * connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, this, &QbsProjectManagerPlugin::updateBuildActions); - connect(SessionManager::instance(), &SessionManager::projectAdded, - this, &QbsProjectManagerPlugin::projectWasAdded); - connect(SessionManager::instance(), &SessionManager::projectRemoved, + connect(SessionManager::instance(), &SessionManager::targetAdded, + this, &QbsProjectManagerPlugin::targetWasAdded); + connect(SessionManager::instance(), &SessionManager::targetRemoved, this, &QbsProjectManagerPlugin::updateBuildActions); connect(SessionManager::instance(), &SessionManager::startupProjectChanged, this, &QbsProjectManagerPlugin::updateReparseQbsAction); @@ -264,16 +264,14 @@ bool QbsProjectManagerPlugin::initialize(const QStringList &arguments, QString * void QbsProjectManagerPlugin::extensionsInitialized() { } -void QbsProjectManagerPlugin::projectWasAdded(Project *project) +void QbsProjectManagerPlugin::targetWasAdded(Target *target) { - auto qbsProject = qobject_cast<QbsProject *>(project); - - if (!qbsProject) + if (!qobject_cast<QbsProject *>(target->project())) return; - connect(qbsProject, &Project::parsingStarted, + connect(target, &Target::parsingStarted, this, &QbsProjectManagerPlugin::projectChanged); - connect(qbsProject, &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &QbsProjectManagerPlugin::projectChanged); } @@ -282,7 +280,8 @@ void QbsProjectManagerPlugin::updateContextActions() auto project = qobject_cast<Internal::QbsProject *>(ProjectTree::currentProject()); const Node *node = ProjectTree::currentNode(); bool isEnabled = !BuildManager::isBuilding(project) - && project && !project->isParsing() + && project && project->activeTarget() + && !project->activeTarget()->buildSystem()->isParsing() && node && node->isEnabled(); const bool isFile = project && node && node->asFileNode(); @@ -305,7 +304,8 @@ void QbsProjectManagerPlugin::updateReparseQbsAction() auto project = qobject_cast<QbsProject *>(SessionManager::startupProject()); m_reparseQbs->setEnabled(project && !BuildManager::isBuilding(project) - && !project->isParsing()); + && project && project->activeTarget() + && !project->activeTarget()->buildSystem()->isParsing()); } void QbsProjectManagerPlugin::updateBuildActions() @@ -334,7 +334,9 @@ void QbsProjectManagerPlugin::updateBuildActions() } if (QbsProject *editorProject = currentEditorProject()) { - enabled = !BuildManager::isBuilding(editorProject) && !editorProject->isParsing(); + enabled = !BuildManager::isBuilding(editorProject) + && editorProject->activeTarget() + && !editorProject->activeTarget()->buildSystem()->isParsing(); fileVisible = productNode || dynamic_cast<QbsProjectNode *>(parentProjectNode) || dynamic_cast<QbsGroupNode *>(parentProjectNode); @@ -567,12 +569,20 @@ void QbsProjectManagerPlugin::reparseProject(QbsProject *project) if (!project) return; + Target *t = project->activeTarget(); + if (!t) + return; + + QbsBuildSystem *bs = static_cast<QbsBuildSystem *>(t->buildSystem()); + if (!bs) + return; + // Qbs does update the build graph during the build. So we cannot // start to parse while a build is running or we will lose information. if (BuildManager::isBuilding(project)) - project->scheduleParsing(); + bs->scheduleParsing(); else - project->parseCurrentBuildConfiguration(); + bs->parseCurrentBuildConfiguration(); } void QbsProjectManagerPlugin::buildNamedProduct(QbsProject *project, const QString &product) diff --git a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h index 267b7777ae3..d237e82d82a 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h +++ b/src/plugins/qbsprojectmanager/qbsprojectmanagerplugin.h @@ -29,7 +29,7 @@ #include <extensionsystem/iplugin.h> #include <utils/parameteraction.h> -namespace ProjectExplorer { class Project; } +namespace ProjectExplorer { class Target; } namespace QbsProjectManager { namespace Internal { @@ -51,7 +51,7 @@ private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final; - void projectWasAdded(ProjectExplorer::Project *project); + void targetWasAdded(ProjectExplorer::Target *target); void projectChanged(); void buildFileContextMenu(); diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index 10196cbd37a..6e2c9f39368 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -48,11 +48,11 @@ namespace Internal { // QbsProjectParser: // -------------------------------------------------------------------- -QbsProjectParser::QbsProjectParser(QbsProject *project, QFutureInterface<bool> *fi) : +QbsProjectParser::QbsProjectParser(QbsBuildSystem *buildSystem, QFutureInterface<bool> *fi) : m_fi(fi) { - m_project = project->qbsProject(); - m_projectFilePath = project->projectFilePath().toString(); + m_project = buildSystem->qbsProject(); + m_projectFilePath = buildSystem->projectFilePath().toString(); auto * const watcher = new QFutureWatcher<bool>(this); connect(watcher, &QFutureWatcher<bool>::canceled, this, &QbsProjectParser::cancel); watcher->setFuture(fi->future()); diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.h b/src/plugins/qbsprojectmanager/qbsprojectparser.h index 37b9e5f6d27..c6353d3df4f 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.h +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.h @@ -35,15 +35,14 @@ namespace QbsProjectManager { namespace Internal { -class QbsProject; +class QbsBuildSystem; class QbsProjectParser : public QObject { Q_OBJECT public: - QbsProjectParser(QbsProjectManager::Internal::QbsProject *project, - QFutureInterface<bool> *fi); + QbsProjectParser(QbsBuildSystem *buildSystem, QFutureInterface<bool> *fi); ~QbsProjectParser() override; void parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir, diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp index 1f7a96eee55..0d152832279 100644 --- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp +++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp @@ -1018,8 +1018,12 @@ void InternalLibraryDetailsController::updateProFile() m_rootProjectPath = project->projectDirectory().toString(); + auto t = project->activeTarget(); + auto bs = dynamic_cast<QmakeBuildSystem *>(t ? t->buildSystem() : nullptr); + QTC_ASSERT(bs, return); + QDir rootDir(m_rootProjectPath); - foreach (QmakeProFile *proFile, project->rootProFile()->allProFiles()) { + foreach (QmakeProFile *proFile, bs->rootProFile()->allProFiles()) { QmakeProjectManager::ProjectType type = proFile->projectType(); if (type != ProjectType::SharedLibraryTemplate && type != ProjectType::StaticLibraryTemplate) continue; diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp index 346f1197828..3d14ff3d500 100644 --- a/src/plugins/qmakeprojectmanager/profileeditor.cpp +++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp @@ -38,6 +38,7 @@ #include <extensionsystem/pluginmanager.h> #include <qtsupport/qtsupportconstants.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/target.h> #include <projectexplorer/session.h> #include <texteditor/texteditoractionhandler.h> #include <texteditor/textdocument.h> @@ -85,8 +86,10 @@ QString ProFileEditorWidget::checkForPrfFile(const QString &baseName) const const FilePath projectFile = textDocument()->filePath(); const QmakePriFileNode *projectNode = nullptr; for (const Project * const project : SessionManager::projects()) { - if (project->isParsing()) - continue; + if (Target *t = project->activeTarget()) { + if (t->buildSystem()->isParsing()) + continue; + } projectNode = dynamic_cast<const QmakePriFileNode *>(project->rootProjectNode() ->findProjectNode([&projectFile](const ProjectNode *pn) { return pn->filePath() == projectFile; diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp index 7e90562c54b..193df6477ac 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.cpp @@ -108,6 +108,8 @@ enum { debug = 0 }; QmakeBuildConfiguration::QmakeBuildConfiguration(Target *target, Core::Id id) : BuildConfiguration(target, id) { + m_buildSystem = new QmakeBuildSystem(this); + connect(this, &BuildConfiguration::buildDirectoryChanged, this, &QmakeBuildConfiguration::emitProFileEvaluateNeeded); connect(this, &BuildConfiguration::environmentChanged, @@ -175,7 +177,10 @@ void QmakeBuildConfiguration::initialize() updateCacheAndEmitEnvironmentChanged(); } -QmakeBuildConfiguration::~QmakeBuildConfiguration() = default; +QmakeBuildConfiguration::~QmakeBuildConfiguration() +{ + delete m_buildSystem; +} QVariantMap QmakeBuildConfiguration::toMap() const { @@ -219,6 +224,11 @@ void QmakeBuildConfiguration::qtVersionsChanged(const QList<int> &,const QList<i emitProFileEvaluateNeeded(); } +BuildSystem *QmakeBuildConfiguration::buildSystem() const +{ + return m_buildSystem; +} + NamedWidget *QmakeBuildConfiguration::createConfigWidget() { return new QmakeProjectConfigWidget(this); @@ -255,8 +265,7 @@ void QmakeBuildConfiguration::setFileNodeBuild(FileNode *node) QString QmakeBuildConfiguration::makefile() const { - auto rootNode = dynamic_cast<QmakeProFileNode *>(target()->project()->rootProjectNode()); - return rootNode ? rootNode->makefile() : QString(); + return m_buildSystem->rootProFile()->singleVariableValue(Variable::Makefile); } BaseQtVersion::QmakeBuildConfigs QmakeBuildConfiguration::qmakeBuildConfiguration() const @@ -277,10 +286,7 @@ void QmakeBuildConfiguration::setQMakeBuildConfiguration(BaseQtVersion::QmakeBui void QmakeBuildConfiguration::emitProFileEvaluateNeeded() { - Target *t = target(); - Project *p = t->project(); - if (t->activeBuildConfiguration() == this && p->activeTarget() == t) - static_cast<QmakeProject *>(p)->scheduleAsyncUpdate(); + m_buildSystem->scheduleUpdateAllNowOrLater(); } QString QmakeBuildConfiguration::unalignedBuildDirWarning() @@ -341,6 +347,11 @@ QmakeMakeStep *QmakeBuildConfiguration::makeStep() const return nullptr; } +QmakeBuildSystem *QmakeBuildConfiguration::qmakeBuildSystem() const +{ + return m_buildSystem; +} + // Returns true if both are equal. QmakeBuildConfiguration::MakefileState QmakeBuildConfiguration::compareToImportFrom(const QString &makefile, QString *errorString) { diff --git a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h index 7fd4c7dfebc..5445c9ebc97 100644 --- a/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h +++ b/src/plugins/qmakeprojectmanager/qmakebuildconfiguration.h @@ -35,6 +35,7 @@ namespace ProjectExplorer { class FileNode; } namespace QmakeProjectManager { class QMakeStep; +class QmakeBuildSystem; class QmakeMakeStep; class QmakeProFileNode; @@ -46,6 +47,8 @@ public: QmakeBuildConfiguration(ProjectExplorer::Target *target, Core::Id id); ~QmakeBuildConfiguration() override; + ProjectExplorer::BuildSystem *buildSystem() const final; + void initialize() override; ProjectExplorer::NamedWidget *createConfigWidget() override; @@ -72,6 +75,8 @@ public: QMakeStep *qmakeStep() const; QmakeMakeStep *makeStep() const; + QmakeBuildSystem *qmakeBuildSystem() const; + QString makefile() const; enum MakefileState { MakefileMatches, MakefileForWrongProject, MakefileIncompatible, MakefileMissing }; @@ -125,6 +130,7 @@ private: QtSupport::BaseQtVersion::QmakeBuildConfigs m_qmakeBuildConfiguration; QmakeProFileNode *m_subNodeBuild = nullptr; ProjectExplorer::FileNode *m_fileNodeBuild = nullptr; + QmakeBuildSystem *m_buildSystem = nullptr; }; class QMAKEPROJECTMANAGER_EXPORT QmakeBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory diff --git a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp index 77aec206cfd..3de706a50fb 100644 --- a/src/plugins/qmakeprojectmanager/qmakemakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakemakestep.cpp @@ -48,7 +48,6 @@ #include <QDir> #include <QFileInfo> -using ExtensionSystem::PluginManager; using namespace ProjectExplorer; using namespace QmakeProjectManager; using namespace QmakeProjectManager::Internal; @@ -85,12 +84,12 @@ bool QmakeMakeStep::init() ProcessParameters *pp = processParameters(); pp->setMacroExpander(bc->macroExpander()); - QString workingDirectory; + Utils::FilePath workingDirectory; if (bc->subNodeBuild()) - workingDirectory = bc->subNodeBuild()->buildDir(); + workingDirectory = bc->subNodeBuild()->buildDir(bc); else - workingDirectory = bc->buildDirectory().toString(); - pp->setWorkingDirectory(Utils::FilePath::fromString(workingDirectory)); + workingDirectory = bc->buildDirectory(); + pp->setWorkingDirectory(workingDirectory); // If we are cleaning, then make can fail with a error code, but that doesn't mean // we should stop the clean queue @@ -117,13 +116,14 @@ bool QmakeMakeStep::init() if (makefile != "Makefile") makeCmd.addArgs({"-f", makefile}); - m_makeFileToCheck = QDir(workingDirectory).filePath(makefile); + m_makeFileToCheck = QDir(workingDirectory.toString()).filePath(makefile); } else { - if (!bc->makefile().isEmpty()) { - makeCmd.addArgs({"-f", bc->makefile()}); - m_makeFileToCheck = QDir(workingDirectory).filePath(bc->makefile()); + QString makefile = bc->makefile(); + if (!makefile.isEmpty()) { + makeCmd.addArgs({"-f", makefile}); + m_makeFileToCheck = QDir(workingDirectory.toString()).filePath(makefile); } else { - m_makeFileToCheck = QDir(workingDirectory).filePath("Makefile"); + m_makeFileToCheck = QDir(workingDirectory.toString()).filePath("Makefile"); } } @@ -168,7 +168,9 @@ bool QmakeMakeStep::init() appendOutputParser(new QMakeParser); // make may cause qmake to be run, add last to make sure // it has a low priority. - m_scriptTarget = (static_cast<QmakeProject *>(bc->target()->project())->rootProjectNode()->projectType() == ProjectType::ScriptTemplate); + auto rootNode = dynamic_cast<QmakeProFileNode *>(bc->project()->rootProjectNode()); + QTC_ASSERT(rootNode, return false); + m_scriptTarget = rootNode->projectType() == ProjectType::ScriptTemplate; m_unalignedBuildDir = !bc->isBuildDirAtSafeLocation(); // A user doing "make clean" indicates they want a proper rebuild, so make sure to really diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 59c650e675f..08cd2bc573b 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -47,6 +47,8 @@ using namespace ProjectExplorer; using namespace Utils; +using namespace QmakeProjectManager::Internal; + namespace QmakeProjectManager { /*! @@ -54,21 +56,26 @@ namespace QmakeProjectManager { Implements abstract ProjectNode class */ -QmakePriFileNode::QmakePriFileNode(QmakeProject *project, QmakeProFileNode *qmakeProFileNode, +QmakePriFileNode::QmakePriFileNode(QmakeBuildSystem *buildSystem, QmakeProFileNode *qmakeProFileNode, const FilePath &filePath, QmakePriFile *pf) : ProjectNode(filePath), - m_project(project), + m_buildSystem(buildSystem), m_qmakeProFileNode(qmakeProFileNode), m_qmakePriFile(pf) { } QmakePriFile *QmakePriFileNode::priFile() const { - if (!m_project->isParsing()) + if (!m_buildSystem) + return nullptr; + + if (!m_buildSystem->isParsing()) return m_qmakePriFile; + // During a parsing run the qmakePriFile tree will change, so search for the PriFile and // do not depend on the cached value. - return m_project->rootProFile()->findPriFile(filePath()); + // NOTE: This would go away if the node tree would be per-buildsystem + return m_buildSystem->rootProFile()->findPriFile(filePath()); } bool QmakePriFileNode::deploysFolder(const QString &folder) const @@ -91,16 +98,21 @@ bool QmakeBuildSystem::supportsAction(Node *context, ProjectAction action, const || dynamic_cast<const ResourceEditor::ResourceTopLevelNode *>(node); } - const FolderNode *folderNode = n; - const QmakeProFileNode *proFileNode; - while (!(proFileNode = dynamic_cast<const QmakeProFileNode*>(folderNode))) { - folderNode = folderNode->parentFolderNode(); - QTC_ASSERT(folderNode, return false); + ProjectType t = ProjectType::Invalid; + const QmakeProFile *pro = nullptr; + if (hasParsingData()) { + const FolderNode *folderNode = n; + const QmakeProFileNode *proFileNode; + while (!(proFileNode = dynamic_cast<const QmakeProFileNode*>(folderNode))) { + folderNode = folderNode->parentFolderNode(); + QTC_ASSERT(folderNode, return false); + } + QTC_ASSERT(proFileNode, return false); + pro = proFileNode->proFile(); + t = pro->projectType(); } - QTC_ASSERT(proFileNode, return false); - const QmakeProFile *pro = proFileNode->proFile(); - switch (pro ? pro->projectType() : ProjectType::Invalid) { + switch (t) { case ProjectType::ApplicationTemplate: case ProjectType::StaticLibraryTemplate: case ProjectType::SharedLibraryTemplate: @@ -287,8 +299,8 @@ FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringL \class QmakeProFileNode Implements abstract ProjectNode class */ -QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FilePath &filePath, QmakeProFile *pf) : - QmakePriFileNode(project, this, filePath, pf) +QmakeProFileNode::QmakeProFileNode(QmakeBuildSystem *buildSystem, const FilePath &filePath, QmakeProFile *pf) : + QmakePriFileNode(buildSystem, this, filePath, pf) { if (projectType() == ProjectType::ApplicationTemplate) { setProductType(ProductType::App); @@ -302,7 +314,7 @@ QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FilePath &filePa bool QmakeProFileNode::showInSimpleTree() const { - return showInSimpleTree(projectType()) || m_project->rootProjectNode() == this; + return showInSimpleTree(projectType()) || m_buildSystem->project()->rootProjectNode() == this; } QString QmakeProFileNode::buildKey() const @@ -407,7 +419,7 @@ bool QmakeProFileNode::setData(Core::Id role, const QVariant &value) const QmakeProFile *QmakeProFileNode::proFile() const { - return static_cast<QmakeProFile*>(QmakePriFileNode::priFile()); + return dynamic_cast<QmakeProFile*>(QmakePriFileNode::priFile()); } QString QmakeProFileNode::makefile() const @@ -469,19 +481,7 @@ QString QmakeProFileNode::singleVariableValue(const Variable var) const return values.isEmpty() ? QString() : values.first(); } -QString QmakeProFileNode::buildDir() const -{ - if (Target *target = m_project->activeTarget()) { - if (BuildConfiguration *bc = target->activeBuildConfiguration()) { - const QDir srcDirRoot(m_project->projectDirectory().toString()); - const QString relativeDir = srcDirRoot.relativeFilePath(filePath().parentDir().toString()); - return QDir::cleanPath(QDir(bc->buildDirectory().toString()).absoluteFilePath(relativeDir)); - } - } - return QString(); -} - -FilePath QmakeProFileNode::buildDir(QmakeBuildConfiguration *bc) const +FilePath QmakeProFileNode::buildDir(BuildConfiguration *bc) const { const QmakeProFile *pro = proFile(); return pro ? pro->buildDir(bc) : FilePath(); @@ -500,9 +500,4 @@ TargetInformation QmakeProFileNode::targetInformation() const return proFile() ? proFile()->targetInformation() : TargetInformation(); } -QmakeBuildSystem::QmakeBuildSystem(Project *project) - : BuildSystem(project) -{ -} - } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 473f4006208..1332574bdbc 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -37,36 +37,11 @@ namespace QmakeProjectManager { class QmakeProFileNode; class QmakeProject; -class QmakeBuildSystem : public ProjectExplorer::BuildSystem -{ -public: - explicit QmakeBuildSystem(ProjectExplorer::Project *project); - - bool supportsAction(ProjectExplorer::Node *context, - ProjectExplorer::ProjectAction action, - const ProjectExplorer::Node *node) const override; - - bool addFiles(ProjectExplorer::Node *context, - const QStringList &filePaths, - QStringList *notAdded = nullptr) override; - ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, - const QStringList &filePaths, - QStringList *notRemoved = nullptr) override; - bool deleteFiles(ProjectExplorer::Node *context, - const QStringList &filePaths) override; - bool canRenameFile(ProjectExplorer::Node *context, - const QString &filePath, const QString &newFilePath) override; - bool renameFile(ProjectExplorer::Node *context, - const QString &filePath, const QString &newFilePath) override; - bool addDependencies(ProjectExplorer::Node *context, - const QStringList &dependencies) override; -}; - // Implements ProjectNode for qmake .pri files class QMAKEPROJECTMANAGER_EXPORT QmakePriFileNode : public ProjectExplorer::ProjectNode { public: - QmakePriFileNode(QmakeProject *project, QmakeProFileNode *qmakeProFileNode, + QmakePriFileNode(QmakeBuildSystem *buildSystem, QmakeProFileNode *qmakeProFileNode, const Utils::FilePath &filePath, QmakePriFile *pf); QmakePriFile *priFile() const; @@ -85,7 +60,7 @@ public: QmakeProFileNode *proFileNode() const; protected: - QmakeProject *m_project = nullptr; + QPointer<QmakeBuildSystem> m_buildSystem; private: QmakeProFileNode *m_qmakeProFileNode = nullptr; @@ -96,7 +71,7 @@ private: class QMAKEPROJECTMANAGER_EXPORT QmakeProFileNode : public QmakePriFileNode { public: - QmakeProFileNode(QmakeProject *project, const Utils::FilePath &filePath, QmakeProFile *pf); + QmakeProFileNode(QmakeBuildSystem *buildSystem, const Utils::FilePath &filePath, QmakeProFile *pf); QmakeProFile *proFile() const; @@ -122,8 +97,7 @@ public: bool setData(Core::Id role, const QVariant &value) const override; QmakeProjectManager::ProjectType projectType() const; - QString buildDir() const; - Utils::FilePath buildDir(QmakeBuildConfiguration *bc) const; + Utils::FilePath buildDir(ProjectExplorer::BuildConfiguration *bc) const; QStringList variableValue(const Variable var) const; QString singleVariableValue(const Variable var) const; diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index e02c037aa1d..18a73f768fb 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -42,6 +42,8 @@ using namespace ProjectExplorer; using namespace QtSupport; using namespace Utils; +using namespace QmakeProjectManager::Internal; + namespace { // Static cached data in struct QmakeStaticData providing information and icons @@ -128,7 +130,10 @@ void clearQmakeStaticData() namespace QmakeProjectManager { -static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const FilePathList &toExclude) +static void createTree(QmakeBuildSystem *buildSystem, + const QmakePriFile *pri, + QmakePriFileNode *node, + const FilePathList &toExclude) { QTC_ASSERT(pri, return); QTC_ASSERT(node, return); @@ -166,7 +171,7 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi if (type == FileType::Resource) { for (const auto &file : newFilePaths) { - auto vfs = pri->project()->qmakeVfs(); + auto vfs = buildSystem->qmakeVfs(); QString contents; QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption @@ -223,26 +228,26 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi for (QmakePriFile *c : pri->children()) { std::unique_ptr<QmakePriFileNode> newNode; if (auto pf = dynamic_cast<QmakeProFile *>(c)) - newNode = std::make_unique<QmakeProFileNode>(c->project(), c->filePath(), pf); + newNode = std::make_unique<QmakeProFileNode>(c->buildSystem(), c->filePath(), pf); else - newNode = std::make_unique<QmakePriFileNode>(c->project(), node->proFileNode(), c->filePath(), c); - createTree(c, newNode.get(), toExclude); + newNode = std::make_unique<QmakePriFileNode>(c->buildSystem(), node->proFileNode(), c->filePath(), c); + createTree(buildSystem, c, newNode.get(), toExclude); node->addNode(std::move(newNode)); } } -std::unique_ptr<QmakeProFileNode> QmakeNodeTreeBuilder::buildTree(QmakeProject *project) +std::unique_ptr<QmakeProFileNode> QmakeNodeTreeBuilder::buildTree(QmakeBuildSystem *buildSystem) { // Remove qmake implementation details that litter up the project data: - Target *t = project->activeTarget(); - Kit *k = t ? t->kit() : KitManager::defaultKit(); - BaseQtVersion *qt = k ? QtKitAspect::qtVersion(k) : nullptr; + Target *t = buildSystem->target(); + BaseQtVersion *qt = QtKitAspect::qtVersion(t->kit()); const FilePathList toExclude = qt ? qt->directoriesToIgnoreInProjectTree() : FilePathList(); - auto root = std::make_unique<QmakeProFileNode>(project, project->projectFilePath(), - project->rootProFile()); - createTree(project->rootProFile(), root.get(), toExclude); + auto root = std::make_unique<QmakeProFileNode>(buildSystem, + buildSystem->projectFilePath(), + buildSystem->rootProFile()); + createTree(buildSystem, buildSystem->rootProFile(), root.get(), toExclude); return root; } diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.h b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.h index be3240da3c4..267331d574a 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.h +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.h @@ -28,16 +28,14 @@ #include "qmakeprojectmanager_global.h" #include "qmakeparsernodes.h" #include "qmakenodes.h" - -namespace Utils { class FilePath; } -namespace ProjectExplorer { class RunConfiguration; } +#include "qmakeproject.h" namespace QmakeProjectManager { class QmakeNodeTreeBuilder { public: - static std::unique_ptr<QmakeProFileNode> buildTree(QmakeProject *project); + static std::unique_ptr<QmakeProFileNode> buildTree(QmakeBuildSystem *buildSystem); }; } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 0ae1c3ae1a1..945ba7a9401 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -162,12 +162,12 @@ public: } // namespace Internal -QmakePriFile::QmakePriFile(QmakeProject *project, QmakeProFile *qmakeProFile, +QmakePriFile::QmakePriFile(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile, const FilePath &filePath) : - m_project(project), + m_buildSystem(buildSystem), m_qmakeProFile(qmakeProFile) { - Q_ASSERT(project); + Q_ASSERT(buildSystem); m_priFileDocument = std::make_unique<QmakePriFileDocument>(this, filePath); Core::DocumentManager::addDocument(m_priFileDocument.get()); } @@ -194,7 +194,7 @@ QmakePriFile *QmakePriFile::parent() const QmakeProject *QmakePriFile::project() const { - return m_project; + return static_cast<QmakeProject *>(m_buildSystem->project()); } QVector<QmakePriFile *> QmakePriFile::children() const @@ -255,7 +255,7 @@ QmakePriFile::~QmakePriFile() void QmakePriFile::scheduleUpdate() { QtSupport::ProFileCacheManager::instance()->discardFile( - filePath().toString(), m_project->qmakeVfs()); + filePath().toString(), m_buildSystem->qmakeVfs()); m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater); } @@ -399,8 +399,8 @@ void QmakePriFile::watchFolders(const QSet<FilePath> &folders) QSet<QString> toWatch = folderStrings; toWatch.subtract(m_watchedFolders); - m_project->unwatchFolders(Utils::toList(toUnwatch), this); - m_project->watchFolders(Utils::toList(toWatch), this); + m_buildSystem->unwatchFolders(Utils::toList(toUnwatch), this); + m_buildSystem->watchFolders(Utils::toList(toWatch), this); m_watchedFolders = folderStrings; } @@ -418,6 +418,11 @@ QString QmakePriFile::continuationIndent() const return QString(tabSettings.m_indentSize, ' '); } +QmakeBuildSystem *QmakePriFile::buildSystem() const +{ + return m_buildSystem; +} + bool QmakePriFile::knowsFile(const FilePath &filePath) const { return m_recursiveEnumerateFiles.contains(filePath); @@ -710,8 +715,9 @@ bool QmakePriFile::saveModifiedEditors() // force instant reload of ourselves QtSupport::ProFileCacheManager::instance()->discardFile( - filePath().toString(), m_project->qmakeVfs()); - QmakeProject::notifyChanged(filePath()); + filePath().toString(), m_buildSystem->qmakeVfs()); + + m_buildSystem->notifyChanged(filePath()); return true; } @@ -784,7 +790,7 @@ QPair<ProFile *, QStringList> QmakePriFile::readProFile() &contents, &m_textFormat, &errorMsg) != TextFileFormat::ReadSuccess) { - QmakeProject::proFileParseError(errorMsg); + QmakeBuildSystem::proFileParseError(errorMsg); return qMakePair(includeFile, lines); } lines = contents.split('\n'); @@ -1171,8 +1177,8 @@ QByteArray QmakeProFile::cxxDefines() const \class QmakeProFile Implements abstract ProjectNode class */ -QmakeProFile::QmakeProFile(QmakeProject *project, const FilePath &filePath) : - QmakePriFile(project, this, filePath) +QmakeProFile::QmakeProFile(QmakeBuildSystem *buildSystem, const FilePath &filePath) : + QmakePriFile(buildSystem, this, filePath) { // The lifetime of the m_parserFutureWatcher is shorter // than of this, so this is all safe @@ -1245,10 +1251,7 @@ void QmakeProFile::setParseInProgressRecursive(bool b) void QmakeProFile::setParseInProgress(bool b) { - if (m_parseInProgress == b) - return; m_parseInProgress = b; - emit m_project->proFileUpdated(this, m_validParse, m_parseInProgress); } // Do note the absence of signal emission, always set validParse @@ -1275,12 +1278,12 @@ bool QmakeProFile::parseInProgress() const void QmakeProFile::scheduleUpdate(QmakeProFile::AsyncUpdateDelay delay) { setParseInProgressRecursive(true); - m_project->scheduleAsyncUpdate(this, delay); + m_buildSystem->scheduleAsyncUpdateFile(this, delay); } void QmakeProFile::asyncUpdate() { - m_project->incrementPendingEvaluateFutures(); + m_buildSystem->incrementPendingEvaluateFutures(); setupReader(); if (!includedInExactParse()) m_readerExact->setExact(false); @@ -1307,11 +1310,11 @@ QmakeEvalInput QmakeProFile::evalInput() const input.projectDir = directoryPath().toString(); input.projectFilePath = filePath(); input.buildDirectory = buildDir(); - input.sysroot = FilePath::fromString(m_project->qmakeSysroot()); + input.sysroot = FilePath::fromString(m_buildSystem->qmakeSysroot()); input.readerExact = m_readerExact; input.readerCumulative = m_readerCumulative; - input.qmakeGlobals = m_project->qmakeGlobals(); - input.qmakeVfs = m_project->qmakeVfs(); + input.qmakeGlobals = m_buildSystem->qmakeGlobals(); + input.qmakeVfs = m_buildSystem->qmakeVfs(); return input; } @@ -1320,9 +1323,9 @@ void QmakeProFile::setupReader() Q_ASSERT(!m_readerExact); Q_ASSERT(!m_readerCumulative); - m_readerExact = m_project->createProFileReader(this); + m_readerExact = m_buildSystem->createProFileReader(this); - m_readerCumulative = m_project->createProFileReader(this); + m_readerCumulative = m_buildSystem->createProFileReader(this); m_readerCumulative->setCumulative(true); } @@ -1588,7 +1591,7 @@ void QmakeProFile::applyAsyncEvaluate() { if (m_parseFutureWatcher.isFinished()) applyEvaluate(m_parseFutureWatcher.result()); - m_project->decrementPendingEvaluateFutures(); + m_buildSystem->decrementPendingEvaluateFutures(); } bool sortByParserNodes(Node *a, Node *b) @@ -1602,23 +1605,24 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult) if (!m_readerExact) return; - if (m_project->asyncUpdateState() == QmakeProject::ShuttingDown) { + if (m_buildSystem->asyncUpdateState() == QmakeBuildSystem::ShuttingDown) { cleanupProFileReaders(); return; } foreach (const QString &error, evalResult->errors) - QmakeProject::proFileParseError(error); + QmakeBuildSystem::proFileParseError(error); // we are changing what is executed in that case - if (result->state == QmakeEvalResult::EvalFail || m_project->wasEvaluateCanceled()) { + if (result->state == QmakeEvalResult::EvalFail || m_buildSystem->wasEvaluateCanceled()) { m_validParse = false; cleanupProFileReaders(); setValidParseRecursive(false); setParseInProgressRecursive(false); if (result->state == QmakeEvalResult::EvalFail) { - QmakeProject::proFileParseError(QCoreApplication::translate("QmakeProFile", "Error while parsing file %1. Giving up.") + QmakeBuildSystem::proFileParseError( + QCoreApplication::translate("QmakeProFile", "Error while parsing file %1. Giving up.") .arg(filePath().toUserOutput())); if (m_projectType == ProjectType::Invalid) return; @@ -1678,14 +1682,14 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult) continue; // Do nothing if (priFile->proFile) { - auto *qmakePriFileNode = new QmakePriFile(m_project, this, priFile->name); + auto *qmakePriFileNode = new QmakePriFile(m_buildSystem, this, priFile->name); pn->addChild(qmakePriFileNode); qmakePriFileNode->setIncludedInExactParse( (result->state == QmakeEvalResult::EvalOk) && pn->includedInExactParse()); qmakePriFileNode->update(priFile->result); toCompare.append(qMakePair(qmakePriFileNode, priFile)); } else { - auto *qmakeProFileNode = new QmakeProFile(m_project, priFile->name); + auto *qmakeProFileNode = new QmakeProFile(m_buildSystem, priFile->name); pn->addChild(qmakeProFileNode); qmakeProFileNode->setIncludedInExactParse( result->exactSubdirs.contains(qmakeProFileNode->filePath()) @@ -1765,9 +1769,9 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult) void QmakeProFile::cleanupProFileReaders() { if (m_readerExact) - m_project->destroyProFileReader(m_readerExact); + m_buildSystem->destroyProFileReader(m_readerExact); if (m_readerCumulative) - m_project->destroyProFileReader(m_readerCumulative); + m_buildSystem->destroyProFileReader(m_readerCumulative); m_readerExact = nullptr; m_readerCumulative = nullptr; @@ -2017,15 +2021,16 @@ FilePath QmakeProFile::sourceDir() const return directoryPath(); } -FilePath QmakeProFile::buildDir(QmakeBuildConfiguration *bc) const +FilePath QmakeProFile::buildDir(BuildConfiguration *bc) const { - const QDir srcDirRoot = QDir(m_project->projectDirectory().toString()); + if (!bc) + bc = m_buildSystem->target()->activeBuildConfiguration(); + + const QDir srcDirRoot = QDir(m_buildSystem->projectDirectory().toString()); const QString relativeDir = srcDirRoot.relativeFilePath(directoryPath().toString()); - if (!bc && m_project->activeTarget()) - bc = static_cast<QmakeBuildConfiguration *>(m_project->activeTarget()->activeBuildConfiguration()); const QString buildConfigBuildDir = bc ? bc->buildDirectory().toString() : QString(); const QString buildDir = buildConfigBuildDir.isEmpty() - ? m_project->projectDirectory().toString() + ? m_buildSystem->projectDirectory().toString() : buildConfigBuildDir; return FilePath::fromString(QDir::cleanPath(QDir(buildDir).absoluteFilePath(relativeDir))); } @@ -2075,7 +2080,7 @@ void QmakeProFile::setupExtraCompiler(const FilePath &buildDir, for (const FilePath &fn : collectFiles(fileType)) { const FilePathList generated = generatedFiles(buildDir, fn, fileType); if (!generated.isEmpty()) - m_extraCompilers.append(factory->create(m_project, fn, generated)); + m_extraCompilers.append(factory->create(m_buildSystem->project(), fn, generated)); } } diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index 538d1a65e91..25dc5c5acf5 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -47,10 +47,10 @@ class FileSystemWatcher; } // namespace Utils; namespace QtSupport { class ProFileReader; } -namespace ProjectExplorer { class RunConfiguration; } namespace QmakeProjectManager { class QmakeBuildConfiguration; +class QmakeBuildSystem; class QmakeProFile; class QmakeProject; @@ -122,7 +122,7 @@ using SourceFiles = QSet<SourceFile>; class QMAKEPROJECTMANAGER_EXPORT QmakePriFile { public: - QmakePriFile(QmakeProject *project, QmakeProFile *qmakeProFile, const Utils::FilePath &filePath); + QmakePriFile(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile, const Utils::FilePath &filePath); virtual ~QmakePriFile(); Utils::FilePath filePath() const; @@ -178,6 +178,8 @@ public: void scheduleUpdate(); + QmakeBuildSystem *buildSystem() const; + protected: void setIncludedInExactParse(bool b); static QStringList varNames(ProjectExplorer::FileType type, QtSupport::ProFileReader *readerExact); @@ -225,7 +227,7 @@ private: QString continuationIndent() const; - QmakeProject *m_project = nullptr; + QPointer<QmakeBuildSystem> m_buildSystem; QmakeProFile *m_qmakeProFile = nullptr; QmakePriFile *m_parent = nullptr; QVector<QmakePriFile *> m_children; @@ -289,7 +291,7 @@ public: class QMAKEPROJECTMANAGER_EXPORT QmakeProFile : public QmakePriFile { public: - QmakeProFile(QmakeProject *project, const Utils::FilePath &filePath); + QmakeProFile(QmakeBuildSystem *buildSystem, const Utils::FilePath &filePath); ~QmakeProFile() override; bool isParent(QmakeProFile *node); @@ -309,7 +311,7 @@ public: } Utils::FilePath sourceDir() const; - Utils::FilePath buildDir(QmakeBuildConfiguration *bc = nullptr) const; + Utils::FilePath buildDir(ProjectExplorer::BuildConfiguration *bc = nullptr) const; Utils::FilePathList generatedFiles(const Utils::FilePath &buildDirectory, const Utils::FilePath &sourceFile, diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index 01916251c79..d0c03864c85 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -90,7 +90,7 @@ class CentralizedFolderWatcher : public QObject { Q_OBJECT public: - CentralizedFolderWatcher(QmakeProject *parent); + CentralizedFolderWatcher(QmakeBuildSystem *BuildSystem); void watchFolders(const QList<QString> &folders, QmakePriFile *file); void unwatchFolders(const QList<QString> &folders, QmakePriFile *file); @@ -100,7 +100,7 @@ private: void onTimer(); void delayedFolderChanged(const QString &folder); - QmakeProject *m_project; + QmakeBuildSystem *m_buildSystem; QSet<QString> recursiveDirs(const QString &folder); QFileSystemWatcher m_watcher; QMultiMap<QString, QmakePriFile *> m_map; @@ -110,8 +110,6 @@ private: QSet<QString> m_changedFolders; }; -static QList<QmakeProject *> s_projects; - } // namespace Internal /*! @@ -120,61 +118,35 @@ static QList<QmakeProject *> s_projects; QmakeProject manages information about an individual Qt 4 (.pro) project file. */ +static bool matchesKit(const Project *p, const Kit *kit) +{ + FilePath filePath = p->projectFilePath(); + QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit); + + return QtSupport::QtVersionManager::version([&filePath, version](const QtSupport::BaseQtVersion *v) { + return v->isValid() && v->isSubProject(filePath) && v == version; + }); +} + QmakeProject::QmakeProject(const FilePath &fileName) : - Project(QmakeProjectManager::Constants::PROFILE_MIMETYPE, fileName), - m_qmakeVfs(new QMakeVfs), - m_cppCodeModelUpdater(new CppTools::CppProjectUpdater) + Project(QmakeProjectManager::Constants::PROFILE_MIMETYPE, fileName) { - s_projects.append(this); setId(Constants::QMAKEPROJECT_ID); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(fileName.toFileInfo().completeBaseName()); setCanBuildProducts(); setHasMakeInstallEquivalent(true); - const QTextCodec *codec = Core::EditorManager::defaultTextCodec(); - m_qmakeVfs->setTextCodec(codec); - - m_asyncUpdateTimer.setSingleShot(true); - m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL); - connect(&m_asyncUpdateTimer, &QTimer::timeout, this, &QmakeProject::asyncUpdate); - - m_rootProFile = std::make_unique<QmakeProFile>(this, projectFilePath()); - - connect(BuildManager::instance(), &BuildManager::buildQueueFinished, - this, &QmakeProject::buildFinished); - - setPreferredKitPredicate([this](const Kit *kit) -> bool { return matchesKit(kit); }); - setBuildSystemCreator([](Project *p) { return new QmakeBuildSystem(p); }); + setPreferredKitPredicate([this](const Kit *kit) -> bool { return matchesKit(this, kit); }); } QmakeProject::~QmakeProject() { - s_projects.removeOne(this); delete m_projectImporter; m_projectImporter = nullptr; - delete m_cppCodeModelUpdater; - m_cppCodeModelUpdater = nullptr; - m_asyncUpdateState = ShuttingDown; // Make sure root node (and associated readers) are shut hown before proceeding setRootProjectNode(nullptr); - m_rootProFile.reset(); - - m_cancelEvaluate = true; - Q_ASSERT(m_qmakeGlobalsRefCnt == 0); - delete m_qmakeVfs; - - if (m_asyncUpdateFutureInterface) { - m_asyncUpdateFutureInterface->reportCanceled(); - m_asyncUpdateFutureInterface->reportFinished(); - delete m_asyncUpdateFutureInterface; - } -} - -QmakeProFile *QmakeProject::rootProFile() const -{ - return m_rootProFile.get(); } Project::RestoreResult QmakeProject::fromMap(const QVariantMap &map, QString *errorMessage) @@ -193,17 +165,6 @@ Project::RestoreResult QmakeProject::fromMap(const QVariantMap &map, QString *er } } - // On active buildconfiguration changes, reevaluate the .pro files - m_activeTarget = activeTarget(); - if (m_activeTarget) { - connect(m_activeTarget, &Target::activeBuildConfigurationChanged, - this, &QmakeProject::scheduleAsyncUpdateLater); - scheduleAsyncUpdate(QmakeProFile::ParseNow); - } - - connect(this, &Project::activeTargetChanged, - this, &QmakeProject::activeTargetWasChanged); - return RestoreResult::Ok; } @@ -212,20 +173,78 @@ DeploymentKnowledge QmakeProject::deploymentKnowledge() const return DeploymentKnowledge::Approximative; // E.g. QTCREATORBUG-21855 } -void QmakeProject::updateCodeModels() +// +// QmakeBuildSystem +// + +QmakeBuildSystem::QmakeBuildSystem(QmakeBuildConfiguration *bc) + : BuildSystem(bc), + m_qmakeVfs(new QMakeVfs), + m_cppCodeModelUpdater(new CppTools::CppProjectUpdater), + m_buildConfiguration(bc) +{ + const QTextCodec *codec = Core::EditorManager::defaultTextCodec(); + m_qmakeVfs->setTextCodec(codec); + + m_asyncUpdateTimer.setSingleShot(true); + m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL); + connect(&m_asyncUpdateTimer, &QTimer::timeout, this, &QmakeBuildSystem::asyncUpdate); + + m_rootProFile = std::make_unique<QmakeProFile>(this, projectFilePath()); + + connect(BuildManager::instance(), &BuildManager::buildQueueFinished, + this, &QmakeBuildSystem::buildFinished); + + connect(bc->target(), &Target::activeBuildConfigurationChanged, + this, [this](BuildConfiguration *bc) { + if (bc == m_buildConfiguration) + scheduleUpdateAllNowOrLater(); +// FIXME: This is too eager in the presence of not handling updates +// when the build configuration is not active, see startAsyncTimer +// below. +// else +// m_cancelEvaluate = true; + }); + + connect(bc->project(), &Project::activeTargetChanged, + this, &QmakeBuildSystem::activeTargetWasChanged); + + connect(bc->project(), &Project::projectFileIsDirty, + this, &QmakeBuildSystem::scheduleUpdateAllLater); +} + +QmakeBuildSystem::~QmakeBuildSystem() +{ + delete m_cppCodeModelUpdater; + m_cppCodeModelUpdater = nullptr; + m_asyncUpdateState = ShuttingDown; + + // Make sure root node (and associated readers) are shut hown before proceeding + m_rootProFile.reset(); + + m_cancelEvaluate = true; + QTC_CHECK(m_qmakeGlobalsRefCnt == 0); + delete m_qmakeVfs; + m_qmakeVfs = nullptr; + + m_asyncUpdateFutureInterface.reportCanceled(); + m_asyncUpdateFutureInterface.reportFinished(); +} + +void QmakeBuildSystem::updateCodeModels() { - if (activeTarget() && !activeTarget()->activeBuildConfiguration()) + if (!m_buildConfiguration->isActive()) return; updateCppCodeModel(); updateQmlJSCodeModel(); } -void QmakeProject::updateCppCodeModel() +void QmakeBuildSystem::updateCppCodeModel() { m_toolChainWarnings.clear(); - QtSupport::CppKitInfo kitInfo(this); + QtSupport::CppKitInfo kitInfo(project()); QTC_ASSERT(kitInfo.isValid(), return); QList<ProjectExplorer::ExtraCompiler *> generators; @@ -286,17 +305,17 @@ void QmakeProject::updateCppCodeModel() } CppTools::GeneratedCodeModelSupport::update(generators); - m_cppCodeModelUpdater->update({this, kitInfo, activeParseEnvironment(), rpps}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), rpps}); } -void QmakeProject::updateQmlJSCodeModel() +void QmakeBuildSystem::updateQmlJSCodeModel() { QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); if (!modelManager) return; QmlJS::ModelManagerInterface::ProjectInfo projectInfo = - modelManager->defaultProjectInfoForProject(this); + modelManager->defaultProjectInfoForProject(project()); const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles(); @@ -339,15 +358,15 @@ void QmakeProject::updateQmlJSCodeModel() // This assumption fails when there are no QDeclarativeEngine/QDeclarativeView (QtQuick 1) // or QQmlEngine/QQuickView (QtQuick 2) instances. if (hasQmlLib) - addProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); + project()->addProjectLanguage(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); projectInfo.activeResourceFiles.removeDuplicates(); projectInfo.allResourceFiles.removeDuplicates(); - modelManager->updateProjectInfo(projectInfo, this); + modelManager->updateProjectInfo(projectInfo, project()); } -void QmakeProject::scheduleAsyncUpdate(QmakeProFile *file, QmakeProFile::AsyncUpdateDelay delay) +void QmakeBuildSystem::scheduleAsyncUpdateFile(QmakeProFile *file, QmakeProFile::AsyncUpdateDelay delay) { if (m_asyncUpdateState == ShuttingDown) return; @@ -400,11 +419,21 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile *file, QmakeProFile::AsyncUp // change a partial update gets in progress and then another // batch of changes come in, which triggers a full update // even if that's not really needed - scheduleAsyncUpdate(delay); + scheduleUpdateAll(delay); } } -void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay) +void QmakeBuildSystem::scheduleUpdateAllNowOrLater() +{ + if (m_firstParseNeeded) { + m_firstParseNeeded = false; + scheduleUpdateAll(QmakeProFile::ParseNow); + } else { + scheduleUpdateAll(QmakeProFile::ParseLater); + } +} + +void QmakeBuildSystem::scheduleUpdateAll(QmakeProFile::AsyncUpdateDelay delay) { if (m_asyncUpdateState == ShuttingDown) return; @@ -430,8 +459,11 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay) startAsyncTimer(delay); } -void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay) +void QmakeBuildSystem::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay) { + if (!m_buildConfiguration->isActive()) + return; + m_asyncUpdateTimer.stop(); m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(), delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0)); @@ -439,33 +471,31 @@ void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay) m_asyncUpdateTimer.start(); } -void QmakeProject::incrementPendingEvaluateFutures() +void QmakeBuildSystem::incrementPendingEvaluateFutures() { if (m_pendingEvaluateFuturesCount == 0) m_guard = guardParsingRun(); ++m_pendingEvaluateFuturesCount; - m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(), - m_asyncUpdateFutureInterface->progressMaximum() + 1); + m_asyncUpdateFutureInterface.setProgressRange(m_asyncUpdateFutureInterface.progressMinimum(), + m_asyncUpdateFutureInterface.progressMaximum() + 1); } -void QmakeProject::decrementPendingEvaluateFutures() +void QmakeBuildSystem::decrementPendingEvaluateFutures() { --m_pendingEvaluateFuturesCount; if (!rootProFile()) return; // We are closing the project! - m_asyncUpdateFutureInterface->setProgressValue(m_asyncUpdateFutureInterface->progressValue() + 1); + m_asyncUpdateFutureInterface.setProgressValue(m_asyncUpdateFutureInterface.progressValue() + 1); if (m_pendingEvaluateFuturesCount == 0) { // We are done! - setRootProjectNode(QmakeNodeTreeBuilder::buildTree(this)); + project()->setRootProjectNode(QmakeNodeTreeBuilder::buildTree(this)); if (!m_rootProFile->validParse()) - m_asyncUpdateFutureInterface->reportCanceled(); + m_asyncUpdateFutureInterface.reportCanceled(); - m_asyncUpdateFutureInterface->reportFinished(); - delete m_asyncUpdateFutureInterface; - m_asyncUpdateFutureInterface = nullptr; + m_asyncUpdateFutureInterface.reportFinished(); m_cancelEvaluate = false; // TODO clear the profile cache ? @@ -479,20 +509,19 @@ void QmakeProject::decrementPendingEvaluateFutures() m_asyncUpdateState = Base; updateBuildSystemData(); updateCodeModels(); - if (activeTarget()) - activeTarget()->updateDefaultDeployConfigurations(); + target()->updateDefaultDeployConfigurations(); m_guard.markAsSuccess(); // Qmake always returns (some) data, even when it failed:-) - m_guard = {}; + m_guard = {}; // This triggers emitParsingFinished by destroying the previous guard. } } } -bool QmakeProject::wasEvaluateCanceled() +bool QmakeBuildSystem::wasEvaluateCanceled() { return m_cancelEvaluate; } -void QmakeProject::asyncUpdate() +void QmakeBuildSystem::asyncUpdate() { m_asyncUpdateTimer.setInterval(UPDATE_INTERVAL); @@ -503,28 +532,23 @@ void QmakeProject::asyncUpdate() m_qmakeVfs->invalidateCache(); } - Q_ASSERT(!m_asyncUpdateFutureInterface); - m_asyncUpdateFutureInterface = new QFutureInterface<void>(); - - m_asyncUpdateFutureInterface->setProgressRange(0, 0); - Core::ProgressManager::addTask(m_asyncUpdateFutureInterface->future(), - tr("Reading Project \"%1\"").arg(displayName()), + m_asyncUpdateFutureInterface.setProgressRange(0, 0); + Core::ProgressManager::addTask(m_asyncUpdateFutureInterface.future(), + tr("Reading Project \"%1\"").arg(project()->displayName()), Constants::PROFILE_EVALUATE); - m_asyncUpdateFutureInterface->reportStarted(); + m_asyncUpdateFutureInterface.reportStarted(); - const Kit * const kit = activeTarget() ? activeTarget()->kit() : nullptr; + const Kit * const kit = target()->kit(); QtSupport::BaseQtVersion * const qtVersion = QtSupport::QtKitAspect::qtVersion(kit); if (!qtVersion || !qtVersion->isValid()) { const QString errorMessage = kit ? tr("Cannot parse project \"%1\": The currently selected kit \"%2\" does not " - "have a valid Qt.").arg(displayName(), kit->displayName()) - : tr("Cannot parse project \"%1\": No kit selected.").arg(displayName()); + "have a valid Qt.").arg(project()->displayName(), kit->displayName()) + : tr("Cannot parse project \"%1\": No kit selected.").arg(project()->displayName()); proFileParseError(errorMessage); - m_asyncUpdateFutureInterface->reportCanceled(); - m_asyncUpdateFutureInterface->reportFinished(); - delete m_asyncUpdateFutureInterface; - m_asyncUpdateFutureInterface = nullptr; + m_asyncUpdateFutureInterface.reportCanceled(); + m_asyncUpdateFutureInterface.reportFinished(); return; } @@ -539,7 +563,7 @@ void QmakeProject::asyncUpdate() m_asyncUpdateState = AsyncUpdateInProgress; } -void QmakeProject::buildFinished(bool success) +void QmakeBuildSystem::buildFinished(bool success) { if (success) m_invalidateQmakeVfsContents = true; @@ -584,51 +608,28 @@ static FileNode *fileNodeOf(FolderNode *in, const FilePath &fileName) return nullptr; } -QStringList QmakeProject::filesGeneratedFrom(const QString &input) const -{ - if (!rootProjectNode()) - return { }; - - if (const FileNode *file = fileNodeOf(rootProjectNode(), FilePath::fromString(input))) { - const QmakeProFileNode *pro = static_cast<QmakeProFileNode *>(file->parentFolderNode()); - QTC_ASSERT(pro, return {}); - if (const QmakeProFile *proFile = pro->proFile()) - return Utils::transform(proFile->generatedFiles(FilePath::fromString(pro->buildDir()), - file->filePath(), file->fileType()), - &FilePath::toString); - } - return { }; -} - -void QmakeProject::proFileParseError(const QString &errorMessage) +void QmakeBuildSystem::proFileParseError(const QString &errorMessage) { Core::MessageManager::write(errorMessage); } -QtSupport::ProFileReader *QmakeProject::createProFileReader(const QmakeProFile *qmakeProFile) +QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFile *qmakeProFile) { if (!m_qmakeGlobals) { m_qmakeGlobals = std::make_unique<QMakeGlobals>(); m_qmakeGlobalsRefCnt = 0; - Kit *k = KitManager::defaultKit(); Environment env = Environment::systemEnvironment(); QStringList qmakeArgs; - if (Target *t = activeTarget()) { - k = t->kit(); - if (auto bc = static_cast<QmakeBuildConfiguration *>(t->activeBuildConfiguration())) { - env = bc->environment(); - if (QMakeStep *qs = bc->qmakeStep()) - qmakeArgs = qs->parserArguments(); - else - qmakeArgs = bc->configCommandLineArguments(); - } - } else { - // Set up a better default environment without using a build configuration: - QmakeBuildConfiguration::setupBuildEnvironment(k, env); - if (k) - k->addToEnvironment(env); + Target *t = target(); + Kit *k = t->kit(); + if (auto bc = static_cast<QmakeBuildConfiguration *>(t->activeBuildConfiguration())) { + env = bc->environment(); + if (QMakeStep *qs = bc->qmakeStep()) + qmakeArgs = qs->parserArguments(); + else + qmakeArgs = bc->configCommandLineArguments(); } QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(k); @@ -672,22 +673,22 @@ QtSupport::ProFileReader *QmakeProject::createProFileReader(const QmakeProFile * return reader; } -QMakeGlobals *QmakeProject::qmakeGlobals() +QMakeGlobals *QmakeBuildSystem::qmakeGlobals() { return m_qmakeGlobals.get(); } -QMakeVfs *QmakeProject::qmakeVfs() +QMakeVfs *QmakeBuildSystem::qmakeVfs() { return m_qmakeVfs; } -QString QmakeProject::qmakeSysroot() +QString QmakeBuildSystem::qmakeSysroot() { return m_qmakeSysroot; } -void QmakeProject::destroyProFileReader(QtSupport::ProFileReader *reader) +void QmakeBuildSystem::destroyProFileReader(QtSupport::ProFileReader *reader) { delete reader; if (!--m_qmakeGlobalsRefCnt) { @@ -701,36 +702,21 @@ void QmakeProject::destroyProFileReader(QtSupport::ProFileReader *reader) } } -QmakeProFileNode *QmakeProject::rootProjectNode() const -{ - return static_cast<QmakeProFileNode *>(Project::rootProjectNode()); -} - -void QmakeProject::activeTargetWasChanged() +void QmakeBuildSystem::activeTargetWasChanged(Target *t) { - const bool hadActiveTarget = m_activeTarget; - if (hadActiveTarget) { - disconnect(m_activeTarget, &Target::activeBuildConfigurationChanged, - this, &QmakeProject::scheduleAsyncUpdateLater); - } - - m_activeTarget = activeTarget(); - m_invalidateQmakeVfsContents = true; - - if (!m_activeTarget) + // We are only interested in our own target. + if (t != m_buildConfiguration->target()) return; - connect(m_activeTarget, &Target::activeBuildConfigurationChanged, - this, &QmakeProject::scheduleAsyncUpdateLater); - - scheduleAsyncUpdate(hadActiveTarget ? QmakeProFile::ParseLater : QmakeProFile::ParseNow); + m_invalidateQmakeVfsContents = true; + scheduleUpdateAll(QmakeProFile::ParseLater); } static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file) { if (file->filePath() == fileName) { QtSupport::ProFileCacheManager::instance()->discardFile( - fileName.toString(), file->project()->qmakeVfs()); + fileName.toString(), file->buildSystem()->qmakeVfs()); file->scheduleUpdate(QmakeProFile::ParseNow); } @@ -740,19 +726,19 @@ static void notifyChangedHelper(const FilePath &fileName, QmakeProFile *file) } } -void QmakeProject::notifyChanged(const FilePath &name) +void QmakeBuildSystem::notifyChanged(const FilePath &name) { - for (QmakeProject *project : s_projects) { - if (!project - ->files([&name](const ProjectExplorer::Node *n) { - return Project::SourceFiles(n) && n->filePath() == name; - }) - .isEmpty()) - notifyChangedHelper(name, project->rootProFile()); - } + FilePathList files = project()->files([&name](const Node *n) { + return Project::SourceFiles(n) && n->filePath() == name; + }); + + if (files.isEmpty()) + return; + + notifyChangedHelper(name, m_rootProFile.get()); } -void QmakeProject::watchFolders(const QStringList &l, QmakePriFile *file) +void QmakeBuildSystem::watchFolders(const QStringList &l, QmakePriFile *file) { if (l.isEmpty()) return; @@ -761,7 +747,7 @@ void QmakeProject::watchFolders(const QStringList &l, QmakePriFile *file) m_centralizedFolderWatcher->watchFolders(l, file); } -void QmakeProject::unwatchFolders(const QStringList &l, QmakePriFile *file) +void QmakeBuildSystem::unwatchFolders(const QStringList &l, QmakePriFile *file) { if (m_centralizedFolderWatcher && !l.isEmpty()) m_centralizedFolderWatcher->unwatchFolders(l, file); @@ -772,8 +758,8 @@ void QmakeProject::unwatchFolders(const QStringList &l, QmakePriFile *file) //////////// // All the folder have a trailing slash! -CentralizedFolderWatcher::CentralizedFolderWatcher(QmakeProject *parent) - : QObject(parent), m_project(parent) +CentralizedFolderWatcher::CentralizedFolderWatcher(QmakeBuildSystem *parent) + : QObject(parent), m_buildSystem(parent) { m_compressTimer.setSingleShot(true); m_compressTimer.setInterval(200); @@ -914,7 +900,7 @@ void CentralizedFolderWatcher::delayedFolderChanged(const QString &folder) } if (newOrRemovedFiles) - m_project->updateCodeModels(); + m_buildSystem->updateCodeModels(); } void QmakeProject::configureAsExampleProject() @@ -930,22 +916,19 @@ void QmakeProject::configureAsExampleProject() setup(infoList); } -void QmakeProject::updateBuildSystemData() +void QmakeBuildSystem::updateBuildSystemData() { - Target *const target = activeTarget(); - if (!target) - return; const QmakeProFile *const file = rootProFile(); if (!file || file->parseInProgress()) return; DeploymentData deploymentData; collectData(file, deploymentData); - target->setDeploymentData(deploymentData); + setDeploymentData(deploymentData); QList<BuildTargetInfo> appTargetList; - rootProjectNode()->forEachProjectNode([this, target, &appTargetList](const ProjectNode *pn) { + project()->rootProjectNode()->forEachProjectNode([this, &appTargetList](const ProjectNode *pn) { auto node = dynamic_cast<const QmakeProFileNode *>(pn); if (!node || !node->includedInExactParse()) return; @@ -1017,7 +1000,7 @@ void QmakeProject::updateBuildSystemData() libraryPaths.append(dir); } } - QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit()); + QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target()->kit()); if (qtVersion) libraryPaths.append(qtVersion->librarySearchPath().toString()); @@ -1030,10 +1013,10 @@ void QmakeProject::updateBuildSystemData() appTargetList.append(bti); }); - target->setApplicationTargets(appTargetList); + setApplicationTargets(appTargetList); } -void QmakeProject::collectData(const QmakeProFile *file, DeploymentData &deploymentData) +void QmakeBuildSystem::collectData(const QmakeProFile *file, DeploymentData &deploymentData) { if (!file->isSubProjectDeployable(file->filePath())) return; @@ -1069,7 +1052,7 @@ void QmakeProject::collectData(const QmakeProFile *file, DeploymentData &deploym } } -void QmakeProject::collectApplicationData(const QmakeProFile *file, DeploymentData &deploymentData) +void QmakeBuildSystem::collectApplicationData(const QmakeProFile *file, DeploymentData &deploymentData) { QString executable = executableFor(file); if (!executable.isEmpty()) @@ -1086,12 +1069,12 @@ static FilePath destDirFor(const TargetInformation &ti) return ti.destDir; } -void QmakeProject::collectLibraryData(const QmakeProFile *file, DeploymentData &deploymentData) +void QmakeBuildSystem::collectLibraryData(const QmakeProFile *file, DeploymentData &deploymentData) { const QString targetPath = file->installsList().targetPath; if (targetPath.isEmpty()) return; - const Kit * const kit = activeTarget()->kit(); + const Kit * const kit = target()->kit(); const ToolChain * const toolchain = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID); if (!toolchain) return; @@ -1176,16 +1159,6 @@ void QmakeProject::collectLibraryData(const QmakeProFile *file, DeploymentData & } } -bool QmakeProject::matchesKit(const Kit *kit) -{ - FilePath filePath = projectFilePath(); - QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit); - - return QtSupport::QtVersionManager::version([&filePath, version](const QtSupport::BaseQtVersion *v) { - return v->isValid() && v->isSubProject(filePath) && v == version; - }); -} - static Utils::FilePath getFullPathOf(const QmakeProFile *pro, Variable variable, const BuildConfiguration *bc) { @@ -1205,7 +1178,7 @@ static Utils::FilePath getFullPathOf(const QmakeProFile *pro, Variable variable, return bc->environment().searchInPath(exe); } -void QmakeProject::testToolChain(ToolChain *tc, const Utils::FilePath &path) const +void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const { if (!tc || path.isEmpty()) return; @@ -1213,15 +1186,14 @@ void QmakeProject::testToolChain(ToolChain *tc, const Utils::FilePath &path) con const Utils::FilePath expected = tc->compilerCommand(); Environment env = Environment::systemEnvironment(); - Kit *k = nullptr; - if (Target *t = activeTarget()) { - k = t->kit(); - if (BuildConfiguration *bc = t->activeBuildConfiguration()) - env = bc->environment(); - else - k->addToEnvironment(env); - } - QTC_ASSERT(k, return); + Target *t = target(); + QTC_ASSERT(t, return); + + Kit *k = t->kit(); + if (BuildConfiguration *bc = t->activeBuildConfiguration()) + env = bc->environment(); + else + k->addToEnvironment(env); if (env.isSameExecutable(path.toString(), expected.toString())) return; @@ -1247,9 +1219,9 @@ void QmakeProject::testToolChain(ToolChain *tc, const Utils::FilePath &path) con m_toolChainWarnings.insert(pair); } -void QmakeProject::warnOnToolChainMismatch(const QmakeProFile *pro) const +void QmakeBuildSystem::warnOnToolChainMismatch(const QmakeProFile *pro) const { - const Target *t = activeTarget(); + const Target *t = target(); const BuildConfiguration *bc = t ? t->activeBuildConfiguration() : nullptr; if (!bc) return; @@ -1260,9 +1232,9 @@ void QmakeProject::warnOnToolChainMismatch(const QmakeProFile *pro) const getFullPathOf(pro, Variable::QmakeCxx, bc)); } -QString QmakeProject::executableFor(const QmakeProFile *file) +QString QmakeBuildSystem::executableFor(const QmakeProFile *file) { - const Kit *const kit = activeTarget() ? activeTarget()->kit() : nullptr; + const Kit *const kit = target()->kit(); const ToolChain *const tc = ToolChainKitAspect::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID); if (!tc) return QString(); @@ -1285,11 +1257,6 @@ QString QmakeProject::executableFor(const QmakeProFile *file) return QDir(destDirFor(ti).toString()).absoluteFilePath(target); } -void QmakeProject::emitBuildDirectoryInitialized() -{ - emit buildDirectoryInitialized(); -} - ProjectImporter *QmakeProject::projectImporter() const { if (!m_projectImporter) @@ -1297,24 +1264,44 @@ ProjectImporter *QmakeProject::projectImporter() const return m_projectImporter; } -QmakeProject::AsyncUpdateState QmakeProject::asyncUpdateState() const +QmakeBuildSystem::AsyncUpdateState QmakeBuildSystem::asyncUpdateState() const { return m_asyncUpdateState; } -QString QmakeProject::mapProFilePathToTarget(const FilePath &proFilePath) +QmakeProFile *QmakeBuildSystem::rootProFile() const +{ + return m_rootProFile.get(); +} + +void QmakeBuildSystem::triggerParsing() +{ + asyncUpdate(); +} + +QStringList QmakeBuildSystem::filesGeneratedFrom(const QString &input) const { - const QmakeProFile *pro = rootProFile()->findProFile(proFilePath); - return pro ? pro->targetInformation().target : QString(); + if (!project()->rootProjectNode()) + return {}; + + if (const FileNode *file = fileNodeOf(project()->rootProjectNode(), FilePath::fromString(input))) { + const QmakeProFileNode *pro = dynamic_cast<QmakeProFileNode *>(file->parentFolderNode()); + QTC_ASSERT(pro, return {}); + if (const QmakeProFile *proFile = pro->proFile()) + return Utils::transform(proFile->generatedFiles(pro->buildDir(nullptr), + file->filePath(), file->fileType()), + &FilePath::toString); + } + return {}; } -QVariant QmakeProject::additionalData(Core::Id id, const Target *target) const +QVariant QmakeBuildSystem::additionalData(Core::Id id) const { if (id == "QmlDesignerImportPath") - return rootProjectNode()->variableValue(Variable::QmlDesignerImportPath); - return Project::additionalData(id, target); + return m_rootProFile->variableValue(Variable::QmlDesignerImportPath); + return BuildSystem::additionalData(id); } -} // namespace QmakeProjectManager +} // QmakeProjectManager #include "qmakeproject.moc" diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.h b/src/plugins/qmakeprojectmanager/qmakeproject.h index 3c1b4f1ba6f..8c138e54994 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.h +++ b/src/plugins/qmakeprojectmanager/qmakeproject.h @@ -59,15 +59,75 @@ public: explicit QmakeProject(const Utils::FilePath &proFile); ~QmakeProject() final; - QmakeProFile *rootProFile() const; - ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final; - QmakeProFileNode *rootProjectNode() const final; + void configureAsExampleProject() final; + + ProjectExplorer::ProjectImporter *projectImporter() const final; + +protected: + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; + +private: + ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; + + mutable ProjectExplorer::ProjectImporter *m_projectImporter = nullptr; +}; + +// FIXME: This export here is only there to appease the current version +// of the appman plugin. This _will_ go away, one way or the other. +class QMAKEPROJECTMANAGER_EXPORT QmakeBuildSystem : public ProjectExplorer::BuildSystem +{ + Q_OBJECT + +public: + explicit QmakeBuildSystem(QmakeBuildConfiguration *bc); + ~QmakeBuildSystem(); + + bool supportsAction(ProjectExplorer::Node *context, + ProjectExplorer::ProjectAction action, + const ProjectExplorer::Node *node) const override; + + bool addFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notAdded = nullptr) override; + ProjectExplorer::RemovedFilesFromProject removeFiles(ProjectExplorer::Node *context, + const QStringList &filePaths, + QStringList *notRemoved = nullptr) override; + bool deleteFiles(ProjectExplorer::Node *context, + const QStringList &filePaths) override; + bool canRenameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + bool renameFile(ProjectExplorer::Node *context, + const QString &filePath, const QString &newFilePath) override; + bool addDependencies(ProjectExplorer::Node *context, + const QStringList &dependencies) override; + void triggerParsing() final; QStringList filesGeneratedFrom(const QString &file) const final; + QVariant additionalData(Core::Id id) const final; + + void asyncUpdate(); + void buildFinished(bool success); + void activeTargetWasChanged(ProjectExplorer::Target *); + + QString executableFor(const QmakeProFile *file); + + void updateCppCodeModel(); + void updateQmlJSCodeModel(); + + static bool equalFileList(const QStringList &a, const QStringList &b); + + void updateBuildSystemData(); + void collectData(const QmakeProFile *file, ProjectExplorer::DeploymentData &deploymentData); + void collectApplicationData(const QmakeProFile *file, + ProjectExplorer::DeploymentData &deploymentData); + void collectLibraryData(const QmakeProFile *file, + ProjectExplorer::DeploymentData &deploymentData); + void startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay); - static void notifyChanged(const Utils::FilePath &name); + void warnOnToolChainMismatch(const QmakeProFile *pro) const; + void testToolChain(ProjectExplorer::ToolChain *tc, const Utils::FilePath &path) const; /// \internal QtSupport::ProFileReader *createProFileReader(const QmakeProFile *qmakeProFile); @@ -81,8 +141,8 @@ public: void destroyProFileReader(QtSupport::ProFileReader *reader); /// \internal - void scheduleAsyncUpdate(QmakeProFile *file, - QmakeProFile::AsyncUpdateDelay delay = QmakeProFile::ParseLater); + void scheduleAsyncUpdateFile(QmakeProFile *file, + QmakeProFile::AsyncUpdateDelay delay = QmakeProFile::ParseLater); /// \internal void incrementPendingEvaluateFutures(); /// \internal @@ -95,56 +155,19 @@ public: void watchFolders(const QStringList &l, QmakePriFile *file); void unwatchFolders(const QStringList &l, QmakePriFile *file); - void configureAsExampleProject() final; - - void emitBuildDirectoryInitialized(); static void proFileParseError(const QString &errorMessage); - ProjectExplorer::ProjectImporter *projectImporter() const final; - enum AsyncUpdateState { Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress, ShuttingDown }; AsyncUpdateState asyncUpdateState() const; - QString mapProFilePathToTarget(const Utils::FilePath &proFilePath); - - QVariant additionalData(Core::Id id, const ProjectExplorer::Target *target) const final; + QmakeProFile *rootProFile() const; -signals: - void proFileUpdated(QmakeProjectManager::QmakeProFile *pro, bool, bool); - void buildDirectoryInitialized(); + void notifyChanged(const Utils::FilePath &name); public: - void scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay = QmakeProFile::ParseLater); - void scheduleAsyncUpdateLater() { scheduleAsyncUpdate(); } - -protected: - RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) final; - -private: - ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - - void asyncUpdate(); - void buildFinished(bool success); - void activeTargetWasChanged(); - - QString executableFor(const QmakeProFile *file); - - void updateCppCodeModel(); - void updateQmlJSCodeModel(); - - static bool equalFileList(const QStringList &a, const QStringList &b); - - void updateBuildSystemData(); - void collectData(const QmakeProFile *file, ProjectExplorer::DeploymentData &deploymentData); - void collectApplicationData(const QmakeProFile *file, - ProjectExplorer::DeploymentData &deploymentData); - void collectLibraryData(const QmakeProFile *file, - ProjectExplorer::DeploymentData &deploymentData); - void startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay); - bool matchesKit(const ProjectExplorer::Kit *kit); - - void warnOnToolChainMismatch(const QmakeProFile *pro) const; - void testToolChain(ProjectExplorer::ToolChain *tc, const Utils::FilePath &path) const; + void scheduleUpdateAll(QmakeProFile::AsyncUpdateDelay delay); + void scheduleUpdateAllLater() { scheduleUpdateAll(QmakeProFile::ParseLater); } + void scheduleUpdateAllNowOrLater(); mutable QSet<const QPair<Utils::FilePath, Utils::FilePath>> m_toolChainWarnings; @@ -164,7 +187,7 @@ private: QString m_qmakeSysroot; QTimer m_asyncUpdateTimer; - QFutureInterface<void> *m_asyncUpdateFutureInterface = nullptr; + QFutureInterface<void> m_asyncUpdateFutureInterface; int m_pendingEvaluateFuturesCount = 0; AsyncUpdateState m_asyncUpdateState = Base; bool m_cancelEvaluate = false; @@ -174,10 +197,9 @@ private: Internal::CentralizedFolderWatcher *m_centralizedFolderWatcher = nullptr; - ProjectExplorer::Target *m_activeTarget = nullptr; - mutable ProjectExplorer::ProjectImporter *m_projectImporter = nullptr; - - ParseGuard m_guard; + ProjectExplorer::BuildSystem::ParseGuard m_guard; + QmakeBuildConfiguration *m_buildConfiguration = nullptr; + bool m_firstParseNeeded = true; }; } // namespace QmakeProjectManager diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp index 7949d21f723..04286333e36 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectconfigwidget.cpp @@ -149,10 +149,7 @@ QmakeProjectConfigWidget::QmakeProjectConfigWidget(QmakeBuildConfiguration *bc) connect(bc, &BuildConfiguration::enabledChanged, this, &QmakeProjectConfigWidget::environmentChanged); - auto qmakeProject = static_cast<QmakeProject *>(bc->target()->project()); - connect(qmakeProject, &QmakeProject::buildDirectoryInitialized, - this, &QmakeProjectConfigWidget::updateProblemLabel); - connect(qmakeProject, &Project::parsingFinished, + connect(bc->target(), &Target::parsingFinished, this, &QmakeProjectConfigWidget::updateProblemLabel); connect(&QmakeSettings::instance(), &QmakeSettings::settingsChanged, this, &QmakeProjectConfigWidget::updateProblemLabel); @@ -254,8 +251,8 @@ void QmakeProjectConfigWidget::updateProblemLabel() return; } - auto *p = static_cast<QmakeProject *>(m_buildConfiguration->target()->project()); - if (p->rootProFile()->parseInProgress() || !p->rootProFile()->validParse()) { + auto bs = m_buildConfiguration->qmakeBuildSystem(); + if (bs->rootProFile()->parseInProgress() || !bs->rootProFile()->validParse()) { setProblemLabel(QString()); return; } diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index f7068873cc4..c8bd5614df7 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -319,8 +319,6 @@ void QmakeProjectManagerPluginPrivate::projectChanged() if (m_previousStartupProject) { connect(m_previousStartupProject, &Project::activeTargetChanged, this, &QmakeProjectManagerPluginPrivate::activeTargetChanged); - connect(m_previousStartupProject, &Project::parsingFinished, - this, &QmakeProjectManagerPluginPrivate::updateActions); } activeTargetChanged(); @@ -334,9 +332,12 @@ void QmakeProjectManagerPluginPrivate::activeTargetChanged() m_previousTarget = m_previousStartupProject ? m_previousStartupProject->activeTarget() : nullptr; - if (m_previousTarget) + if (m_previousTarget) { connect(m_previousTarget, &Target::activeBuildConfigurationChanged, this, &QmakeProjectManagerPluginPrivate::updateRunQMakeAction); + connect(m_previousTarget, &Target::parsingFinished, + this, &QmakeProjectManagerPluginPrivate::updateActions); + } updateRunQMakeAction(); } diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 671a7ee3751..d212caa10d4 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -81,7 +81,7 @@ QMakeStep::QMakeStep(BuildStepList *bsl) : AbstractProcessStep(bsl, Constants::Q QmakeBuildConfiguration *QMakeStep::qmakeBuildConfiguration() const { - return static_cast<QmakeBuildConfiguration *>(buildConfiguration()); + return qobject_cast<QmakeBuildConfiguration *>(buildConfiguration()); } /// @@ -174,17 +174,17 @@ bool QMakeStep::init() return false; } - QString workingDirectory; + FilePath workingDirectory; if (qmakeBc->subNodeBuild()) - workingDirectory = qmakeBc->subNodeBuild()->buildDir(); + workingDirectory = qmakeBc->subNodeBuild()->buildDir(qmakeBc); else - workingDirectory = qmakeBc->buildDirectory().toString(); + workingDirectory = qmakeBc->buildDirectory(); m_qmakeCommand = CommandLine{qtVersion->qmakeCommand(), allArguments(qtVersion), CommandLine::Raw}; m_runMakeQmake = (qtVersion->qtVersion() >= QtVersionNumber(5, 0 ,0)); - QString makefile = workingDirectory + '/'; + QString makefile = workingDirectory.toString() + '/'; if (qmakeBc->subNodeBuild()) { QmakeProFileNode *pro = qmakeBc->subNodeBuild(); @@ -220,18 +220,18 @@ bool QMakeStep::init() ProcessParameters *pp = processParameters(); pp->setMacroExpander(qmakeBc->macroExpander()); - pp->setWorkingDirectory(Utils::FilePath::fromString(workingDirectory)); + pp->setWorkingDirectory(workingDirectory); pp->setEnvironment(qmakeBc->environment()); setOutputParser(new QMakeParser); - QmakeProFileNode *node = static_cast<QmakeProject *>(qmakeBc->target()->project())->rootProjectNode(); + QmakeProFileNode *node = static_cast<QmakeProFileNode *>(qmakeBc->project()->rootProjectNode()); if (qmakeBc->subNodeBuild()) node = qmakeBc->subNodeBuild(); QTC_ASSERT(node, return false); QString proFile = node->filePath().toString(); - Tasks tasks = qtVersion->reportIssues(proFile, workingDirectory); + Tasks tasks = qtVersion->reportIssues(proFile, workingDirectory.toString()); Utils::sort(tasks); if (!tasks.isEmpty()) { @@ -292,8 +292,7 @@ bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status) bool result = AbstractProcessStep::processSucceeded(exitCode, status); if (!result) m_needToRunQMake = true; - auto *project = static_cast<QmakeProject *>(qmakeBuildConfiguration()->target()->project()); - project->emitBuildDirectoryInitialized(); + emit buildConfiguration()->buildDirectoryChanged(); return result; } @@ -591,7 +590,7 @@ QMakeStepConfigWidget::QMakeStepConfigWidget(QMakeStep *step) this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged); connect(step->project(), &Project::projectLanguagesUpdated, this, &QMakeStepConfigWidget::linkQmlDebuggingLibraryChanged); - connect(step->project(), &Project::parsingFinished, + connect(step->target(), &Target::parsingFinished, this, &QMakeStepConfigWidget::updateEffectiveQMakeCall); connect(step, &QMakeStep::useQtQuickCompilerChanged, this, &QMakeStepConfigWidget::useQtQuickCompilerChanged); @@ -866,7 +865,7 @@ void QMakeStepConfigWidget::updateEffectiveQMakeCall() void QMakeStepConfigWidget::recompileMessageBoxFinished(int button) { if (button == QMessageBox::Yes) { - QmakeBuildConfiguration *bc = m_step->qmakeBuildConfiguration(); + BuildConfiguration *bc = m_step->buildConfiguration(); if (!bc) return; diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index d227db6fe52..afe577487af 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "qmlproject.h" + #include "fileformat/qmlprojectfileformat.h" #include "fileformat/qmlprojectitem.h" #include "qmlprojectrunconfiguration.h" @@ -31,6 +32,9 @@ #include "qmlprojectmanagerconstants.h" #include "qmlprojectnodes.h" +#include <coreplugin/documentmanager.h> +#include <coreplugin/editormanager/documentmodel.h> +#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/icontext.h> #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> @@ -46,66 +50,84 @@ #include <qmljs/qmljsmodelmanagerinterface.h> +#include <texteditor/textdocument.h> + #include <utils/algorithm.h> #include <QDebug> +#include <QRegularExpression> +#include <QTextCodec> using namespace Core; using namespace ProjectExplorer; +using namespace QmlProjectManager::Internal; namespace QmlProjectManager { QmlProject::QmlProject(const Utils::FilePath &fileName) : Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName) { - const QString normalized - = Utils::FileUtils::normalizePathName(fileName.toFileInfo().canonicalFilePath()); - m_canonicalProjectDir = Utils::FilePath::fromString(normalized).parentDir(); - setId(QmlProjectManager::Constants::QML_PROJECT_ID); setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID)); setDisplayName(fileName.toFileInfo().completeBaseName()); setNeedsBuildConfigurations(false); - setBuildSystemCreator([](Project *p) { return new Internal::QmlBuildSystem(p); }); + setBuildSystemCreator([](Target *t) { return new QmlBuildSystem(t); }); +} + +QmlBuildSystem::QmlBuildSystem(Target *target) + : BuildSystem(target) +{ + const QString normalized + = Utils::FileUtils::normalizePathName(target->project() + ->projectFilePath().toFileInfo().canonicalFilePath()); + m_canonicalProjectDir = Utils::FilePath::fromString(normalized).parentDir(); + + connect(target->project(), &Project::projectFileIsDirty, + this, &QmlBuildSystem::refreshProjectFile); - connect(this, &QmlProject::projectFileIsDirty, this, &QmlProject::refreshProjectFile); + // refresh first - project information is used e.g. to decide the default RC's + refresh(Everything); + +// FIXME: Check. Probably bogus after the BuildSystem move. +// // addedTarget calls updateEnabled on the runconfigurations +// // which needs to happen after refresh +// foreach (Target *t, targets()) +// addedTarget(t); + + connect(target->project(), &Project::activeTargetChanged, + this, &QmlBuildSystem::onActiveTargetChanged); + updateDeploymentData(); } -QmlProject::~QmlProject() +QmlBuildSystem::~QmlBuildSystem() { delete m_projectItem.data(); } -void QmlProject::addedTarget(Target *target) +void QmlBuildSystem::triggerParsing() { - updateDeploymentData(target); + refresh(Everything); } -void QmlProject::onActiveTargetChanged(Target *target) +void QmlBuildSystem::onActiveTargetChanged(Target *) { - if (m_activeTarget) - disconnect(m_activeTarget, &Target::kitChanged, this, &QmlProject::onKitChanged); - m_activeTarget = target; - if (m_activeTarget) - connect(target, &Target::kitChanged, this, &QmlProject::onKitChanged); - // make sure e.g. the default qml imports are adapted refresh(Configuration); } -void QmlProject::onKitChanged() +void QmlBuildSystem::onKitChanged() { // make sure e.g. the default qml imports are adapted refresh(Configuration); } -Utils::FilePath QmlProject::canonicalProjectDir() const +Utils::FilePath QmlBuildSystem::canonicalProjectDir() const { return m_canonicalProjectDir; } -void QmlProject::parseProject(RefreshOptions options) +void QmlBuildSystem::parseProject(RefreshOptions options) { if (options & Files) { if (options & ProjectFile) @@ -115,7 +137,7 @@ void QmlProject::parseProject(RefreshOptions options) m_projectItem = QmlProjectFileFormat::parseProjectFile(projectFilePath(), &errorMessage); if (m_projectItem) { connect(m_projectItem.data(), &QmlProjectItem::qmlFilesChanged, - this, &QmlProject::refreshFiles); + this, &QmlBuildSystem::refreshFiles); } else { MessageManager::write(tr("Error while loading project file %1.") @@ -153,7 +175,7 @@ void QmlProject::parseProject(RefreshOptions options) } } -void QmlProject::refresh(RefreshOptions options) +void QmlBuildSystem::refresh(RefreshOptions options) { ParseGuard guard = guardParsingRun(); parseProject(options); @@ -166,32 +188,32 @@ void QmlProject::refresh(RefreshOptions options) return; QmlJS::ModelManagerInterface::ProjectInfo projectInfo = - modelManager->defaultProjectInfoForProject(this); + modelManager->defaultProjectInfoForProject(project()); foreach (const QString &searchPath, makeAbsolute(canonicalProjectDir(), customImportPaths())) projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath), QmlJS::Dialect::Qml); - modelManager->updateProjectInfo(projectInfo, this); + modelManager->updateProjectInfo(projectInfo, project()); guard.markAsSuccess(); } -QString QmlProject::mainFile() const +QString QmlBuildSystem::mainFile() const { if (m_projectItem) return m_projectItem.data()->mainFile(); return QString(); } -void QmlProject::setMainFile(const QString &mainFilePath) +void QmlBuildSystem::setMainFile(const QString &mainFilePath) { if (m_projectItem) m_projectItem.data()->setMainFile(mainFilePath); } -Utils::FilePath QmlProject::targetDirectory(const Target *target) const +Utils::FilePath QmlBuildSystem::targetDirectory() const { - if (DeviceTypeKitAspect::deviceTypeId(target->kit()) + if (DeviceTypeKitAspect::deviceTypeId(target()->kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) return canonicalProjectDir(); @@ -199,53 +221,42 @@ Utils::FilePath QmlProject::targetDirectory(const Target *target) const : Utils::FilePath(); } -Utils::FilePath QmlProject::targetFile(const Utils::FilePath &sourceFile, - const Target *target) const +Utils::FilePath QmlBuildSystem::targetFile(const Utils::FilePath &sourceFile) const { const QDir sourceDir(m_projectItem ? m_projectItem->sourceDirectory() : canonicalProjectDir().toString()); - const QDir targetDir(targetDirectory(target).toString()); + const QDir targetDir(targetDirectory().toString()); const QString relative = sourceDir.relativeFilePath(sourceFile.toString()); return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative))); } -Utils::EnvironmentItems QmlProject::environment() const +Utils::EnvironmentItems QmlBuildSystem::environment() const { if (m_projectItem) return m_projectItem.data()->environment(); return {}; } -QStringList QmlProject::customImportPaths() const +QStringList QmlBuildSystem::customImportPaths() const { if (m_projectItem) return m_projectItem.data()->importPaths(); return {}; } -QStringList QmlProject::customFileSelectors() const +QStringList QmlBuildSystem::customFileSelectors() const { if (m_projectItem) return m_projectItem.data()->fileSelectors(); return {}; } -bool QmlProject::addFiles(const QStringList &filePaths) -{ - QStringList toAdd; - foreach (const QString &filePath, filePaths) { - if (!m_projectItem.data()->matchesFile(filePath)) - toAdd << filePaths; - } - return toAdd.isEmpty(); -} - -void QmlProject::refreshProjectFile() +void QmlBuildSystem::refreshProjectFile() { - refresh(QmlProject::ProjectFile | Files); + refresh(QmlBuildSystem::ProjectFile | Files); } -QStringList QmlProject::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths) +QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths) { if (path.isEmpty()) return relativePaths; @@ -256,14 +267,7 @@ QStringList QmlProject::makeAbsolute(const Utils::FilePath &path, const QStringL }); } -QVariant QmlProject::additionalData(Id id, const Target *) const -{ - if (id == Constants::customFileSelectorsData) - return customFileSelectors(); - return {}; -} - -void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed) +void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed) { refresh(Files); if (!removed.isEmpty()) { @@ -273,11 +277,9 @@ void QmlProject::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString refreshTargetDirectory(); } -void QmlProject::refreshTargetDirectory() +void QmlBuildSystem::refreshTargetDirectory() { - const QList<Target *> targetList = targets(); - for (Target *target : targetList) - updateDeploymentData(target); + updateDeploymentData(); } Tasks QmlProject::projectIssues(const Kit *k) const @@ -324,9 +326,6 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro if (result != RestoreResult::Ok) return result; - // refresh first - project information is used e.g. to decide the default RC's - refresh(Everything); - if (!activeTarget()) { // find a kit that matches prerequisites (prefer default one) const QList<Kit*> kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) { @@ -341,18 +340,6 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro } } - // addedTarget calls updateEnabled on the runconfigurations - // which needs to happen after refresh - foreach (Target *t, targets()) - addedTarget(t); - - connect(this, &ProjectExplorer::Project::addedTarget, this, &QmlProject::addedTarget); - - connect(this, &ProjectExplorer::Project::activeTargetChanged, - this, &QmlProject::onActiveTargetChanged); - - onActiveTargetChanged(activeTarget()); - return RestoreResult::Ok; } @@ -361,12 +348,12 @@ ProjectExplorer::DeploymentKnowledge QmlProject::deploymentKnowledge() const return DeploymentKnowledge::Perfect; } -void QmlProject::generateProjectTree() +void QmlBuildSystem::generateProjectTree() { if (!m_projectItem) return; - auto newRoot = std::make_unique<Internal::QmlProjectNode>(this); + auto newRoot = std::make_unique<QmlProjectNode>(project()); for (const QString &f : m_projectItem.data()->files()) { const Utils::FilePath fileName = Utils::FilePath::fromString(f); @@ -376,16 +363,16 @@ void QmlProject::generateProjectTree() } newRoot->addNestedNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project)); - setRootProjectNode(std::move(newRoot)); + project()->setRootProjectNode(std::move(newRoot)); refreshTargetDirectory(); } -void QmlProject::updateDeploymentData(ProjectExplorer::Target *target) +void QmlBuildSystem::updateDeploymentData() { if (!m_projectItem) return; - if (DeviceTypeKitAspect::deviceTypeId(target->kit()) + if (DeviceTypeKitAspect::deviceTypeId(target()->kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { return; } @@ -394,10 +381,109 @@ void QmlProject::updateDeploymentData(ProjectExplorer::Target *target) for (const QString &file : m_projectItem->files()) { deploymentData.addFile( file, - targetFile(Utils::FilePath::fromString(file), target).parentDir().toString()); + targetFile(Utils::FilePath::fromString(file)).parentDir().toString()); + } + + setDeploymentData(deploymentData); +} + +QVariant QmlBuildSystem::additionalData(Id id) const +{ + if (id == Constants::customFileSelectorsData) + return customFileSelectors(); + return {}; +} + +bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const +{ + if (dynamic_cast<QmlProjectNode *>(context)) { + if (action == AddNewFile || action == EraseFile) + return true; + QTC_ASSERT(node, return false); + + if (action == Rename && node->asFileNode()) { + const FileNode *fileNode = node->asFileNode(); + QTC_ASSERT(fileNode, return false); + return fileNode->fileType() != FileType::Project; + } + + return false; + } + + return BuildSystem::supportsAction(context, action, node); +} + +QmlProject *QmlBuildSystem::qmlProject() const +{ + return static_cast<QmlProject *>(BuildSystem::project()); +} + +bool QmlBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *) +{ + if (!dynamic_cast<QmlProjectNode *>(context)) + return false; + + QStringList toAdd; + foreach (const QString &filePath, filePaths) { + if (!m_projectItem.data()->matchesFile(filePath)) + toAdd << filePaths; + } + return toAdd.isEmpty(); +} + +bool QmlBuildSystem::deleteFiles(Node *context, const QStringList &filePaths) +{ + if (dynamic_cast<QmlProjectNode *>(context)) + return true; + + return BuildSystem::deleteFiles(context, filePaths); +} + +bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const QString &newFilePath) +{ + if (dynamic_cast<QmlProjectNode *>(context)) { + if (filePath.endsWith(mainFile())) { + setMainFile(newFilePath); + + // make sure to change it also in the qmlproject file + const QString qmlProjectFilePath = project()->projectFilePath().toString(); + Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); + const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); + TextEditor::TextDocument *document = nullptr; + if (!editors.isEmpty()) { + document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document()); + if (document && document->isModified()) + if (!Core::DocumentManager::saveDocument(document)) + return false; + } + + QString fileContent; + QString error; + Utils::TextFileFormat textFileFormat; + const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 + if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) + != Utils::TextFileFormat::ReadSuccess) { + qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; + } + + // find the mainFile and do the file name with brackets in a capture group and mask the . with \. + QString originalFileName = QFileInfo(filePath).fileName(); + originalFileName.replace(".", "\\."); + const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName)); + const QRegularExpressionMatch match = expression.match(fileContent); + + fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName()); + + if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) + qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; + + refresh(Everything); + } + + return true; } - target->setDeploymentData(deploymentData); + return BuildSystem::renameFile(context, filePath, newFilePath); } } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index d911d7946e2..2fe1d6dfd77 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -35,19 +35,18 @@ #include <QPointer> -namespace ProjectExplorer { class RunConfiguration; } - namespace QmlProjectManager { class QmlProject; class QmlProjectItem; -namespace Internal { - class QmlBuildSystem : public ProjectExplorer::BuildSystem { public: - explicit QmlBuildSystem(ProjectExplorer::Project *project) : BuildSystem(project) {} + explicit QmlBuildSystem(ProjectExplorer::Target *target); + ~QmlBuildSystem(); + + void triggerParsing() final; bool supportsAction(ProjectExplorer::Node *context, ProjectExplorer::ProjectAction action, @@ -59,20 +58,9 @@ public: bool renameFile(ProjectExplorer::Node *context, const QString &filePath, const QString &newFilePath) override; - QmlProject *project() const; -}; - -} // Internal + QmlProject *qmlProject() const; -class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project -{ - Q_OBJECT - -public: - explicit QmlProject(const Utils::FilePath &filename); - ~QmlProject() override; - - ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final; + QVariant additionalData(Core::Id id) const override; enum RefreshOption { ProjectFile = 0x01, @@ -87,9 +75,8 @@ public: Utils::FilePath canonicalProjectDir() const; QString mainFile() const; void setMainFile(const QString &mainFilePath); - Utils::FilePath targetDirectory(const ProjectExplorer::Target *target) const; - Utils::FilePath targetFile(const Utils::FilePath &sourceFile, - const ProjectExplorer::Target *target) const; + Utils::FilePath targetDirectory() const; + Utils::FilePath targetFile(const Utils::FilePath &sourceFile) const; Utils::EnvironmentItems environment() const; QStringList customImportPaths() const; @@ -101,31 +88,37 @@ public: static QStringList makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths); - QVariant additionalData(Core::Id id, const ProjectExplorer::Target *target) const override; - -protected: - RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; - -private: - ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - void generateProjectTree(); - void updateDeploymentData(ProjectExplorer::Target *target); + void updateDeploymentData(); void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed); void refreshTargetDirectory(); - void addedTarget(ProjectExplorer::Target *target); void onActiveTargetChanged(ProjectExplorer::Target *target); void onKitChanged(); // plain format void parseProject(RefreshOptions options); - ProjectExplorer::Target *m_activeTarget = nullptr; - QPointer<QmlProjectItem> m_projectItem; Utils::FilePath m_canonicalProjectDir; }; +class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project +{ + Q_OBJECT + +public: + explicit QmlProject(const Utils::FilePath &filename); + + ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final; + +protected: + RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override; + +private: + ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; + +}; + } // namespace QmlProjectManager -Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlProject::RefreshOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlBuildSystem::RefreshOptions) diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp index 2d7a4daddb4..cfa6c5e74ed 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp @@ -24,28 +24,19 @@ ****************************************************************************/ #include "qmlprojectnodes.h" -#include "qmlproject.h" -#include <coreplugin/idocument.h> #include <coreplugin/fileiconprovider.h> -#include <coreplugin/documentmanager.h> -#include <coreplugin/editormanager/documentmodel.h> -#include <coreplugin/editormanager/ieditor.h> -#include <projectexplorer/projectexplorer.h> -#include <texteditor/textdocument.h> -#include <utils/algorithm.h> -#include <utils/textfileformat.h> -#include <QRegularExpression> -#include <QTextCodec> +#include <projectexplorer/project.h> +#include <projectexplorer/projectexplorer.h> using namespace ProjectExplorer; namespace QmlProjectManager { namespace Internal { -QmlProjectNode::QmlProjectNode(QmlProject *project) : ProjectNode(project->projectDirectory()), - m_project(project) +QmlProjectNode::QmlProjectNode(Project *project) + : ProjectNode(project->projectDirectory()) { setDisplayName(project->projectFilePath().toFileInfo().completeBaseName()); @@ -53,91 +44,5 @@ QmlProjectNode::QmlProjectNode(QmlProject *project) : ProjectNode(project->proje setIcon(qmlProjectIcon); } -bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const -{ - if (dynamic_cast<QmlProjectNode *>(context)) { - if (action == AddNewFile || action == EraseFile) - return true; - QTC_ASSERT(node, return false); - - if (action == Rename && node->asFileNode()) { - const FileNode *fileNode = node->asFileNode(); - QTC_ASSERT(fileNode, return false); - return fileNode->fileType() != FileType::Project; - } - - return false; - } - - return BuildSystem::supportsAction(context, action, node); -} - -QmlProject *QmlBuildSystem::project() const -{ - return static_cast<QmlProject *>(BuildSystem::project()); -} - -bool QmlBuildSystem::addFiles(Node *context, const QStringList &filePaths, QStringList *notAdded) -{ - if (dynamic_cast<QmlProjectNode *>(context)) - return project()->addFiles(filePaths); - - return BuildSystem::addFiles(context, filePaths, notAdded); -} - -bool QmlBuildSystem::deleteFiles(Node *context, const QStringList &filePaths) -{ - if (dynamic_cast<QmlProjectNode *>(context)) - return true; - - return BuildSystem::deleteFiles(context, filePaths); -} - -bool QmlBuildSystem::renameFile(Node * context, const QString &filePath, const QString &newFilePath) -{ - if (dynamic_cast<QmlProjectNode *>(context)) { - if (filePath.endsWith(project()->mainFile())) { - project()->setMainFile(newFilePath); - - // make sure to change it also in the qmlproject file - const QString qmlProjectFilePath = project()->projectFilePath().toString(); - Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath); - const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath); - TextEditor::TextDocument *document = nullptr; - if (!editors.isEmpty()) { - document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document()); - if (document && document->isModified()) - if (!Core::DocumentManager::saveDocument(document)) - return false; - } - - QString fileContent; - QString error; - Utils::TextFileFormat textFileFormat; - const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8 - if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error) - != Utils::TextFileFormat::ReadSuccess) { - qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error; - } - - // find the mainFile and do the file name with brackets in a capture group and mask the . with \. - QString originalFileName = QFileInfo(filePath).fileName(); - originalFileName.replace(".", "\\."); - const QRegularExpression expression(QString("mainFile:\\s*\"(%1)\"").arg(originalFileName)); - const QRegularExpressionMatch match = expression.match(fileContent); - - fileContent.replace(match.capturedStart(1), match.capturedLength(1), QFileInfo(newFilePath).fileName()); - - if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error)) - qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error; - project()->refresh(QmlProject::Everything); - } - - return true; - } - - return BuildSystem::renameFile(context, filePath, newFilePath); -} - } // namespace Internal } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.h b/src/plugins/qmlprojectmanager/qmlprojectnodes.h index 13c25a31a74..b400a21c69b 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectnodes.h +++ b/src/plugins/qmlprojectmanager/qmlprojectnodes.h @@ -28,18 +28,12 @@ #include <projectexplorer/projectnodes.h> namespace QmlProjectManager { - -class QmlProject; - namespace Internal { class QmlProjectNode : public ProjectExplorer::ProjectNode { public: - QmlProjectNode(QmlProject *project); - -private: - QmlProject *m_project; + explicit QmlProjectNode(ProjectExplorer::Project *project); }; } // namespace Internal diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp index a10ac4fa57b..9979249269e 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.cpp @@ -73,7 +73,7 @@ static bool caseInsensitiveLessThan(const QString &s1, const QString &s2) class MainQmlFileAspect : public ProjectConfigurationAspect { public: - explicit MainQmlFileAspect(QmlProject *project); + explicit MainQmlFileAspect(Target *target); ~MainQmlFileAspect() override { delete m_fileListCombo; } enum MainScriptSource { @@ -97,7 +97,12 @@ public: bool isQmlFilePresent(); public: - QmlProject *m_project; + QmlBuildSystem *qmlBuildSystem() const + { + return static_cast<QmlBuildSystem *>(m_target->buildSystem()); + } + + Target *m_target = nullptr; QPointer<QComboBox> m_fileListCombo; QStandardItemModel m_fileListModel; QString m_scriptFile; @@ -107,8 +112,8 @@ public: QString m_mainScriptFilename; }; -MainQmlFileAspect::MainQmlFileAspect(QmlProject *project) - : m_project(project) +MainQmlFileAspect::MainQmlFileAspect(Target *target) + : m_target(target) , m_scriptFile(M_CURRENT_FILE) { connect(EditorManager::instance(), &EditorManager::currentEditorChanged, @@ -153,7 +158,7 @@ void MainQmlFileAspect::fromMap(const QVariantMap &map) void MainQmlFileAspect::updateFileComboBox() { - QDir projectDir(m_project->projectDirectory().toString()); + QDir projectDir(m_target->project()->projectDirectory().toString()); if (mainScriptSource() == FileInProjectFile) { const QString mainScriptInFilePath = projectDir.relativeFilePath(mainScript()); @@ -170,7 +175,7 @@ void MainQmlFileAspect::updateFileComboBox() m_fileListModel.appendRow(new QStandardItem(QLatin1String(CURRENT_FILE))); QModelIndex currentIndex; - QStringList sortedFiles = Utils::transform(m_project->files(Project::SourceFiles), + QStringList sortedFiles = Utils::transform(m_target->project()->files(Project::SourceFiles), &Utils::FilePath::toString); // make paths relative to project directory @@ -207,7 +212,7 @@ void MainQmlFileAspect::updateFileComboBox() MainQmlFileAspect::MainScriptSource MainQmlFileAspect::mainScriptSource() const { - if (!m_project->mainFile().isEmpty()) + if (!qmlBuildSystem()->mainFile().isEmpty()) return FileInProjectFile; if (!m_mainScriptFilename.isEmpty()) return FileInSettings; @@ -234,7 +239,7 @@ void MainQmlFileAspect::setScriptSource(MainScriptSource source, const QString & m_mainScriptFilename.clear(); } else { // FileInSettings m_scriptFile = settingsPath; - m_mainScriptFilename = m_project->projectDirectory().toString() + '/' + m_scriptFile; + m_mainScriptFilename = m_target->project()->projectDirectory().toString() + '/' + m_scriptFile; } emit changed(); @@ -246,12 +251,12 @@ void MainQmlFileAspect::setScriptSource(MainScriptSource source, const QString & */ QString MainQmlFileAspect::mainScript() const { - if (!m_project->mainFile().isEmpty()) { - const QString pathInProject = m_project->mainFile(); + if (!qmlBuildSystem()->mainFile().isEmpty()) { + const QString pathInProject = qmlBuildSystem()->mainFile(); if (QFileInfo(pathInProject).isAbsolute()) return pathInProject; else - return QDir(m_project->canonicalProjectDir().toString()).absoluteFilePath(pathInProject); + return QDir(qmlBuildSystem()->canonicalProjectDir().toString()).absoluteFilePath(pathInProject); } if (!m_mainScriptFilename.isEmpty()) @@ -279,9 +284,9 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id) { auto envAspect = addAspect<EnvironmentAspect>(); - auto envModifier = [target](Environment env) { - if (auto project = qobject_cast<const QmlProject *>(target->project())) - env.modify(project->environment()); + auto envModifier = [this](Environment env) { + if (auto bs = dynamic_cast<const QmlBuildSystem *>(activeBuildSystem())) + env.modify(bs->environment()); return env; }; @@ -311,9 +316,7 @@ QmlProjectRunConfiguration::QmlProjectRunConfiguration(Target *target, Id id) CommandLine::Raw); }); - auto qmlProject = qobject_cast<QmlProject *>(target->project()); - QTC_ASSERT(qmlProject, return); - m_mainQmlFileAspect = addAspect<MainQmlFileAspect>(qmlProject); + m_mainQmlFileAspect = addAspect<MainQmlFileAspect>(target); connect(m_mainQmlFileAspect, &MainQmlFileAspect::changed, this, &QmlProjectRunConfiguration::updateEnabledState); @@ -329,7 +332,8 @@ Runnable QmlProjectRunConfiguration::runnable() const Runnable r; r.setCommandLine(commandLine()); r.environment = aspect<EnvironmentAspect>()->environment(); - r.workingDirectory = static_cast<QmlProject *>(project())->targetDirectory(target()).toString(); + const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(activeBuildSystem()); + r.workingDirectory = bs->targetDirectory().toString(); return r; } @@ -377,38 +381,35 @@ QString QmlProjectRunConfiguration::commandLineArguments() const { // arguments in .user file QString args = aspect<ArgumentsAspect>()->arguments(macroExpander()); - const Target *currentTarget = target(); - const IDevice::ConstPtr device = DeviceKitAspect::device(currentTarget->kit()); + const IDevice::ConstPtr device = DeviceKitAspect::device(target()->kit()); const Utils::OsType osType = device ? device->osType() : Utils::HostOsInfo::hostOs(); // arguments from .qmlproject file - const QmlProject *project = static_cast<QmlProject *>(currentTarget->project()); + const QmlBuildSystem *bs = static_cast<QmlBuildSystem *>(target()->buildSystem()); foreach (const QString &importPath, - QmlProject::makeAbsolute(project->targetDirectory(currentTarget), project->customImportPaths())) { + QmlBuildSystem::makeAbsolute(bs->targetDirectory(), bs->customImportPaths())) { Utils::QtcProcess::addArg(&args, QLatin1String("-I"), osType); Utils::QtcProcess::addArg(&args, importPath, osType); } - for (const QString &fileSelector : project->customFileSelectors()) { + for (const QString &fileSelector : bs->customFileSelectors()) { Utils::QtcProcess::addArg(&args, QLatin1String("-S"), osType); Utils::QtcProcess::addArg(&args, fileSelector, osType); } - const QString main = project->targetFile(Utils::FilePath::fromString(mainScript()), - currentTarget).toString(); + const QString main = bs->targetFile(FilePath::fromString(mainScript())).toString(); if (!main.isEmpty()) Utils::QtcProcess::addArg(&args, main, osType); return args; } -void QmlProjectRunConfiguration::updateEnabledState() +bool QmlProjectRunConfiguration::isEnabled() const { - bool enabled = false; if (m_mainQmlFileAspect->isQmlFilePresent() && !commandLine().executable().isEmpty()) { - Project *p = target()->project(); - enabled = !p->isParsing() && p->hasParsingData(); + BuildSystem *bs = activeBuildSystem(); + return !bs->isParsing() && bs->hasParsingData(); } - setEnabled(enabled); + return false; } bool MainQmlFileAspect::isQmlFilePresent() @@ -430,7 +431,7 @@ bool MainQmlFileAspect::isQmlFilePresent() || mainScriptMimeType.matchesName(QLatin1String(QmlJSTools::Constants::QMLPROJECT_MIMETYPE))) { // find a qml file with lowercase filename. This is slow, but only done // in initialization/other border cases. - const auto files = m_project->files(Project::SourceFiles); + const auto files = m_target->project()->files(Project::SourceFiles); for (const Utils::FilePath &filename : files) { const QFileInfo fi = filename.toFileInfo(); diff --git a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h index 8a18fd0ef97..9d810671f11 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h +++ b/src/plugins/qmlprojectmanager/qmlprojectrunconfiguration.h @@ -44,7 +44,7 @@ public: private: ProjectExplorer::Runnable runnable() const final; QString disabledReason() const final; - void updateEnabledState() final; + bool isEnabled() const final; QString mainScript() const; QString theExecutable() const; diff --git a/src/plugins/qnx/qnxrunconfiguration.cpp b/src/plugins/qnx/qnxrunconfiguration.cpp index d9b35222077..74481cfabd5 100644 --- a/src/plugins/qnx/qnxrunconfiguration.cpp +++ b/src/plugins/qnx/qnxrunconfiguration.cpp @@ -82,7 +82,7 @@ QnxRunConfiguration::QnxRunConfiguration(Target *target, Core::Id id) connect(target, &Target::deploymentDataChanged, this, updateTargetInformation); connect(target, &Target::applicationTargetsChanged, this, updateTargetInformation); - connect(target->project(), &Project::parsingFinished, this, updateTargetInformation); + connect(target, &Target::parsingFinished, this, updateTargetInformation); connect(target, &Target::kitChanged, this, updateTargetInformation); } diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index 7ddb4c9083f..c902bd2f420 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -27,6 +27,7 @@ #include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildsteplist.h> +#include <projectexplorer/buildsystem.h> #include <projectexplorer/deployconfiguration.h> #include <projectexplorer/processparameters.h> #include <projectexplorer/runconfigurationaspects.h> @@ -167,7 +168,7 @@ void MakeInstallStep::finish(bool success) m_deploymentData.addFile(fi.filePath(), fi.dir().path().mid(installRoot().toString().length())); } - target()->setDeploymentData(m_deploymentData); + buildSystem()->setDeploymentData(m_deploymentData); } else if (m_noInstallTarget && m_isCmakeProject) { emit addTask(Task(Task::Warning, tr("You need to add an install statement to your " "CMakeLists.txt file for deployment to work."), diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp index 745858dd416..7c1d7403670 100644 --- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp @@ -72,7 +72,7 @@ RemoteLinuxRunConfiguration::RemoteLinuxRunConfiguration(Target *target, Core::I this, &RemoteLinuxRunConfiguration::updateTargetInformation); connect(target, &Target::applicationTargetsChanged, this, &RemoteLinuxRunConfiguration::updateTargetInformation); - connect(target->project(), &Project::parsingFinished, + connect(target, &Target::parsingFinished, this, &RemoteLinuxRunConfiguration::updateTargetInformation); connect(target, &Target::kitChanged, this, &RemoteLinuxRunConfiguration::updateTargetInformation); |