forked from qt-creator/qt-creator
QmlProjectManager: New project structure support for CMakeGenerator
- Add writer interface in order to support the current and the new project structure in parallel. Using the new one if qdsVersion is >= 4.5 - Separated templates for the new generator from the old one - Add file name validity check - Generate files in the folder src and cmake if they do not exist yet. Only re-generate files in src/autogen. - Add action to enable or disable the cmake-generator - Add function that checks if a resource file is within the project folder but not part of the project Change-Id: I3d75dbee1043ed28e6126cf0b2c83994cb70ed45 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
259
src/plugins/qmlprojectmanager/cmakegen/cmakewriter.cpp
Normal file
259
src/plugins/qmlprojectmanager/cmakegen/cmakewriter.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
// 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 <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
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<CMakeWriterV1>(parent);
|
||||
|
||||
return std::make_unique<CMakeWriterV0>(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<Utils::FilePath> CMakeWriter::files(const NodePtr &node, const FileGetter &getter) const
|
||||
{
|
||||
std::vector<Utils::FilePath> 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<Utils::FilePath> CMakeWriter::qmlFiles(const NodePtr &node) const
|
||||
{
|
||||
return files(node, [](const NodePtr &n) { return n->files; });
|
||||
}
|
||||
|
||||
std::vector<Utils::FilePath> CMakeWriter::singletons(const NodePtr &node) const
|
||||
{
|
||||
return files(node, [](const NodePtr &n) { return n->singletons; });
|
||||
}
|
||||
|
||||
std::vector<Utils::FilePath> CMakeWriter::resources(const NodePtr &node) const
|
||||
{
|
||||
return files(node, [](const NodePtr &n) { return n->resources; });
|
||||
}
|
||||
|
||||
std::vector<Utils::FilePath> CMakeWriter::sources(const NodePtr &node) const
|
||||
{
|
||||
return files(node, [](const NodePtr &n) { return n->sources; });
|
||||
}
|
||||
|
||||
std::vector<QString> CMakeWriter::plugins(const NodePtr &node) const
|
||||
{
|
||||
QTC_ASSERT(parent(), return {});
|
||||
std::vector<QString> 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<QString, QString> CMakeWriter::makeResourcesBlocks(const NodePtr &node) const
|
||||
{
|
||||
QString resourcesOut;
|
||||
QString bigResourcesOut;
|
||||
|
||||
QString resourceFiles;
|
||||
std::vector<QString> 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 file: %1");
|
||||
CMakeGenerator::logIssue(text.arg(path.path()));
|
||||
}
|
||||
fileHandle.close();
|
||||
}
|
||||
|
||||
void CMakeWriter::collectPlugins(const NodePtr &node, std::vector<QString> &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.
|
||||
Reference in New Issue
Block a user