// 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 "cmakewriter.h" #include "cmakegenerator.h" #include "cmakewriterv0.h" #include "cmakewriterv1.h" #include "generatecmakelistsconstants.h" #include "qmlprojectmanager/qmlproject.h" #include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" #include "utils/namevalueitem.h" #include #include namespace QmlProjectManager { namespace GenerateCmake { const char TEMPLATE_BIG_RESOURCES[] = R"( qt6_add_resources(%1 %2 BIG_RESOURCES PREFIX "%3" VERSION 1.0 FILES %4 ))"; CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent) { const QmlProject *project = parent->qmlProject(); QTC_ASSERT(project, return {}); const QmlBuildSystem *buildSystem = parent->buildSystem(); QTC_ASSERT(buildSystem, return {}); const QString versionString = buildSystem->versionDesignStudio(); bool ok = false; if (float version = versionString.toFloat(&ok); ok && version > 4.4) return std::make_unique(parent); return std::make_unique(parent); } CMakeWriter::CMakeWriter(CMakeGenerator *parent) : m_parent(parent) {} const CMakeGenerator *CMakeWriter::parent() const { return m_parent; } bool CMakeWriter::isPlugin(const NodePtr &node) const { if (node->type == Node::Type::Module) return true; return false; } QString CMakeWriter::sourceDirName() const { return Constants::DIRNAME_CPP; } void CMakeWriter::transformNode(NodePtr &) const {} std::vector CMakeWriter::files(const NodePtr &node, const FileGetter &getter) const { std::vector out = getter(node); for (const NodePtr &child : node->subdirs) { if (child->type == Node::Type::Module) continue; auto childFiles = files(child, getter); out.insert(out.end(), childFiles.begin(), childFiles.end()); } return out; } std::vector CMakeWriter::qmlFiles(const NodePtr &node) const { return files(node, [](const NodePtr &n) { return n->files; }); } std::vector CMakeWriter::singletons(const NodePtr &node) const { return files(node, [](const NodePtr &n) { return n->singletons; }); } std::vector CMakeWriter::resources(const NodePtr &node) const { return files(node, [](const NodePtr &n) { return n->resources; }); } std::vector CMakeWriter::sources(const NodePtr &node) const { return files(node, [](const NodePtr &n) { return n->sources; }); } std::vector CMakeWriter::plugins(const NodePtr &node) const { QTC_ASSERT(parent(), return {}); std::vector out; collectPlugins(node, out); return out; } QString CMakeWriter::getEnvironmentVariable(const QString &key) const { QTC_ASSERT(parent(), return {}); QString value; if (m_parent->buildSystem()) { auto envItems = m_parent->buildSystem()->environment(); auto confEnv = std::find_if( envItems.begin(), envItems.end(), [key](const Utils::EnvironmentItem &item) { return item.name == key; }); if (confEnv != envItems.end()) value = confEnv->value; } return value; } QString CMakeWriter::makeRelative(const NodePtr &node, const Utils::FilePath &path) const { const QString dir = node->dir.toString(); return "\"" + Utils::FilePath::calcRelativePath(path.toString(), dir) + "\""; } QString CMakeWriter::makeQmlFilesBlock(const NodePtr &node) const { QTC_ASSERT(parent(), return {}); QString qmlFileContent; for (const Utils::FilePath &path : qmlFiles(node)) qmlFileContent.append(QString("\t\t%1\n").arg(makeRelative(node, path))); QString str; if (!qmlFileContent.isEmpty()) str.append(QString("\tQML_FILES\n%1").arg(qmlFileContent)); return str; } QString CMakeWriter::makeSingletonBlock(const NodePtr &node) const { QString str; const QString setProperties("set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"); for (const Utils::FilePath &path : node->singletons) str.append(setProperties.arg(path.fileName()).arg("QT_QML_SINGLETON_TYPE").arg("true")); return str; } QString CMakeWriter::makeSubdirectoriesBlock(const NodePtr &node) const { QTC_ASSERT(parent(), return {}); QString str; for (const NodePtr &n : node->subdirs) { if (n->type == Node::Type::Module || n->type == Node::Type::Library || n->type == Node::Type::App || parent()->hasChildModule(n)) str.append(QString("add_subdirectory(%1)\n").arg(n->dir.fileName())); } return str; } QString CMakeWriter::makeSetEnvironmentFn() const { QTC_ASSERT(parent(), return {}); QTC_ASSERT(parent()->buildSystem(), return {}); const QmlBuildSystem *buildSystem = parent()->buildSystem(); const QString configFile = getEnvironmentVariable(Constants::ENV_VARIABLE_CONTROLCONF); QString out("inline void set_qt_environment() {\n"); for (Utils::EnvironmentItem &envItem : buildSystem->environment()) { QString key = envItem.name; QString value = envItem.value; if (value == configFile) value.prepend(":/"); out.append(QString("\tqputenv(\"%1\", \"%2\");\n").arg(key).arg(value)); } out.append("}"); return out; } std::tuple CMakeWriter::makeResourcesBlocks(const NodePtr &node) const { QString resourcesOut; QString bigResourcesOut; QString resourceFiles; std::vector bigResources; for (const Utils::FilePath &path : resources(node)) { if (path.fileSize() > 5000000) { bigResources.push_back(makeRelative(node, path)); continue; } resourceFiles.append(QString("\t\t%1\n").arg(makeRelative(node, path))); } if (!resourceFiles.isEmpty()) resourcesOut.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); QString templatePostfix; if (!bigResources.empty()) { QString resourceContent; for (const QString &res : bigResources) resourceContent.append(QString("\n %1").arg(res)); const QString prefixPath = QString(node->uri).replace('.', '/'); const QString prefix = "/qt/qml/" + prefixPath; const QString resourceName = node->name + "BigResource"; bigResourcesOut = QString::fromUtf8(TEMPLATE_BIG_RESOURCES, -1) .arg(node->name, resourceName, prefix, resourceContent); } return {resourcesOut, bigResourcesOut}; } QString CMakeWriter::readTemplate(const QString &templatePath) const { QFile templatefile(templatePath); templatefile.open(QIODevice::ReadOnly); QTextStream stream(&templatefile); QString content = stream.readAll(); templatefile.close(); return content; } void CMakeWriter::writeFile(const Utils::FilePath &path, const QString &content) const { QFile fileHandle(path.toString()); if (fileHandle.open(QIODevice::WriteOnly)) { QTextStream stream(&fileHandle); stream << content; } else { QString text("Failed to write"); CMakeGenerator::logIssue(ProjectExplorer::Task::Error, text, path); } fileHandle.close(); } void CMakeWriter::collectPlugins(const NodePtr &node, std::vector &out) const { if (isPlugin(node)) out.push_back(node->name); for (const auto &child : node->subdirs) collectPlugins(child, out); } } // End namespace GenerateCmake. } // End namespace QmlProjectManager.