CMake generating: Modify to generate files according to new dir structure

Task-number: QDS-5380
Change-Id: Ic3a4d6f4cd05185ded31b5d40adef43ff6508407
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Tapani Mattila
2021-11-11 18:36:48 +02:00
parent 9e04c6133c
commit d325db3eb2
8 changed files with 155 additions and 95 deletions

View File

@@ -1,5 +1,10 @@
<RCC> <RCC>
<qresource prefix="/boilerplatetemplates"> <qresource prefix="/boilerplatetemplates">
<file>qmlprojectmaincpp.tpl</file> <file>qmlprojectmaincpp.tpl</file>
<file>qmlprojectmaincppheader.tpl</file>
<file>qmlprojectmodules.tpl</file>
<file>qmlprojectmaincmakelists.tpl</file>
<file>qmlprojectmodulecmakelists.tpl</file>
<file>qmlprojectmainqml.tpl</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -78,7 +78,7 @@ void onGenerateCmakeLists()
{ {
queuedFiles.clear(); queuedFiles.clear();
FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory();
GenerateCmakeLists::generateMainCmake(rootDir); GenerateCmakeLists::generateCmakes(rootDir);
GenerateEntryPoints::generateMainCpp(rootDir); GenerateEntryPoints::generateMainCpp(rootDir);
GenerateEntryPoints::generateMainQml(rootDir); GenerateEntryPoints::generateMainQml(rootDir);
if (showConfirmationDialog(rootDir)) if (showConfirmationDialog(rootDir))
@@ -139,138 +139,125 @@ bool writeFile(const GeneratableFile &file)
return true; return true;
} }
QString readTemplate(const QString &templatePath)
{
QFile templatefile(templatePath);
templatefile.open(QIODevice::ReadOnly);
QTextStream stream(&templatefile);
QString content = stream.readAll();
templatefile.close();
return content;
}
} }
namespace GenerateCmakeLists { namespace GenerateCmakeLists {
QStringList moduleNames;
const QDir::Filters FILES_ONLY = QDir::Files; const QDir::Filters FILES_ONLY = QDir::Files;
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const char CMAKEFILENAME[] = "CMakeLists.txt"; const char CMAKEFILENAME[] = "CMakeLists.txt";
const char QMLDIRFILENAME[] = "qmldir"; const char QMLDIRFILENAME[] = "qmldir";
const char MODULEFILENAME[] = "qmlmodules";
QStringList processDirectory(const FilePath &dir) bool generateCmakes(const FilePath &rootDir)
{ {
QStringList moduleNames; moduleNames.clear();
FilePaths files = dir.dirEntries(FILES_ONLY); FilePath contentDir = rootDir.pathAppended("content");
for (FilePath &file : files) { FilePath importDir = rootDir.pathAppended("imports");
if (!file.fileName().compare(CMAKEFILENAME))
files.removeAll(file);
}
if (files.isEmpty()) { generateModuleCmake(contentDir);
generateSubdirCmake(dir); generateImportCmake(importDir);
FilePaths subDirs = dir.dirEntries(DIRS_ONLY); generateMainCmake(rootDir);
for (FilePath &subDir : subDirs) {
QStringList subDirModules = processDirectory(subDir);
moduleNames.append(subDirModules);
}
}
else {
QString moduleName = generateModuleCmake(dir);
if (!moduleName.isEmpty()) {
moduleNames.append(moduleName);
}
}
return moduleNames; return true;
} }
const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n"; const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl";
const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n"; const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl";
const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n";
const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n";
const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n";
const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n";
const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n";
const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n";
const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
void generateMainCmake(const FilePath &rootDir) void generateMainCmake(const FilePath &rootDir)
{ {
//TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all.
QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName();
QString appName = projectName + "App";
FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY); QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName);
queueCmakeFile(rootDir, cmakeFileContent);
QString modulesAsPlugins;
for (const QString &moduleName : moduleNames)
modulesAsPlugins.append(" " + moduleName + "plugin\n");
QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins);
GenerateCmake::queueFile(rootDir.pathAppended(MODULEFILENAME), moduleFileContent);
}
const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n";
const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
void generateImportCmake(const FilePath &dir)
{
QString fileContent; QString fileContent;
fileContent.append(MAINFILE_REQUIRED_VERSION);
fileContent.append(QString(MAINFILE_PROJECT).arg(projectName));
fileContent.append(MAINFILE_CMAKE_OPTIONS);
fileContent.append(MAINFILE_PACKAGES);
fileContent.append(QString(MAINFILE_CPP).arg(projectName));
fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName));
fileContent.append(MAINFILE_LIBRARIES);
fileContent.append(DO_NOT_EDIT_FILE_COMMENT);
FilePaths subDirs = dir.dirEntries(DIRS_ONLY);
for (FilePath &subDir : subDirs) { for (FilePath &subDir : subDirs) {
QStringList subDirModules = processDirectory(subDir);
if (!subDirModules.isEmpty())
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
generateModuleCmake(subDir);
} }
fileContent.append("\n");
fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName)); queueCmakeFile(dir, fileContent);
createCmakeFile(rootDir, fileContent);
} }
const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE"; const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE";
const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"; const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n PROPERTIES\n %2 %3\n)\n\n";
const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n"; const char MODULEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl";
void generateModuleCmake(const FilePath &dir)
QString generateModuleCmake(const FilePath &dir)
{ {
QString fileContent; QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH);
const QStringList qmldirFilesOnly(QMLDIRFILENAME); const QStringList qmldirFilesOnly(QMLDIRFILENAME);
QString singletonContent;
FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY);
if (!qmldirFileList.isEmpty()) { if (!qmldirFileList.isEmpty()) {
QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first()); QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first());
for (QString &singleton : singletons) { for (QString &singleton : singletons) {
fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); singletonContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true"));
} }
} }
QStringList qmlFileList = getDirectoryTreeQmls(dir); QStringList qmlFileList = getDirectoryTreeQmls(dir);
QString qmlFiles; QString qmlFiles;
for (QString &qmlFile : qmlFileList) for (QString &qmlFile : qmlFileList)
qmlFiles.append(QString("\t\t%1\n").arg(qmlFile)); qmlFiles.append(QString(" %1\n").arg(qmlFile));
QStringList resourceFileList = getDirectoryTreeResources(dir); QStringList resourceFileList = getDirectoryTreeResources(dir);
QString resourceFiles; QString resourceFiles;
for (QString &resourceFile : resourceFileList) for (QString &resourceFile : resourceFileList)
resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); resourceFiles.append(QString(" %1\n").arg(resourceFile));
QString moduleContent; QString moduleContent;
if (!qmlFiles.isEmpty()) { if (!qmlFiles.isEmpty()) {
moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles)); moduleContent.append(QString(" QML_FILES\n%1").arg(qmlFiles));
} }
if (!resourceFiles.isEmpty()) { if (!resourceFiles.isEmpty()) {
moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles));
} }
QString moduleName = dir.fileName(); QString moduleName = dir.fileName();
fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent)); moduleNames.append(moduleName);
createCmakeFile(dir, fileContent);
return moduleName;
}
void generateSubdirCmake(const FilePath &dir)
{
QString fileContent; QString fileContent;
FilePaths subDirs = dir.dirEntries(DIRS_ONLY); fileContent.append(fileTemplate.arg(singletonContent).arg(moduleName).arg(moduleContent));
queueCmakeFile(dir, fileContent);
for (FilePath &subDir : subDirs) {
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
}
createCmakeFile(dir, fileContent);
} }
QStringList getSingletonsFromQmldirFile(const FilePath &filePath) QStringList getSingletonsFromQmldirFile(const FilePath &filePath)
@@ -347,7 +334,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
return resourceFileList; return resourceFileList;
} }
void createCmakeFile(const FilePath &dir, const QString &content) void queueCmakeFile(const FilePath &dir, const QString &content)
{ {
FilePath filePath = dir.pathAppended(CMAKEFILENAME); FilePath filePath = dir.pathAppended(CMAKEFILENAME);
GenerateCmake::queueFile(filePath, content); GenerateCmake::queueFile(filePath, content);
@@ -370,35 +357,42 @@ bool generateEntryPointFiles(const FilePath &dir)
return cppOk && qmlOk; return cppOk && qmlOk;
} }
const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
const char MAIN_CPPFILE_DIR[] = "src";
const char MAIN_CPPFILE_NAME[] = "main.cpp"; const char MAIN_CPPFILE_NAME[] = "main.cpp";
const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl";
const char MAIN_CPPFILE_HEADER_NAME[] = "import_qml_plugins.h";
const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n";
bool generateMainCpp(const FilePath &dir) bool generateMainCpp(const FilePath &dir)
{ {
QFile templatefile(MAIN_CPPFILE_CONTENT); FilePath srcDir = dir.pathAppended(MAIN_CPPFILE_DIR);
templatefile.open(QIODevice::ReadOnly);
QTextStream stream(&templatefile);
QString content = stream.readAll();
templatefile.close();
FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME); QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH);
return GenerateCmake::queueFile(filePath, content); FilePath cppFilePath = srcDir.pathAppended(MAIN_CPPFILE_NAME);
bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent);
QString modulesAsPlugins;
for (const QString &moduleName : GenerateCmakeLists::moduleNames)
modulesAsPlugins.append(
QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "plugin"));
QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH)
.arg(modulesAsPlugins);
FilePath headerFilePath = srcDir.pathAppended(MAIN_CPPFILE_HEADER_NAME);
bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent);
return cppOk && headerOk;
} }
const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n"; const char MAIN_QMLFILE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl";
const char MAIN_QMLFILE_NAME[] = "main.qml"; const char MAIN_QMLFILE_NAME[] = "main.qml";
bool generateMainQml(const FilePath &dir) bool generateMainQml(const FilePath &dir)
{ {
QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_PATH);
FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME); FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME);
QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); return GenerateCmake::queueFile(filePath, content);
ProjectExplorer::RunConfiguration *runConfiguration = ProjectExplorer::SessionManager::startupRunConfiguration();
QString mainClass;
if (const auto aspect = runConfiguration->aspect<QmlProjectManager::QmlMainFileAspect>())
mainClass = FilePath::fromString(aspect->mainScript()).baseName();
return GenerateCmake::queueFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass));
} }
} }

