diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt index 3b7209d05c7..9b6e7609176 100644 --- a/src/plugins/qmlprojectmanager/CMakeLists.txt +++ b/src/plugins/qmlprojectmanager/CMakeLists.txt @@ -1,7 +1,7 @@ add_qtc_plugin(QmlProjectManager CONDITION TARGET Qt5::QuickWidgets PLUGIN_CLASS QmlProjectPlugin - DEPENDS QmlJS Qt5::QuickWidgets Utils + DEPENDS QmlJS Qt5::QuickWidgets Utils McuSupport CMakeProjectManager PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesignerBase SOURCES qmlprojectgen/qmlprojectgenerator.cpp qmlprojectgen/qmlprojectgenerator.h @@ -21,6 +21,7 @@ add_qtc_plugin(QmlProjectManager qmlprojectplugin.cpp qmlprojectplugin.h qmlprojectrunconfiguration.cpp qmlprojectrunconfiguration.h buildsystem/qmlbuildsystem.cpp buildsystem/qmlbuildsystem.h + mcubuildstep.cpp mcubuildstep.h "${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc" ) diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp index 869e5b89c74..0872f24ede5 100644 --- a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp +++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp @@ -3,6 +3,7 @@ #include "qmlbuildsystem.h" #include "qmlprojectconstants.h" +#include "mcubuildstep.h" #include #include @@ -49,7 +50,11 @@ QmlBuildSystem::QmlBuildSystem(Target *target) updateDeploymentData(); registerMenuButtons(); - connect(target->project(), &Project::activeTargetChanged, [this]() { refresh(RefreshOptions::NoFileRefresh); }); + connect(target->project(), &Project::activeTargetChanged, [this](Target *target) { + refresh(RefreshOptions::NoFileRefresh); + if (qtForMCUs()) + MCUBuildStepFactory::attachToTarget(target); + }); connect(target->project(), &Project::projectFileIsDirty, [this]() { refresh(RefreshOptions::Project); }); diff --git a/src/plugins/qmlprojectmanager/mcubuildstep.cpp b/src/plugins/qmlprojectmanager/mcubuildstep.cpp new file mode 100644 index 00000000000..7ee5bc83939 --- /dev/null +++ b/src/plugins/qmlprojectmanager/mcubuildstep.cpp @@ -0,0 +1,197 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "mcubuildstep.h" + +#include "projectexplorer/buildstep.h" +#include "projectexplorer/buildsystem.h" +#include "projectexplorer/buildsteplist.h" +#include "projectexplorer/deployconfiguration.h" +#include "projectexplorer/kit.h" +#include "projectexplorer/target.h" +#include "projectexplorer/kitmanager.h" + +#include +#include + +#include "qtsupport/qtsupportconstants.h" +#include "mcusupport/mcusupportconstants.h" +#include "mcusupport/mculegacyconstants.h" + +#include "utils/aspects.h" +#include "utils/filepath.h" + +#include + +namespace QmlProjectManager { + +const Utils::Id DeployMcuProcessStep::id = "QmlProject.Mcu.DeployStep"; +const QString DeployMcuProcessStep::processCommandKey = "QmlProject.Mcu.ProcessStep.Command"; +const QString DeployMcuProcessStep::processArgumentsKey = "QmlProject.Mcu.ProcessStep.Arguments"; +const QString DeployMcuProcessStep::processWorkingDirectoryKey = "QmlProject.Mcu.ProcessStep.BuildDirectory"; + +void DeployMcuProcessStep::showError(const QString& text) { + Core::AsynchronousMessageBox::critical(tr("Qt4MCU Deploy Step"), text); +} + +// TODO: +// - Grabbing *a* kit might not be the best todo. +// Would be better to specify a specific version of Qt4MCU in the qmlproject file. +// Currently we use the kit with the greatest version number. +// +// - Do not compare to *legacy* constants. +// Sounds like they will stop existing at some point. +// Also: Find Constant for QUL_PLATFORM + +DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id) + : AbstractProcessStep(bc, id) + , m_tmpDir() +{ + if (not buildSystem()) { + showError(QObject::tr("Failed to find valid build system")); + return; + } + + if (not m_tmpDir.isValid()) { + showError(QObject::tr("Failed to create valid build directory")); + return; + } + + auto fixPath = [](const QString& path) -> QString { + return "\"" + QDir::toNativeSeparators(path) + "\""; + }; + + ProjectExplorer::Kit* kit = MCUBuildStepFactory::findMostRecentQulKit(); + if (not kit) + return; + + QString root = findKitInformation(kit, McuSupport::Internal::Legacy::Constants::QUL_CMAKE_VAR); + + auto* cmd = addAspect(); + cmd->setSettingsKey(processCommandKey); + cmd->setDisplayStyle(Utils::StringAspect::PathChooserDisplay); + cmd->setExpectedKind(Utils::PathChooser::Command); + cmd->setLabelText(tr("Command:")); + cmd->setValue(QDir::toNativeSeparators(root + "/bin/qmlprojectexporter")); + + const char* importPathConstant = QtSupport::Constants::KIT_QML_IMPORT_PATH; + QString projectDir = buildSystem()->projectDirectory().toString(); + QString qulIncludeDir = kit->value(importPathConstant).toString( ); + QStringList includeDirs { + fixPath(qulIncludeDir), + fixPath(qulIncludeDir + "/Timeline"), + fixPath(projectDir + "/imports") + }; + + const char* toolChainConstant = McuSupport::Internal::Constants::KIT_MCUTARGET_TOOLCHAIN_KEY; + QStringList arguments = { + fixPath(buildSystem()->projectFilePath().toString()), + "--platform", findKitInformation(kit, "QUL_PLATFORM"), + "--toolchain", kit->value(toolChainConstant).toString( ), + "--include-dirs", includeDirs.join(","), + }; + + auto* args = addAspect(); + args->setSettingsKey(processArgumentsKey); + args->setDisplayStyle(Utils::StringAspect::LineEditDisplay); + args->setLabelText(tr("Arguments:")); + args->setValue(arguments.join(" ")); + + auto* outDir = addAspect(); + outDir->setSettingsKey(processWorkingDirectoryKey); + outDir->setDisplayStyle(Utils::StringAspect::PathChooserDisplay); + outDir->setExpectedKind(Utils::PathChooser::Directory); + outDir->setLabelText(tr("Build directory:")); + outDir->setPlaceHolderText(fixPath(m_tmpDir.path())); + + setCommandLineProvider([this, cmd, args, outDir, fixPath]() -> Utils::CommandLine { + auto directory = outDir->value(); + if (directory.isEmpty()) + directory = fixPath(m_tmpDir.path()); + + QString outArg = " --outdir " + directory; + return {cmd->filePath(), args->value() + outArg, Utils::CommandLine::Raw}; + }); +} + +bool DeployMcuProcessStep::init() +{ + if (!AbstractProcessStep::init()) + return false; + return true; +} + +void DeployMcuProcessStep::doRun() +{ + AbstractProcessStep::doRun(); +} + +QString DeployMcuProcessStep::findKitInformation(ProjectExplorer::Kit* kit, const QString& key) +{ + // This is (kind of) stolen from mcukitmanager.cpp. Might make sense to unify. + using namespace CMakeProjectManager; + const auto config = CMakeConfigurationKitAspect::configuration(kit).toList(); + const auto keyName = key.toUtf8(); + for (const CMakeProjectManager::CMakeConfigItem &configItem : config) { + if (configItem.key == keyName) + return QString::fromUtf8(configItem.value); + } + return {}; +} + + +MCUBuildStepFactory::MCUBuildStepFactory() + : BuildStepFactory() +{ + setDisplayName("Qt4MCU Deploy Step"); + registerStep< DeployMcuProcessStep >(DeployMcuProcessStep::id); +} + +void MCUBuildStepFactory::attachToTarget(ProjectExplorer::Target *target) +{ + if (not target) + return; + + ProjectExplorer::DeployConfiguration* deployConfiguration = target->activeDeployConfiguration(); + ProjectExplorer::BuildStepList* stepList = deployConfiguration->stepList(); + if (stepList->contains(DeployMcuProcessStep::id)) + return; + + if (not findMostRecentQulKit()) { + DeployMcuProcessStep::showError(QObject::tr("Failed to find valid Qt4MCU kit")); + return; + } + + for (BuildStepFactory *factory : BuildStepFactory::allBuildStepFactories()) { + if (factory->stepId() == DeployMcuProcessStep::id) { + ProjectExplorer::BuildStep* deployConfig = factory->create(stepList); + stepList->appendStep(deployConfig); + } + } +} + +ProjectExplorer::Kit* MCUBuildStepFactory::findMostRecentQulKit() +{ + // Stolen from mcukitmanager.cpp + auto kitQulVersion = [](const ProjectExplorer::Kit *kit) -> QVersionNumber { + const char* sdkVersion = McuSupport::Internal::Constants::KIT_MCUTARGET_SDKVERSION_KEY; + return QVersionNumber::fromString(kit->value(sdkVersion).toString()); + }; + + ProjectExplorer::Kit* kit = nullptr; + for (auto k : ProjectExplorer::KitManager::kits()) + { + auto qulVersion = kitQulVersion(k); + if (qulVersion.isNull( )) + continue; + + if (not kit) + kit = k; + + if (qulVersion > kitQulVersion(kit)) + kit = k; + } + return kit; +} + +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/mcubuildstep.h b/src/plugins/qmlprojectmanager/mcubuildstep.h new file mode 100644 index 00000000000..e1167e1917a --- /dev/null +++ b/src/plugins/qmlprojectmanager/mcubuildstep.h @@ -0,0 +1,42 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +#pragma once + +#include "projectexplorer/kit.h" +#include "projectexplorer/project.h" +#include +#include +#include + +#include + +namespace QmlProjectManager { + +class DeployMcuProcessStep : public ProjectExplorer::AbstractProcessStep +{ +public: + static const Utils::Id id; + static void showError(const QString& text); + + DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id); + +private: + bool init() override; + void doRun() override; + QString findKitInformation(ProjectExplorer::Kit* kit, const QString& key); + + static const QString processCommandKey; + static const QString processArgumentsKey; + static const QString processWorkingDirectoryKey; + QTemporaryDir m_tmpDir; +}; + +class MCUBuildStepFactory : public ProjectExplorer::BuildStepFactory +{ +public: + MCUBuildStepFactory(); + static void attachToTarget(ProjectExplorer::Target *target); + static ProjectExplorer::Kit* findMostRecentQulKit( ); +}; + +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index 0a87ef9bc90..dd33508636c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "mcubuildstep.h" #include "qdslandingpage.h" #include "qmlprojectplugin.h" #include "qmlproject.h" @@ -93,6 +94,7 @@ public: QPointer lastMessageBox; QdsLandingPage *landingPage = nullptr; QdsLandingPageWidget *landingPageWidget = nullptr; + MCUBuildStepFactory mcuBuildStepFactory; }; QmlProjectPlugin::~QmlProjectPlugin()