diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt index 4f6eb8eba41..2c7b143d901 100644 --- a/src/plugins/qmlprojectmanager/CMakeLists.txt +++ b/src/plugins/qmlprojectmanager/CMakeLists.txt @@ -48,6 +48,7 @@ extend_qtc_plugin(QmlProjectManager cmakewriter.cpp cmakewriter.h cmakewriterv0.cpp cmakewriterv0.h cmakewriterv1.cpp cmakewriterv1.h + cmakewriterlib.cpp cmakewriterlib.h exporter.cpp exporter.h filegenerator.cpp filegenerator.h filetypes.cpp filetypes.h diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc index 50e9909a17c..822a2f807bd 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc @@ -2,6 +2,7 @@ templates/cmakeroot_v0.tpl templates/cmakeroot_v1.tpl + templates/cmakeroot_lib.tpl templates/main_cpp_v0.tpl templates/main_cpp_v1.tpl templates/cmakemodule_v1.tpl diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp index aeb065a4f17..31d1d75d834 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp @@ -11,10 +11,12 @@ #include "projectexplorer/projectnodes.h" #include "utils/filenamevalidatinglineedit.h" +#include "utils/persistentsettings.h" #include #include #include +#include #include @@ -60,7 +62,12 @@ void CMakeGenerator::updateProject(QmlProject *project) if (!isEnabled()) return; - m_writer = CMakeWriter::create(this); + if (!isActive()) + return; + + createWriter(); + if (!m_writer) + return; m_root = std::make_shared(); m_root->type = Node::Type::App; @@ -85,6 +92,14 @@ QString CMakeGenerator::projectName() const return m_projectName; } +Utils::FilePath CMakeGenerator::projectDir() const +{ + if (!m_root) + return {}; + + return m_root->dir; +} + bool CMakeGenerator::findFile(const Utils::FilePath& file) const { return findFile(m_root, file); @@ -440,6 +455,18 @@ void CMakeGenerator::removeFile(NodePtr &node, const Utils::FilePath &path) cons } } +void CMakeGenerator::removeAmbiguousFiles(const Utils::FilePath &rootPath) const +{ + const Utils::FilePath rootCMakeFile = rootPath.pathAppended("CMakeLists.txt"); + rootCMakeFile.removeFile(); + + const Utils::FilePath sourceDirPath = rootPath.pathAppended("App"); + if (sourceDirPath.exists()) { + const Utils::FilePath appCMakeFile = sourceDirPath.pathAppended("CMakeLists.txt"); + appCMakeFile.removeFile(); + } +} + void CMakeGenerator::printModules(const NodePtr &node) const { if (node->type == Node::Type::Module) @@ -470,11 +497,12 @@ void CMakeGenerator::printNodeTree(const NodePtr &generatorNode, size_t indent) case Node::Type::Module: typeString = "Node::Type::Module"; break; + case Node::Type::MockModule: + typeString = "Node::Type::MockModule"; + break; case Node::Type::Library: typeString = "Node::Type::Library"; break; - default: - typeString = "Node::Type::Undefined"; } qDebug() << addIndent(indent) << "GeneratorNode: " << generatorNode->name; @@ -517,7 +545,11 @@ void CMakeGenerator::parseSourceTree() { QTC_ASSERT(m_writer, return); - const Utils::FilePath srcDir = m_root->dir.pathAppended(m_writer->sourceDirName()); + QString srcDirName = m_writer->sourceDirName(); + if (srcDirName.isEmpty()) + return; + + const Utils::FilePath srcDir = m_root->dir.pathAppended(srcDirName); QDirIterator it(srcDir.path(), {"*.cpp"}, QDir::Files, QDirIterator::Subdirectories); NodePtr srcNode = std::make_shared(); @@ -560,5 +592,62 @@ void CMakeGenerator::compareWithFileSystem(const NodePtr &node) const logIssue(ProjectExplorer::Task::Warning, text, file); } +void CMakeGenerator::createWriter() +{ + auto writer = CMakeWriter::create(this); + + const QmlProject *project = qmlProject(); + QTC_ASSERT(project, return ); + + const Utils::FilePath rootPath = project->projectDirectory(); + const Utils::FilePath settingsFile = rootPath.pathAppended("CMakeLists.txt.shared"); + Utils::PersistentSettingsReader reader; + reader.load(settingsFile); + auto store = reader.restoreValues(); + + auto writeSettings = [settingsFile, &store](int identifier) { + store["CMake Generator"] = identifier; + QString error; + Utils::PersistentSettingsWriter settingsWriter(settingsFile, "QtCreatorProject"); + if (!settingsWriter.save(store, &error)) { + const QString text("Failed to write settings file"); + logIssue(ProjectExplorer::Task::Error, text, settingsFile); + } + }; + + QVariant idVariant = store["CMake Generator"]; + if (!idVariant.isValid()) { + writeSettings(writer->identifier()); + m_writer = writer; + return; + } + + int identifier = writer->identifier(); + int currentId = idVariant.toInt(); + if (currentId == identifier) { + m_writer = writer; + return; + } + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setText("The CmakeGenerator Has Changed"); + msgBox.setInformativeText( + "This operation will delete build files that may contain" + " user-made changes. Are you sure you want to proceed?"); + int ret = msgBox.exec(); + + if (ret == QMessageBox::Cancel) { + m_writer = CMakeWriter::createAndRecover(currentId, this); + return; + } + + removeAmbiguousFiles( rootPath ); + + writeSettings(writer->identifier()); + m_writer = writer; +} + } // namespace QmlProjectExporter } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h index ed03b36994c..f1225f858e2 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h @@ -33,6 +33,8 @@ public: void updateMenuAction() override; QString projectName() const; + Utils::FilePath projectDir() const; + bool findFile(const Utils::FilePath &file) const; bool isRootNode(const NodePtr &node) const; bool hasChildModule(const NodePtr &node) const; @@ -57,6 +59,7 @@ private: bool findFile(const NodePtr &node, const Utils::FilePath &file) const; void insertFile(NodePtr &node, const Utils::FilePath &path) const; void removeFile(NodePtr &node, const Utils::FilePath &path) const; + void removeAmbiguousFiles(const Utils::FilePath &rootPath) const; void printModules(const NodePtr &generatorNode) const; void printNodeTree(const NodePtr &generatorNode, size_t indent = 0) const; @@ -66,6 +69,7 @@ private: void compareWithFileSystem(const NodePtr &node) const; + void createWriter(); CMakeWriter::Ptr m_writer = {}; QString m_projectName = {}; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp index 9385e40dd99..63384debddf 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp @@ -4,6 +4,7 @@ #include "cmakegenerator.h" #include "cmakewriterv0.h" #include "cmakewriterv1.h" +#include "cmakewriterlib.h" #include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" #include "qmlprojectmanager/qmlproject.h" @@ -42,14 +43,24 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent) const QmlBuildSystem *buildSystem = parent->buildSystem(); QTC_ASSERT(buildSystem, return {}); - auto [major, minor, patch] = versionFromString(buildSystem->versionDesignStudio()); + auto version = versionFromString(buildSystem->versionDesignStudio()); + auto normalizedVersion = normalizeVersion(version); - bool useV1 = false; - if (major.has_value()) - useV1 = minor.has_value() ? *major >= 4 && *minor >= 5 : *major >= 5; - - if (useV1) + if (normalizedVersion >= std::make_tuple(4, 5, 0)) { + if (!buildSystem->standaloneApp()) { + if (normalizedVersion >= std::make_tuple(4, 8, 0)) { + return std::make_unique(parent); + } else { + CMakeGenerator::logIssue( + ProjectExplorer::Task::Error, + Tr::tr( + "Compiling the project as a library requires" + " Qt Design Studio 4.8 or later."), + buildSystem->projectFilePath()); + } + } return std::make_unique(parent); + } CMakeGenerator::logIssue( ProjectExplorer::Task::Warning, @@ -67,6 +78,24 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent) return std::make_unique(parent); } +CMakeWriter::Ptr CMakeWriter::createAndRecover(int id, CMakeGenerator *parent) +{ + switch (id) + { + case 1: + return std::make_unique(parent); + case 2: + parent->setStandaloneApp(true); + return std::make_unique(parent); + case 3: + parent->setStandaloneApp(false); + return std::make_unique(parent); + default: + break; + } + return {}; +} + CMakeWriter::Version CMakeWriter::versionFromString(const QString &versionString) { const QStringList versions = versionString.split('.', Qt::SkipEmptyParts); @@ -98,6 +127,12 @@ CMakeWriter::Version CMakeWriter::versionFromIgnoreFile(const Utils::FilePath &p return {}; } +CMakeWriter::NormalizedVersion CMakeWriter::normalizeVersion(const Version &version) +{ + auto [major, minor, patch] = version; + return {major.value_or(0), minor.value_or(0), patch.value_or(0)}; +} + QString CMakeWriter::readTemplate(const QString &templatePath) { QFile templatefile(templatePath); @@ -149,6 +184,19 @@ QString CMakeWriter::sourceDirName() const void CMakeWriter::transformNode(NodePtr &) const {} +bool CMakeWriter::hasNewComponents() const +{ + auto rootDir = m_parent->projectDir(); + auto componentsDir = rootDir.pathAppended("Dependencies/Components"); + + if (!componentsDir.exists()) + return false; + + auto ignoreFile = componentsDir.pathAppended("ignore-in-qds"); + auto version = normalizeVersion(versionFromIgnoreFile(ignoreFile)); + return version >= std::make_tuple(4, 8, 0); +} + std::vector CMakeWriter::files(const NodePtr &node, const FileGetter &getter) const { std::vector out = getter(node); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h index 15f3e090b91..481f702909f 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h @@ -63,10 +63,14 @@ class CMakeWriter public: using Ptr = std::shared_ptr; using Version = std::tuple, std::optional, std::optional>; + using NormalizedVersion = std::tuple; static Ptr create(CMakeGenerator *parent); + static Ptr createAndRecover(int id, CMakeGenerator *parent); + static Version versionFromString(const QString &versionString); static Version versionFromIgnoreFile(const Utils::FilePath &path); + static NormalizedVersion normalizeVersion(const Version &version); static QString readTemplate(const QString &templatePath); static void writeFile(const Utils::FilePath &path, const QString &content); @@ -79,11 +83,14 @@ public: virtual QString sourceDirName() const; virtual void transformNode(NodePtr &) const; + virtual int identifier() const = 0; virtual void writeRootCMakeFile(const NodePtr &node) const = 0; virtual void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const = 0; virtual void writeSourceFiles(const NodePtr &node, const NodePtr &root) const = 0; protected: + bool hasNewComponents() const; + std::vector files(const NodePtr &node, const FileGetter &getter) const; std::vector qmlFiles(const NodePtr &node) const; std::vector singletons(const NodePtr &node) const; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp new file mode 100644 index 00000000000..7a2985a7b96 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "cmakewriterlib.h" +#include "cmakegenerator.h" + +#include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" + +#include + +namespace QmlProjectManager { + +namespace QmlProjectExporter { + +CMakeWriterLib::CMakeWriterLib(CMakeGenerator *parent) + : CMakeWriterV1(parent) +{ } + +QString CMakeWriterLib::mainLibName() const +{ + QTC_ASSERT(parent(), return {}); + return parent()->projectName() + "Lib"; +} + +void CMakeWriterLib::transformNode(NodePtr &node) const +{ + CMakeWriterV1::transformNode(node); +} + +int CMakeWriterLib::identifier() const +{ + return 3; +} + +void CMakeWriterLib::writeRootCMakeFile(const NodePtr &node) const +{ + QTC_ASSERT(parent(), return); + + const Utils::FilePath cmakeFolderPath = node->dir.pathAppended("cmake"); + if (!cmakeFolderPath.exists()) + cmakeFolderPath.createDir(); + + const Utils::FilePath insightPath = cmakeFolderPath.pathAppended("insight.cmake"); + if (!insightPath.exists()) { + const QString insightTemplate = readTemplate(":/templates/insight"); + writeFile(insightPath, insightTemplate); + } + + createDependencies(node->dir); + + const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared"); + if (!sharedFile.exists()) { + const QString sharedTemplate = readTemplate(":/templates/cmake_shared"); + writeFile(sharedFile, sharedTemplate); + } + + const Utils::FilePath file = node->dir.pathAppended("CMakeLists.txt"); + if (!file.exists()) { + QString fileSection = ""; + const QString configFile = getEnvironmentVariable(ENV_VARIABLE_CONTROLCONF); + if (!configFile.isEmpty()) + fileSection = QString("\t\t%1").arg(configFile); + + const QString fileTemplate = readTemplate(":/templates/cmakeroot_lib"); + const QString fileContent = fileTemplate.arg(mainLibName(), fileSection); + writeFile(file, fileContent); + } +} + +void CMakeWriterLib::writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const +{ + CMakeWriterV1::writeModuleCMakeFile(node, root); +} + +void CMakeWriterLib::writeSourceFiles(const NodePtr &node, const NodePtr &root) const +{ + QTC_ASSERT(parent(), return); + QTC_ASSERT(parent()->buildSystem(), return); + + const QmlBuildSystem *buildSystem = parent()->buildSystem(); + + const Utils::FilePath srcDir = node->dir; + if (!srcDir.exists()) + srcDir.createDir(); + + const Utils::FilePath cmakePath = srcDir.pathAppended("CMakeLists.txt"); + if (!cmakePath.exists()) { + const QString includeAutogen = + "\ntarget_include_directories(%1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})"; + writeFile(cmakePath, includeAutogen.arg(mainLibName())); + } + + const Utils::FilePath autogenDir = srcDir.pathAppended("autogen"); + if (!autogenDir.exists()) + autogenDir.createDir(); + + const Utils::FilePath headerPath = autogenDir.pathAppended("environment.h"); + + QString environmentPrefix; + for (const QString &module : plugins(root)) + environmentPrefix.append(QString("Q_IMPORT_QML_PLUGIN(%1)\n").arg(module + "Plugin")); + + const QString mainFile("const char mainQmlFile[] = \"qrc:/qt/qml/%1\";"); + environmentPrefix.append("\n"); + environmentPrefix.append(mainFile.arg(buildSystem->mainFile())); + + const QString environmentPostfix = makeSetEnvironmentFn(); + const QString headerTemplate = readTemplate(":/templates/environment_h"); + writeFile(headerPath, headerTemplate.arg(environmentPrefix, environmentPostfix)); +} + +} // namespace QmlProjectExporter +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h new file mode 100644 index 00000000000..5b957d47937 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h @@ -0,0 +1,26 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + +#include "cmakewriterv1.h" + +namespace QmlProjectManager { + +namespace QmlProjectExporter { + +class CMakeWriterLib final : public CMakeWriterV1 +{ +public: + CMakeWriterLib(CMakeGenerator *parent); + + QString mainLibName() const override; + void transformNode(NodePtr &node) const override; + + int identifier() const override; + void writeRootCMakeFile(const NodePtr &node) const override; + void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; + void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; +}; + +} // namespace QmlProjectExporter +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp index 41cd2e52e9a..7b4cb9984f8 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp @@ -46,6 +46,11 @@ void CMakeWriterV0::transformNode(NodePtr &node) const } } +int CMakeWriterV0::identifier() const +{ + return 1; +} + void CMakeWriterV0::writeRootCMakeFile(const NodePtr &node) const { QTC_ASSERT(parent(), return); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h index b7f47f0d547..747b0389e7a 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h @@ -16,6 +16,7 @@ public: bool isPlugin(const NodePtr &node) const override; void transformNode(NodePtr &node) const override; + int identifier() const override; void writeRootCMakeFile(const NodePtr &node) const override; void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp index 5593f556178..1cfbdb8add8 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp @@ -33,6 +33,11 @@ CMakeWriterV1::CMakeWriterV1(CMakeGenerator *parent) : CMakeWriter(parent) {} +QString CMakeWriterV1::mainLibName() const +{ + return "${CMAKE_PROJECT_NAME}"; +} + QString CMakeWriterV1::sourceDirName() const { return "App"; @@ -47,6 +52,11 @@ void CMakeWriterV1::transformNode(NodePtr &node) const node->type = Node::Type::Module; } +int CMakeWriterV1::identifier() const +{ + return 2; +} + void CMakeWriterV1::writeRootCMakeFile(const NodePtr &node) const { QTC_ASSERT(parent(), return); @@ -62,72 +72,7 @@ void CMakeWriterV1::writeRootCMakeFile(const NodePtr &node) const writeFile(insightPath, insightTemplate); } - const Utils::FilePath dependenciesPath = node->dir.pathAppended(DEPENDENCIES_DIR); - const Utils::FilePath componentsPath = dependenciesPath.pathAppended(COMPONENTS_DIR); - const Utils::FilePath componentsIgnoreFile = componentsPath.pathAppended(COMPONENTS_IGNORE_FILE); - - bool copyComponents = false; - // Note: If dependencies directory exists but not the components directory, we assunme - // the user has intentionally deleted it because he has the components installed in Qt. - if (!dependenciesPath.exists()) { - dependenciesPath.createDir(); - copyComponents = true; - } else if (componentsIgnoreFile.exists()) { - auto normalizeVersion = [](const auto &version) -> std::tuple { - auto [major, minor, patch] = version; - return {major.value_or(0), minor.value_or(0), patch.value_or(0)}; - }; - auto *bs = parent()->buildSystem(); - auto versionDS = normalizeVersion(versionFromString(bs->versionDesignStudio())); - auto versionIgnore = normalizeVersion(versionFromIgnoreFile(componentsIgnoreFile)); - if (versionDS > versionIgnore) { - copyComponents = true; - if (componentsPath.exists()) - componentsPath.removeRecursively(); - } - } - - if (copyComponents) { - if (!componentsPath.exists()) - componentsPath.createDir(); - - const Utils::FilePath componentsSrc = - Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components"); - - if (componentsSrc.exists()) { - auto cpyResult = componentsSrc.copyRecursively(componentsPath); - if (cpyResult) { - QString depsTemplate = - QString::fromUtf8(TEMPLATE_DEPENDENCIES_CMAKELISTS, -1).arg(COMPONENTS_DIR); - writeFile(dependenciesPath.pathAppended("CMakeLists.txt"), depsTemplate); - - const Utils::FilePath qmlComponentsFilePath = - cmakeFolderPath.pathAppended("qmlcomponents.cmake"); - - if (qmlComponentsFilePath.exists()) { - - const QString warningMsg = Tr::tr( - "The project structure has changed.\n" - "Please clean the build folder before rebuilding\n"); - - CMakeGenerator::logIssue( - ProjectExplorer::Task::Warning, warningMsg, componentsPath); - - auto removeResult = qmlComponentsFilePath.removeFile(); - if (!removeResult) { - QString removeMsg = Tr::tr("Failed to remove the qmlcomponents.cmake file.\n"); - removeMsg.append(removeResult.error()); - - CMakeGenerator::logIssue( - ProjectExplorer::Task::Warning, removeMsg, qmlComponentsFilePath); - } - } - } else { - CMakeGenerator::logIssue( - ProjectExplorer::Task::Error, cpyResult.error(), componentsSrc); - } - } - } + createDependencies(node->dir); const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared"); if (!sharedFile.exists()) { @@ -179,12 +124,15 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c pluginNames.append("\n"); } + if (hasNewComponents()) + pluginNames.append(QString("\n\t") + "QtQuickDesignerComponents"); + QString linkLibrariesTemplate( - "target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE\n" - "%1)"); + "target_link_libraries(%1 PRIVATE\n" + "%2)"); userFileContent.append("\n"); - userFileContent.append(linkLibrariesTemplate.arg(pluginNames)); + userFileContent.append(linkLibrariesTemplate.arg(mainLibName(), pluginNames)); writeFile(userFile, userFileContent); return; } @@ -265,5 +213,78 @@ void CMakeWriterV1::writeSourceFiles(const NodePtr &node, const NodePtr &root) c writeFile(headerPath, headerTemplate.arg(environmentPrefix, environmentPostfix)); } +void CMakeWriterV1::createDependencies(const Utils::FilePath &rootDir) const +{ + const Utils::FilePath dependenciesPath = rootDir.pathAppended(DEPENDENCIES_DIR); + const Utils::FilePath componentsPath = dependenciesPath.pathAppended(COMPONENTS_DIR); + const Utils::FilePath componentsIgnoreFile = componentsPath.pathAppended(COMPONENTS_IGNORE_FILE); + + bool copyComponents = false; + // Note: If dependencies directory exists but not the components directory, we assunme + // the user has intentionally deleted it because he has the components installed in Qt. + if (!dependenciesPath.exists()) { + dependenciesPath.createDir(); + copyComponents = true; + } else if (componentsIgnoreFile.exists()) { + auto *bs = parent()->buildSystem(); + auto versionDS = normalizeVersion(versionFromString(bs->versionDesignStudio())); + auto versionIgnore = normalizeVersion(versionFromIgnoreFile(componentsIgnoreFile)); + if (versionDS > versionIgnore) { + copyComponents = true; + if (componentsPath.exists()) + componentsPath.removeRecursively(); + } + } + + if (copyComponents) { + if (!componentsPath.exists()) + componentsPath.createDir(); + + Utils::FilePath componentsSrc = + Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components"); + + const Utils::FilePath unifiedPath = + Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components/components"); + + if (unifiedPath.exists( )) + componentsSrc = unifiedPath; + + if (componentsSrc.exists()) { + auto cpyResult = componentsSrc.copyRecursively(componentsPath); + if (cpyResult) { + QString depsTemplate = + QString::fromUtf8(TEMPLATE_DEPENDENCIES_CMAKELISTS, -1).arg(COMPONENTS_DIR); + writeFile(dependenciesPath.pathAppended("CMakeLists.txt"), depsTemplate); + + const Utils::FilePath cmakeFolderPath = rootDir.pathAppended("cmake"); + const Utils::FilePath qmlComponentsFilePath = + cmakeFolderPath.pathAppended("qmlcomponents.cmake"); + + if (qmlComponentsFilePath.exists()) { + + const QString warningMsg = Tr::tr( + "The project structure has changed.\n" + "Please clean the build folder before rebuilding\n"); + + CMakeGenerator::logIssue( + ProjectExplorer::Task::Warning, warningMsg, componentsPath); + + auto removeResult = qmlComponentsFilePath.removeFile(); + if (!removeResult) { + QString removeMsg = Tr::tr("Failed to remove the qmlcomponents.cmake file.\n"); + removeMsg.append(removeResult.error()); + + CMakeGenerator::logIssue( + ProjectExplorer::Task::Warning, removeMsg, qmlComponentsFilePath); + } + } + } else { + CMakeGenerator::logIssue( + ProjectExplorer::Task::Error, cpyResult.error(), componentsSrc); + } + } + } +} + } // namespace QmlProjectExporter } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h index ed51eb070e6..4b6a515cea9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h @@ -8,17 +8,23 @@ namespace QmlProjectManager { namespace QmlProjectExporter { -class CMakeWriterV1 final : public CMakeWriter +class CMakeWriterV1 : public CMakeWriter { public: CMakeWriterV1(CMakeGenerator *parent); + virtual QString mainLibName() const; + QString sourceDirName() const override; void transformNode(NodePtr &node) const override; + int identifier() const override; void writeRootCMakeFile(const NodePtr &node) const override; void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; + +protected: + void createDependencies(const Utils::FilePath &rootDir) const; }; } // namespace QmlProjectExporter diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp index 40de901c4fe..0763f2a442c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp @@ -36,9 +36,6 @@ void Exporter::updateProjectItem(QmlProjectItem *item, bool updateEnabled) if (updateEnabled) { m_cmakeGen->setEnabled(item->enableCMakeGeneration()); m_pythonGen->setEnabled(item->enablePythonGeneration()); - - m_cmakeGen->setStandaloneApp(item->standaloneApp()); - m_pythonGen->setStandaloneApp(item->standaloneApp()); } } diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp index 39cfbad5876..3c3d54571cf 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp @@ -8,6 +8,7 @@ #include "../qmlprojectmanagertr.h" #include +#include #include #include @@ -68,6 +69,17 @@ bool FileGenerator::isEnabled() const return m_enabled; } +bool FileGenerator::isActive() const +{ + if (!m_buildSystem) + return false; + + if (auto *target = m_buildSystem->target()) + return target->isActive(); + + return false; +} + void FileGenerator::setEnabled(bool enabled) { m_enabled = enabled; @@ -75,12 +87,15 @@ void FileGenerator::setEnabled(bool enabled) bool FileGenerator::standaloneApp() const { - return m_standaloneApp; + if (m_buildSystem) + return m_buildSystem->standaloneApp(); + return false; } void FileGenerator::setStandaloneApp(bool value) { - m_standaloneApp = value; + if (m_buildSystem) + m_buildSystem->setStandaloneApp(value); } void FileGenerator::updateMenuAction(const Utils::Id &id, std::function isEnabled) diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h index a617d4448cf..7914aee527e 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h @@ -32,6 +32,7 @@ public: const QmlBuildSystem *buildSystem() const; bool isEnabled() const; + bool isActive() const; void setEnabled(bool enabled); bool standaloneApp() const; @@ -42,7 +43,6 @@ protected: private: bool m_enabled = false; - bool m_standaloneApp = false; QmlBuildSystem *m_buildSystem = nullptr; }; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl new file mode 100644 index 00000000000..b98746e425e --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl @@ -0,0 +1,28 @@ + +cmake_minimum_required(VERSION 3.21.1) + +option(LINK_INSIGHT "Link Qt Insight Tracker library" ON) +option(BUILD_QDS_COMPONENTS "Build design studio components" ON) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml) +set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY} + CACHE STRING "Import paths for Qt Creator's code model" + FORCE +) + +qt_add_library(%1) +qt_add_resources(%1 "configuration" + PREFIX "/" + FILES +%2) + +include(qds) + +if (LINK_INSIGHT) + include(insight OPTIONAL) +endif () +