View File

@@ -45,16 +45,17 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir);
bool queueFile(const Utils::FilePath &filePath, const QString &fileContent); bool queueFile(const Utils::FilePath &filePath, const QString &fileContent);
bool writeFile(const GeneratableFile &file); bool writeFile(const GeneratableFile &file);
bool writeQueuedFiles(); bool writeQueuedFiles();
QString readTemplate(const QString &templatePath);
} }
namespace GenerateCmakeLists { namespace GenerateCmakeLists {
bool generateCmakes(const Utils::FilePath &rootDir);
void generateMainCmake(const Utils::FilePath &rootDir); void generateMainCmake(const Utils::FilePath &rootDir);
void generateSubdirCmake(const Utils::FilePath &dir); void generateImportCmake(const Utils::FilePath &dir);
QString generateModuleCmake(const Utils::FilePath &dir); void generateModuleCmake(const Utils::FilePath &dir);
QStringList processDirectory(const Utils::FilePath &dir);
QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath);
QStringList getDirectoryTreeQmls(const Utils::FilePath &dir); QStringList getDirectoryTreeQmls(const Utils::FilePath &dir);
QStringList getDirectoryTreeResources(const Utils::FilePath &dir); QStringList getDirectoryTreeResources(const Utils::FilePath &dir);
void createCmakeFile(const Utils::FilePath &filePath, const QString &content); void queueCmakeFile(const Utils::FilePath &filePath, const QString &content);
bool isFileBlacklisted(const QString &fileName); bool isFileBlacklisted(const QString &fileName);
} }
namespace GenerateEntryPoints { namespace GenerateEntryPoints {

View File

@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.18)
project(%1 LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt6 COMPONENTS Gui Qml Quick)
add_executable(%1 src/main.cpp)
target_link_libraries(%1 PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Qml
)
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)

View File

@@ -0,0 +1,8 @@
/*
* This file is automatically generated by Qt Design Studio.
* Do not change.
*/
#include <QtQml/qqmlextensionplugin.h>
%1

View File

@@ -0,0 +1,6 @@
import QtQuick
import content
App {
}

View File

@@ -0,0 +1,11 @@
### This file is automatically generated by Qt Design Studio.
### Do not change
%1
qt_add_library(%2 STATIC)
qt6_add_qml_module(%2
URI "%2"
VERSION 1.0
%3
)

View File

@@ -0,0 +1,16 @@
### This file is automatically generated by Qt Design Studio.
### Do not change
qt6_add_qml_module(%1
URI "Main"
VERSION 1.0
NO_PLUGIN
QML_FILES main.qml
)
add_subdirectory(content)
add_subdirectory(imports)
target_link_libraries(%1 PRIVATE
%2
)