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 <alessandro.portale@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Cristian Adam
2023-09-07 19:06:39 +02:00
parent 4d358ae337
commit 78f89fc777

View File

@@ -332,6 +332,12 @@ bool isPchFile(const FilePath &buildDirectory, const FilePath &path)
return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch"); 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, RawProjectParts generateRawProjectParts(const PreprocessedData &input,
const FilePath &sourceDirectory, const FilePath &sourceDirectory,
const FilePath &buildDirectory) const FilePath &buildDirectory)
@@ -381,11 +387,20 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
// Get all sources from the compiler group, except generated sources // Get all sources from the compiler group, except generated sources
QStringList 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) { for (auto idx: ci.sources) {
SourceInfo si = t.sources.at(idx); SourceInfo si = t.sources.at(idx);
if (si.isGenerated) if (si.isGenerated)
continue; 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 // 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)); return isPchFile(buildDirectory, FilePath::fromString(path));
}); });
const bool hasUnitySources = allOf(sources, [buildDirectory](const QString &path) {
return isUnityFile(buildDirectory, FilePath::fromString(path));
});
QString headerMimeType; QString headerMimeType;
if (ci.language == "C") QString sourceMimeType;
if (ci.language == "C") {
headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; 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; headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE;
sourceMimeType = CppEditor::Constants::CPP_SOURCE_MIMETYPE;
}
if (!hasPchSource) { if (!hasPchSource) {
for (const SourceInfo &si : t.sources) { for (const SourceInfo &si : t.sources) {
if (si.isGenerated) if (si.isGenerated)
continue; continue;
const auto mimeTypes = Utils::mimeTypesForFileName(si.path); const auto mimeTypes = Utils::mimeTypesForFileName(si.path);
for (const auto &mime : mimeTypes) for (const auto &mime : mimeTypes) {
if (mime.inherits(headerMimeType)) const bool headerType = mime.inherits(headerMimeType);
sources.push_back( const bool sourceUnityType = hasUnitySources ? mime.inherits(sourceMimeType)
sourceDirectory.pathAppended(si.path).absoluteFilePath().path()); : false;
if (headerType || sourceUnityType)
addToSources(si.path);
} }
} }
}
sources.removeDuplicates();
// Set project files except pch files // Set project files except pch / unity files
rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { rpp.setFiles(Utils::filtered(sources,
return !isPchFile(buildDirectory, FilePath::fromString(path)); [buildDirectory](const QString &path) {
}), {}, [headerMimeType](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 // Similar to ProjectFile::classify but classify headers with language
// of compile group instead of ambiguous header // of compile group instead of ambiguous header
if (path.endsWith(".h")) if (path.endsWith(".h"))
@@ -561,9 +594,9 @@ void addCompileGroups(ProjectNode *targetRoot,
auto node = std::make_unique<FileNode>(sourcePath, Node::fileTypeForFileName(sourcePath)); auto node = std::make_unique<FileNode>(sourcePath, Node::fileTypeForFileName(sourcePath));
node->setIsGenerated(si.isGenerated); 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. // 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); node->setIsGenerated(true);
// Where does the file node need to go? // Where does the file node need to go?