CMakeProjectManager: Fix issues with precompiled headers

Clang code model can break if CMake project uses precompiled headers.

QtCreator will make a copy of the precompiled header, this way it
will not conflict with the build system one.

Ammends 888ea6bbbb

Fixes: QTCREATORBUG-24945
Fixes: QTCREATORBUG-25213
Change-Id: I149fc416cd047683d095758a024de47c7baf681c
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Cristian Adam
2021-01-11 15:57:16 +01:00
parent a64defa10b
commit 98b92ed03e
5 changed files with 81 additions and 47 deletions

View File

@@ -348,10 +348,15 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
}
QString ending;
if (ci.language == "C")
QString qtcPchFile;
if (ci.language == "C") {
ending = "/cmake_pch.h";
else if (ci.language == "CXX")
qtcPchFile = "qtc_cmake_pch.h";
}
else if (ci.language == "CXX") {
ending = "/cmake_pch.hxx";
qtcPchFile = "qtc_cmake_pch.hxx";
}
++counter;
RawProjectPart rpp;
@@ -362,13 +367,7 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
rpp.setMacros(transform<QVector>(ci.defines, &DefineInfo::define));
rpp.setHeaderPaths(transform<QVector>(ci.includes, &IncludeInfo::path));
RawProjectPartFlags cProjectFlags;
cProjectFlags.commandLineFlags = splitFragments(ci.fragments);
rpp.setFlagsForC(cProjectFlags);
RawProjectPartFlags cxxProjectFlags;
cxxProjectFlags.commandLineFlags = cProjectFlags.commandLineFlags;
rpp.setFlagsForCxx(cxxProjectFlags);
QStringList fragments = splitFragments(ci.fragments);
FilePath precompiled_header
= FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) {
@@ -383,9 +382,38 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
const FilePath parentDir = FilePath::fromString(sourceDir.absolutePath());
precompiled_header = parentDir.pathAppended(precompiled_header.toString());
}
rpp.setPreCompiledHeaders({precompiled_header.toString()});
// Remove the CMake PCH usage command line options in order to avoid the case
// when the build system would produce a .pch/.gch file that would be treated
// by the Clang code model as its own and fail.
auto remove = [&](const QStringList &args) {
auto foundPos = std::search(fragments.begin(), fragments.end(),
args.begin(), args.end());
if (foundPos != fragments.end())
fragments.erase(foundPos, std::next(foundPos, args.size()));
};
remove({"-Xclang", "-include-pch", "-Xclang", precompiled_header.toString() + ".gch"});
remove({"-Xclang", "-include-pch", "-Xclang", precompiled_header.toString() + ".pch"});
remove({"-Xclang", "-include", "-Xclang", precompiled_header.toString()});
remove({"-include", precompiled_header.toString()});
remove({"/FI", precompiled_header.toString()});
// Make a copy of the CMake PCH header and use it instead
FilePath qtc_precompiled_header = precompiled_header.parentDir().pathAppended(qtcPchFile);
FileUtils::copyIfDifferent(precompiled_header, qtc_precompiled_header);
rpp.setPreCompiledHeaders({qtc_precompiled_header.toString()});
}
RawProjectPartFlags cProjectFlags;
cProjectFlags.commandLineFlags = fragments;
rpp.setFlagsForC(cProjectFlags);
RawProjectPartFlags cxxProjectFlags;
cxxProjectFlags.commandLineFlags = cProjectFlags.commandLineFlags;
rpp.setFlagsForCxx(cxxProjectFlags);
const bool isExecutable = t.type == "EXECUTABLE";
rpp.setBuildTargetType(isExecutable ? ProjectExplorer::BuildTargetType::Executable
: ProjectExplorer::BuildTargetType::Library);