From 78f89fc777769d6c7c8d629bd5012777e66bfeb3 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 7 Sep 2023 19:06:39 +0200 Subject: [PATCH] CMakePM: Proper support for Unity builds A Unity build can be enabled by specifying CMAKE_UNITY_BUILD set to ON globally or per target bases via the UNITY_BUILD property. CMake would then add unity_NN_[cxx|c].[cxx|c] sources files that would include the existing project files. The existing project files would then be added as "headers" to the project and exported via the CMake file-api. This patch makes sure that these new "headers" are added to the Qt Creator's code model and have proper syntax highlighting, be available to plugins (e.g. Todo) and so on. Fixes: QTCREATORBUG-23635 Fixes: QTCREATORBUG-26822 Fixes: QTCREATORBUG-29080 Change-Id: Ie8dd542504f632c01f91691f8736e51be8b19a01 Reviewed-by: Alessandro Portale Reviewed-by: --- .../fileapidataextractor.cpp | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 05574b9a007..980ba47cbe3 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -332,6 +332,12 @@ bool isPchFile(const FilePath &buildDirectory, const FilePath &path) return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch"); } +bool isUnityFile(const FilePath &buildDirectory, const FilePath &path) +{ + return path.isChildOf(buildDirectory) && path.parentDir().fileName() == "Unity" + && path.fileName().startsWith("unity_"); +} + RawProjectParts generateRawProjectParts(const PreprocessedData &input, const FilePath &sourceDirectory, const FilePath &buildDirectory) @@ -381,11 +387,20 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, // Get all sources from the compiler group, except generated sources QStringList sources; + auto addToSources = [sourceDirectory, &sources](const QString &source) { + const FilePath sourcePath = FilePath::fromString(source); + if (sourcePath.isAbsolutePath()) + sources.push_back(source); + else + sources.push_back( + sourceDirectory.pathAppended(source).absoluteFilePath().path()); + }; + for (auto idx: ci.sources) { SourceInfo si = t.sources.at(idx); if (si.isGenerated) continue; - sources.push_back(sourceDirectory.pathAppended(si.path).absoluteFilePath().path()); + addToSources(si.path); } // If we are not in a pch compiler group, add all the headers that are not generated @@ -393,27 +408,45 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, return isPchFile(buildDirectory, FilePath::fromString(path)); }); + const bool hasUnitySources = allOf(sources, [buildDirectory](const QString &path) { + return isUnityFile(buildDirectory, FilePath::fromString(path)); + }); + QString headerMimeType; - if (ci.language == "C") + QString sourceMimeType; + if (ci.language == "C") { headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; - else if (ci.language == "CXX") + sourceMimeType = CppEditor::Constants::C_SOURCE_MIMETYPE; + } else if (ci.language == "CXX") { headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE; + sourceMimeType = CppEditor::Constants::CPP_SOURCE_MIMETYPE; + } if (!hasPchSource) { for (const SourceInfo &si : t.sources) { if (si.isGenerated) continue; const auto mimeTypes = Utils::mimeTypesForFileName(si.path); - for (const auto &mime : mimeTypes) - if (mime.inherits(headerMimeType)) - sources.push_back( - sourceDirectory.pathAppended(si.path).absoluteFilePath().path()); + for (const auto &mime : mimeTypes) { + const bool headerType = mime.inherits(headerMimeType); + const bool sourceUnityType = hasUnitySources ? mime.inherits(sourceMimeType) + : false; + if (headerType || sourceUnityType) + addToSources(si.path); + } } } + sources.removeDuplicates(); - // Set project files except pch files - rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { - return !isPchFile(buildDirectory, FilePath::fromString(path)); - }), {}, [headerMimeType](const QString &path) { + // Set project files except pch / unity files + rpp.setFiles(Utils::filtered(sources, + [buildDirectory](const QString &path) { + return !isPchFile(buildDirectory, + FilePath::fromString(path)) + && !isUnityFile(buildDirectory, + FilePath::fromString(path)); + }), + {}, + [headerMimeType](const QString &path) { // Similar to ProjectFile::classify but classify headers with language // of compile group instead of ambiguous header if (path.endsWith(".h")) @@ -561,9 +594,9 @@ void addCompileGroups(ProjectNode *targetRoot, auto node = std::make_unique(sourcePath, Node::fileTypeForFileName(sourcePath)); node->setIsGenerated(si.isGenerated); - // CMake pch files are generated at configured time, but not marked as generated + // CMake pch / unity files are generated at configured time, but not marked as generated // so that a "clean" step won't remove them and at a subsequent build they won't exist. - if (isPchFile(buildDirectory, sourcePath)) + if (isPchFile(buildDirectory, sourcePath) || isUnityFile(buildDirectory, sourcePath)) node->setIsGenerated(true); // Where does the file node need to go?