summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCristian Adam <cristian.adam@qt.io>2021-01-11 15:57:16 +0100
committerCristian Adam <cristian.adam@qt.io>2021-01-14 08:08:40 +0000
commit98b92ed03ec49e1c0f614266fadf04b2bca408cd (patch)
tree1e4a8be094e5baf8a3971f0d9eb11076869bfd09
parenta64defa10bb9b1542aa87895e6a0ecd4fb3c6a77 (diff)
downloadqt-creator-98b92ed03ec49e1c0f614266fadf04b2bca408cd.tar.gz
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 888ea6bbbb0f4c6bb6b5616046e600b9520e4faf 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>
-rw-r--r--src/libs/utils/fileutils.cpp23
-rw-r--r--src/libs/utils/fileutils.h2
-rw-r--r--src/plugins/cmakeprojectmanager/fileapidataextractor.cpp48
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.cpp52
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.h3
5 files changed, 81 insertions, 47 deletions
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index 23be348698..53b8957794 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -220,6 +220,29 @@ bool FileUtils::copyRecursively(const FilePath &srcFilePath, const FilePath &tgt
}
/*!
+ Copies a file specified by \a srcFilePath to \a tgtFilePath only if \a srcFilePath is different
+ (file size and last modification time).
+
+ Returns whether the operation succeeded.
+*/
+
+bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath)
+{
+ if (QFile::exists(tgtFilePath.toString())) {
+ const QFileInfo srcFileInfo = srcFilePath.toFileInfo();
+ const QFileInfo tgtFileInfo = tgtFilePath.toFileInfo();
+ if (srcFileInfo.lastModified() == tgtFileInfo.lastModified() &&
+ srcFileInfo.size() == tgtFileInfo.size()) {
+ return true;
+ } else {
+ QFile::remove(tgtFilePath.toString());
+ }
+ }
+
+ return QFile::copy(srcFilePath.toString(), tgtFilePath.toString());
+}
+
+/*!
If this is a directory, the function will recursively check all files and return
true if one of them is newer than \a timeStamp. If this is a single file, true will
be returned if the file is newer than \a timeStamp.
diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h
index 5db3a0a1c2..9f1a0bef91 100644
--- a/src/libs/utils/fileutils.h
+++ b/src/libs/utils/fileutils.h
@@ -189,6 +189,8 @@ public:
const FilePath &tgtFilePath,
QString *error,
T &&copyHelper);
+ static bool copyIfDifferent(const FilePath &srcFilePath,
+ const FilePath &tgtFilePath);
static FilePath resolveSymlinks(const FilePath &path);
static QString fileSystemFriendlyName(const QString &name);
static int indexOfQmakeUnfriendly(const QString &name, int startpos = 0);
diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
index badf74c059..2ca34b68ad 100644
--- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
+++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp
@@ -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);
diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp
index 02ce9a3616..37d64208b1 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.cpp
+++ b/src/plugins/cpptools/compileroptionsbuilder.cpp
@@ -175,14 +175,6 @@ void CompilerOptionsBuilder::addSyntaxOnly()
isClStyle() ? add("/Zs") : add("-fsyntax-only");
}
-void CompilerOptionsBuilder::remove(const QStringList &args)
-{
- auto foundPos = std::search(m_options.begin(), m_options.end(),
- args.begin(), args.end());
- if (foundPos != m_options.end())
- m_options.erase(foundPos, std::next(foundPos, args.size()));
-}
-
QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt)
{
QStringList options;
@@ -369,42 +361,32 @@ void CompilerOptionsBuilder::addHeaderPathOptions()
}
}
-void CompilerOptionsBuilder::addIncludedFiles(const QStringList &files)
+void CompilerOptionsBuilder::addIncludeFile(const QString &file)
{
- QStringList result;
+ if (QFile::exists(file)) {
+ add({isClStyle() ? QLatin1String(includeFileOptionCl)
+ : QLatin1String(includeFileOptionGcc),
+ QDir::toNativeSeparators(file)});
+ }
+}
- const QString includeOptionString
- = QLatin1String(isClStyle() ? includeFileOptionCl : includeFileOptionGcc);
+void CompilerOptionsBuilder::addIncludedFiles(const QStringList &files)
+{
for (const QString &file : files) {
- if (QFile::exists(file)) {
- result += includeOptionString;
- result += QDir::toNativeSeparators(file);
- }
+ if (m_projectPart.precompiledHeaders.contains(file))
+ continue;
+
+ addIncludeFile(file);
}
- m_options.append(result);
}
void CompilerOptionsBuilder::addPrecompiledHeaderOptions(UsePrecompiledHeaders usePrecompiledHeaders)
{
+ if (usePrecompiledHeaders == UsePrecompiledHeaders::No)
+ return;
+
for (const QString &pchFile : m_projectPart.precompiledHeaders) {
- // Bail if build system precompiled header artifacts exists.
- // Clang cannot handle foreign PCH files.
- if (QFile::exists(pchFile + ".gch") || QFile::exists(pchFile + ".pch"))
- usePrecompiledHeaders = UsePrecompiledHeaders::No;
-
- if (usePrecompiledHeaders == UsePrecompiledHeaders::No) {
- // CMake PCH will already have force included the header file in
- // command line options, remove it if exists.
- // In case of Clang compilers, also remove the pch-inclusion arguments.
- remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".gch"});
- remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".pch"});
- remove({isClStyle() ? QLatin1String(includeFileOptionCl)
- : QLatin1String(includeFileOptionGcc), pchFile});
- } else if (QFile::exists(pchFile)) {
- add({isClStyle() ? QLatin1String(includeFileOptionCl)
- : QLatin1String(includeFileOptionGcc),
- QDir::toNativeSeparators(pchFile)});
- }
+ addIncludeFile(pchFile);
}
}
diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h
index d28c081258..f81c515db0 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.h
+++ b/src/plugins/cpptools/compileroptionsbuilder.h
@@ -88,8 +88,6 @@ public:
void add(const QStringList &args, bool gccOnlyOptions = false);
virtual void addExtraOptions() {}
- void remove(const QStringList &args);
-
static UseToolchainMacros useToolChainMacros();
void reset();
@@ -103,6 +101,7 @@ private:
QStringList wrappedQtHeadersIncludePath() const;
QStringList wrappedMingwHeadersIncludePath() const;
QByteArray msvcVersion() const;
+ void addIncludeFile(const QString &file);
private:
const ProjectPart &m_projectPart;