CMake generator: Fix support for deeper module folder structure and asset_imports

Task-number: QDS-5585
Change-Id: Id7d6f551acc5692a6c7c580d5ffc90ca7528bbc8
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Tapani Mattila
2021-11-29 19:34:43 +02:00
committed by Thomas Hartmann
parent 1e537f7ab0
commit bf4a85d60c
5 changed files with 89 additions and 30 deletions

View File

@@ -63,13 +63,14 @@ enum ProjectDirectoryError {
NoError = 0, NoError = 0,
MissingContentDir = 1<<1, MissingContentDir = 1<<1,
MissingImportDir = 1<<2, MissingImportDir = 1<<2,
MissingCppDir = 1<<3, MissingAssetImportDir = 1<<3,
MissingMainCMake = 1<<4, MissingCppDir = 1<<4,
MissingMainQml = 1<<5, MissingMainCMake = 1<<5,
MissingAppMainQml = 1<<6, MissingMainQml = 1<<6,
MissingQmlModules = 1<<7, MissingAppMainQml = 1<<7,
MissingMainCpp = 1<<8, MissingQmlModules = 1<<8,
MissingMainCppHeader = 1<<9 MissingMainCpp = 1<<9,
MissingMainCppHeader = 1<<10
}; };
QVector<GeneratableFile> queuedFiles; QVector<GeneratableFile> queuedFiles;
@@ -131,6 +132,8 @@ int isProjectCorrectlyFormed(const FilePath &rootDir)
if (!rootDir.pathAppended(DIRNAME_IMPORT).exists()) if (!rootDir.pathAppended(DIRNAME_IMPORT).exists())
errors |= MissingImportDir; errors |= MissingImportDir;
if (!rootDir.pathAppended(DIRNAME_ASSET).exists())
errors |= MissingAssetImportDir;
if (!rootDir.pathAppended(DIRNAME_CPP).exists()) if (!rootDir.pathAppended(DIRNAME_CPP).exists())
errors |= MissingCppDir; errors |= MissingCppDir;
@@ -159,7 +162,7 @@ void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles)
const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"The project is not properly structured for automatically generating CMake files.\n\nAborting process.\n\nThe following files or directories are missing:\n\n%1"); "The project is not properly structured for automatically generating CMake files.\n\nAborting process.\n\nThe following files or directories are missing:\n\n%1");
const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"The project is not properly structured for automatically generating CMake files.\n\nThe following files will be created:\n\n%1"); "The project is not properly structured for automatically generating CMake files.\n\nThe following files or directories are missing and may be created:\n\n%1");
const QString WARNING_TITLE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_TITLE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"Cannot Generate CMake Files"); "Cannot Generate CMake Files");
const QString WARNING_TITLE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_TITLE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
@@ -182,6 +185,8 @@ void showProjectDirErrorDialog(int error)
if (error & MissingImportDir) if (error & MissingImportDir)
fatalList.append(QString(DIRNAME_IMPORT) + "\n"); fatalList.append(QString(DIRNAME_IMPORT) + "\n");
if (error & MissingAssetImportDir)
nonFatalList.append(QString(DIRNAME_ASSET) + "\n");
if (error & MissingMainCMake) if (error & MissingMainCMake)
nonFatalList.append(QString(FILENAME_CMAKELISTS) + "\n"); nonFatalList.append(QString(FILENAME_CMAKELISTS) + "\n");
if (error & MissingQmlModules) if (error & MissingQmlModules)
@@ -290,16 +295,21 @@ bool generateCmakes(const FilePath &rootDir)
{ {
moduleNames.clear(); moduleNames.clear();
FilePath contentDir = rootDir.pathAppended("content"); FilePath contentDir = rootDir.pathAppended(DIRNAME_CONTENT);
FilePath importDir = rootDir.pathAppended("imports"); FilePath importDir = rootDir.pathAppended(DIRNAME_IMPORT);
FilePath assetDir = rootDir.pathAppended(DIRNAME_ASSET);
generateModuleCmake(contentDir); generateModuleCmake(contentDir);
generateImportCmake(importDir); generateImportCmake(importDir);
generateImportCmake(assetDir);
generateMainCmake(rootDir); generateMainCmake(rootDir);
return true; return true;
} }
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 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.
@@ -309,27 +319,47 @@ void generateMainCmake(const FilePath &rootDir)
QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName); QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName);
queueCmakeFile(rootDir, cmakeFileContent); queueCmakeFile(rootDir, cmakeFileContent);
QString subdirIncludes;
subdirIncludes.append(QString(ADD_SUBDIR).arg(DIRNAME_CONTENT));
subdirIncludes.append(QString(ADD_SUBDIR).arg(DIRNAME_IMPORT));
if (rootDir.pathAppended(DIRNAME_ASSET).exists())
subdirIncludes.append(QString(ADD_SUBDIR).arg(DIRNAME_ASSET));
QString modulesAsPlugins; QString modulesAsPlugins;
for (const QString &moduleName : moduleNames) for (const QString &moduleName : moduleNames)
modulesAsPlugins.append(" " + moduleName + "plugin\n"); modulesAsPlugins.append(" " + moduleName + "plugin\n");
QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins); QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH)
.arg(appName)
.arg(subdirIncludes)
.arg(modulesAsPlugins);
GenerateCmake::queueFile(rootDir.pathAppended(FILENAME_MODULES), moduleFileContent); GenerateCmake::queueFile(rootDir.pathAppended(FILENAME_MODULES), moduleFileContent);
} }
const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n"; void generateImportCmake(const FilePath &dir, const QString &modulePrefix)
const char ADD_SUBDIR[] = "add_subdirectory(%1)\n";
void generateImportCmake(const FilePath &dir)
{ {
if (!dir.exists())
return;
QString fileContent; QString fileContent;
fileContent.append(DO_NOT_EDIT_FILE_COMMENT); fileContent.append(DO_NOT_EDIT_FILE_COMMENT);
FilePaths subDirs = dir.dirEntries(DIRS_ONLY); FilePaths subDirs = dir.dirEntries(DIRS_ONLY);
for (FilePath &subDir : subDirs) { for (FilePath &subDir : subDirs) {
if (isDirBlacklisted(subDir))
continue;
if (getDirectoryTreeQmls(subDir).isEmpty() && getDirectoryTreeResources(subDir).isEmpty())
continue;
fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName()));
generateModuleCmake(subDir); QString prefix = modulePrefix.isEmpty() ?
modulePrefix % subDir.fileName() :
QString(modulePrefix + '.') + subDir.fileName();
if (getDirectoryQmls(subDir).isEmpty()) {
generateImportCmake(subDir, prefix);
} else {
generateModuleCmake(subDir, prefix);
}
} }
queueCmakeFile(dir, fileContent); queueCmakeFile(dir, fileContent);
@@ -339,13 +369,12 @@ const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE";
const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n PROPERTIES\n %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_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl"; const char MODULEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl";
void generateModuleCmake(const FilePath &dir) void generateModuleCmake(const FilePath &dir, const QString &uri)
{ {
QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH); QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH);
const QStringList qmldirFilesOnly(FILENAME_QMLDIR);
QString singletonContent; QString singletonContent;
FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); FilePaths qmldirFileList = dir.dirEntries(QStringList(FILENAME_QMLDIR), 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) {
@@ -371,12 +400,14 @@ void generateModuleCmake(const FilePath &dir)
moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles)); moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles));
} }
QString moduleName = dir.fileName(); QString moduleUri = uri.isEmpty() ?
dir.fileName() :
uri;
QString moduleName = QString(moduleUri).remove('.');
moduleNames.append(moduleName); moduleNames.append(moduleName);
QString fileContent; QString fileContent;
fileContent.append(fileTemplate.arg(singletonContent).arg(moduleName).arg(moduleContent)); fileContent.append(fileTemplate.arg(singletonContent, moduleName, moduleUri, moduleContent));
queueCmakeFile(dir, fileContent); queueCmakeFile(dir, fileContent);
} }
@@ -403,6 +434,22 @@ QStringList getSingletonsFromQmldirFile(const FilePath &filePath)
return singletons; return singletons;
} }
FilePaths getDirectoryQmls(const FilePath &dir)
{
const QStringList qmlFilesOnly("*.qml");
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
FilePaths allFiles = dir.dirEntries(qmlFilesOnly, FILES_ONLY);
FilePaths moduleFiles;
for (FilePath &file : allFiles) {
if (!isFileBlacklisted(file.fileName()) &&
project->isKnownFile(file)) {
moduleFiles.append(file);
}
}
return moduleFiles;
}
QStringList getDirectoryTreeQmls(const FilePath &dir) QStringList getDirectoryTreeQmls(const FilePath &dir)
{ {
const QStringList qmlFilesOnly("*.qml"); const QStringList qmlFilesOnly("*.qml");
@@ -419,6 +466,8 @@ QStringList getDirectoryTreeQmls(const FilePath &dir)
FilePaths subDirsList = dir.dirEntries(DIRS_ONLY); FilePaths subDirsList = dir.dirEntries(DIRS_ONLY);
for (FilePath &subDir : subDirsList) { for (FilePath &subDir : subDirsList) {
if (isDirBlacklisted(subDir))
continue;
QStringList subDirQmlFiles = getDirectoryTreeQmls(subDir); QStringList subDirQmlFiles = getDirectoryTreeQmls(subDir);
for (QString &qmlFile : subDirQmlFiles) { for (QString &qmlFile : subDirQmlFiles) {
qmlFileList.append(subDir.fileName().append('/').append(qmlFile)); qmlFileList.append(subDir.fileName().append('/').append(qmlFile));
@@ -444,6 +493,8 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
FilePaths subDirsList = dir.dirEntries(DIRS_ONLY); FilePaths subDirsList = dir.dirEntries(DIRS_ONLY);
for (FilePath &subDir : subDirsList) { for (FilePath &subDir : subDirsList) {
if (isDirBlacklisted(subDir))
continue;
QStringList subDirResources = getDirectoryTreeResources(subDir); QStringList subDirResources = getDirectoryTreeResources(subDir);
for (QString &resource : subDirResources) { for (QString &resource : subDirResources) {
resourceFileList.append(subDir.fileName().append('/').append(resource)); resourceFileList.append(subDir.fileName().append('/').append(resource));
@@ -466,6 +517,11 @@ bool isFileBlacklisted(const QString &fileName)
!fileName.compare(FILENAME_CMAKELISTS)); !fileName.compare(FILENAME_CMAKELISTS));
} }
bool isDirBlacklisted(const FilePath &dir)
{
return (!dir.fileName().compare(DIRNAME_DESIGNER));
}
} }
namespace GenerateEntryPoints { namespace GenerateEntryPoints {

View File

@@ -54,13 +54,15 @@ QString readTemplate(const QString &templatePath);
namespace GenerateCmakeLists { namespace GenerateCmakeLists {
bool generateCmakes(const Utils::FilePath &rootDir); bool generateCmakes(const Utils::FilePath &rootDir);
void generateMainCmake(const Utils::FilePath &rootDir); void generateMainCmake(const Utils::FilePath &rootDir);
void generateImportCmake(const Utils::FilePath &dir); void generateImportCmake(const Utils::FilePath &dir, const QString &modulePrefix = QString());
void generateModuleCmake(const Utils::FilePath &dir); void generateModuleCmake(const Utils::FilePath &dir, const QString &moduleUri = QString());
Utils::FilePaths getDirectoryQmls(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 queueCmakeFile(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);
bool isDirBlacklisted(const Utils::FilePath &dir);
} }
namespace GenerateEntryPoints { namespace GenerateEntryPoints {
bool generateEntryPointFiles(const Utils::FilePath &dir); bool generateEntryPointFiles(const Utils::FilePath &dir);

View File

@@ -34,7 +34,9 @@ namespace Constants {
const char DIRNAME_CONTENT[] = "content"; const char DIRNAME_CONTENT[] = "content";
const char DIRNAME_IMPORT[] = "imports"; const char DIRNAME_IMPORT[] = "imports";
const char DIRNAME_ASSET[] = "asset_imports";
const char DIRNAME_CPP[] = "src"; const char DIRNAME_CPP[] = "src";
const char DIRNAME_DESIGNER[] = "designer";
const char FILENAME_CMAKELISTS[] = "CMakeLists.txt"; const char FILENAME_CMAKELISTS[] = "CMakeLists.txt";
const char FILENAME_APPMAINQML[] = "App.qml"; const char FILENAME_APPMAINQML[] = "App.qml";

View File

@@ -5,7 +5,7 @@
qt_add_library(%2 STATIC) qt_add_library(%2 STATIC)
qt6_add_qml_module(%2 qt6_add_qml_module(%2
URI "%2" URI "%3"
VERSION 1.0 VERSION 1.0
%3 %4
) )

View File

@@ -8,9 +8,8 @@ qt6_add_qml_module(%1
QML_FILES main.qml QML_FILES main.qml
) )
add_subdirectory(content) %2
add_subdirectory(imports)
target_link_libraries(%1 PRIVATE target_link_libraries(%1 PRIVATE
%2 %3
) )