forked from qt-creator/qt-creator
Clang: Avoid consuming gcc internal include paths
Given the (default) include paths of GCC, e.g. /usr/include/c++/7 /usr/include/x86_64-linux-gnu/c++/7 /usr/include/c++/7/backward /usr/lib/gcc/x86_64-linux-gnu/7/include /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed /usr/include/x86_64-linux-gnu /usr/include discard gcc-internal paths like /usr/lib/gcc/x86_64-linux-gnu/7/include as they are not relevant for clang and even confuse it with regard to #include_next. Paths below the gcc install dir are considered as gcc-internal. The install dir is queried with $ gcc -print-search-dirs Some GCC distributions, like MinGW, ship the standard library headers in the install dir. Ensure to not discard these. Fixes: QTCREATORBUG-22898 Change-Id: Ia85258fb01b72ad073e71390e003fe8268e3b01f Reviewed-by: Cristian Adam <cristian.adam@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -1813,6 +1813,7 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &
|
||||
{QString::fromLatin1("ToolChain Type"), part->toolchainType.toString()},
|
||||
{QString::fromLatin1("ToolChain Target Triple"), part->toolChainTargetTriple},
|
||||
{QString::fromLatin1("ToolChain Word Width"), CMI::Utils::toString(part->toolChainWordWidth)},
|
||||
{QString::fromLatin1("ToolChain Install Dir"), part->toolChainInstallDir.toString()},
|
||||
{QString::fromLatin1("Language Version"), CMI::Utils::toString(part->languageVersion)},
|
||||
{QString::fromLatin1("Language Extensions"), CMI::Utils::toString(part->languageExtensions)},
|
||||
{QString::fromLatin1("Qt Version"), CMI::Utils::toString(part->qtVersion)}
|
||||
|
@@ -529,6 +529,7 @@ void Dumper::dumpProjectInfos( const QList<ProjectInfo> &projectInfos)
|
||||
m_out << i3 << "ToolChain Type : " << part->toolchainType.toString() << "\n";
|
||||
m_out << i3 << "ToolChain Target Triple: " << part->toolChainTargetTriple << "\n";
|
||||
m_out << i3 << "ToolChain Word Width : " << part->toolChainWordWidth << "\n";
|
||||
m_out << i3 << "ToolChain Install Dir : " << part->toolChainInstallDir << "\n";
|
||||
m_out << i3 << "Compiler Flags : " << part->compilerFlags.join(", ") << "\n";
|
||||
m_out << i3 << "Selected For Building : " << part->selectedForBuilding << "\n";
|
||||
m_out << i3 << "Build System Target : " << part->buildSystemTarget << "\n";
|
||||
|
@@ -167,6 +167,7 @@ ProjectPart::Ptr ProjectInfoGenerator::createProjectPart(
|
||||
part->isMsvc2015Toolchain = tcInfo.isMsvc2015ToolChain;
|
||||
part->toolChainWordWidth = tcInfo.wordWidth == 64 ? ProjectPart::WordWidth64Bit
|
||||
: ProjectPart::WordWidth32Bit;
|
||||
part->toolChainInstallDir = tcInfo.installDir;
|
||||
part->toolChainTargetTriple = tcInfo.targetTriple;
|
||||
part->extraCodeModelFlags = tcInfo.extraCodeModelFlags;
|
||||
part->compilerFlags = flags.commandLineFlags;
|
||||
|
@@ -30,9 +30,12 @@
|
||||
#endif
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
using ProjectExplorer::HeaderPath;
|
||||
@@ -57,6 +60,31 @@ bool HeaderPathFilter::isProjectHeaderPath(const QString &path) const
|
||||
return path.startsWith(projectDirectory) || path.startsWith(buildDirectory);
|
||||
}
|
||||
|
||||
void HeaderPathFilter::removeGccInternalIncludePaths()
|
||||
{
|
||||
if (projectPart.toolchainType != ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|
||||
&& projectPart.toolchainType != ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (projectPart.toolChainInstallDir.isEmpty())
|
||||
return;
|
||||
|
||||
const Utils::FilePath gccInstallDir = projectPart.toolChainInstallDir;
|
||||
auto isGccInternalInclude = [gccInstallDir](const HeaderPath &headerPath){
|
||||
const auto includePath = Utils::FilePath::fromString(headerPath.path);
|
||||
if (includePath.isChildOf(gccInstallDir)) {
|
||||
const QString remainingPath = headerPath.path.mid(gccInstallDir.toString().size());
|
||||
// MinGW ships the standard library headers in "<installdir>/include/c++".
|
||||
// Ensure that we do not remove include paths pointing there.
|
||||
return !remainingPath.startsWith("/include/c++");
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Utils::erase(builtInHeaderPaths, isGccInternalInclude);
|
||||
}
|
||||
|
||||
void HeaderPathFilter::filterHeaderPath(const ProjectExplorer::HeaderPath &headerPath)
|
||||
{
|
||||
if (headerPath.path.isEmpty())
|
||||
@@ -135,6 +163,7 @@ void removeClangSystemHeaderPaths(HeaderPaths &headerPaths)
|
||||
void HeaderPathFilter::tweakHeaderPaths()
|
||||
{
|
||||
removeClangSystemHeaderPaths(builtInHeaderPaths);
|
||||
removeGccInternalIncludePaths();
|
||||
|
||||
auto split = resourceIterator(builtInHeaderPaths,
|
||||
projectPart.toolChainTargetTriple.contains("darwin"));
|
||||
|
@@ -57,6 +57,8 @@ private:
|
||||
|
||||
bool isProjectHeaderPath(const QString &path) const;
|
||||
|
||||
void removeGccInternalIncludePaths();
|
||||
|
||||
static QString ensurePathWithSlashEnding(const QString &path);
|
||||
|
||||
public:
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include <cplusplus/Token.h>
|
||||
|
||||
#include <utils/cpplanguage_details.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QSharedPointer>
|
||||
@@ -108,6 +109,7 @@ public:
|
||||
bool isMsvc2015Toolchain = false;
|
||||
QString toolChainTargetTriple;
|
||||
ToolChainWordWidth toolChainWordWidth = WordWidth32Bit;
|
||||
Utils::FilePath toolChainInstallDir;
|
||||
ProjectExplorer::WarningFlags warningFlags = ProjectExplorer::WarningFlags::Default;
|
||||
|
||||
// Misc
|
||||
|
@@ -232,6 +232,23 @@ static QString gccVersion(const FilePath &path, const QStringList &env)
|
||||
return QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
|
||||
}
|
||||
|
||||
static Utils::FilePath gccInstallDir(const FilePath &path, const QStringList &env)
|
||||
{
|
||||
const QStringList arguments("-print-search-dirs");
|
||||
QString output = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed();
|
||||
// Expected output looks like this:
|
||||
// install: /usr/lib/gcc/x86_64-linux-gnu/7/
|
||||
// ...
|
||||
// Note that clang also supports "-print-search-dirs". However, the
|
||||
// install dir is not part of the output (tested with clang-8/clang-9).
|
||||
|
||||
const QString prefix = "install: ";
|
||||
const QString line = QTextStream(&output).readLine();
|
||||
if (!line.startsWith(prefix))
|
||||
return {};
|
||||
return Utils::FilePath::fromString(QDir::cleanPath(line.mid(prefix.size())));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// GccToolChain
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -269,6 +286,15 @@ void GccToolChain::setOriginalTargetTriple(const QString &targetTriple)
|
||||
toolChainUpdated();
|
||||
}
|
||||
|
||||
void GccToolChain::setInstallDir(const Utils::FilePath &installDir)
|
||||
{
|
||||
if (m_installDir == installDir)
|
||||
return;
|
||||
|
||||
m_installDir = installDir;
|
||||
toolChainUpdated();
|
||||
}
|
||||
|
||||
QString GccToolChain::defaultDisplayName() const
|
||||
{
|
||||
QString type = typeDisplayName();
|
||||
@@ -310,6 +336,13 @@ QString GccToolChain::version() const
|
||||
return m_version;
|
||||
}
|
||||
|
||||
FilePath GccToolChain::installDir() const
|
||||
{
|
||||
if (m_installDir.isEmpty())
|
||||
m_installDir = detectInstallDir();
|
||||
return m_installDir;
|
||||
}
|
||||
|
||||
void GccToolChain::setTargetAbi(const Abi &abi)
|
||||
{
|
||||
if (abi == m_targetAbi)
|
||||
@@ -715,6 +748,7 @@ void GccToolChain::resetToolChain(const FilePath &path)
|
||||
const DetectedAbisResult detectedAbis = detectSupportedAbis();
|
||||
m_supportedAbis = detectedAbis.supportedAbis;
|
||||
m_originalTargetTriple = detectedAbis.originalTargetTriple;
|
||||
m_installDir = installDir();
|
||||
|
||||
m_targetAbi = Abi();
|
||||
if (!m_supportedAbis.isEmpty()) {
|
||||
@@ -856,6 +890,13 @@ QString GccToolChain::detectVersion() const
|
||||
return gccVersion(findLocalCompiler(m_compilerCommand, env), env.toStringList());
|
||||
}
|
||||
|
||||
Utils::FilePath GccToolChain::detectInstallDir() const
|
||||
{
|
||||
Environment env = Environment::systemEnvironment();
|
||||
addToEnvironment(env);
|
||||
return gccInstallDir(findLocalCompiler(m_compilerCommand, env), env.toStringList());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// GccToolChainFactory
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -1119,6 +1160,9 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const ToolChainDescr
|
||||
const GccToolChain::DetectedAbisResult detectedAbis = guessGccAbi(localCompilerPath,
|
||||
systemEnvironment.toStringList(),
|
||||
macros);
|
||||
const Utils::FilePath installDir = gccInstallDir(localCompilerPath,
|
||||
systemEnvironment.toStringList());
|
||||
|
||||
for (const Abi &abi : detectedAbis.supportedAbis) {
|
||||
std::unique_ptr<GccToolChain> tc(dynamic_cast<GccToolChain *>(create()));
|
||||
if (!tc)
|
||||
@@ -1134,6 +1178,7 @@ QList<ToolChain *> GccToolChainFactory::autoDetectToolChain(const ToolChainDescr
|
||||
tc->setSupportedAbis(detectedAbis.supportedAbis);
|
||||
tc->setTargetAbi(abi);
|
||||
tc->setOriginalTargetTriple(detectedAbis.originalTargetTriple);
|
||||
tc->setInstallDir(installDir);
|
||||
tc->setDisplayName(tc->defaultDisplayName()); // reset displayname
|
||||
if (!checker || checker(tc.get()))
|
||||
result.append(tc.release());
|
||||
@@ -1192,6 +1237,7 @@ void GccToolChainConfigWidget::applyImpl()
|
||||
tc->setSupportedAbis(m_abiWidget->supportedAbis());
|
||||
tc->setTargetAbi(m_abiWidget->currentAbi());
|
||||
}
|
||||
tc->setInstallDir(tc->detectInstallDir());
|
||||
tc->setOriginalTargetTriple(tc->detectSupportedAbis().originalTargetTriple);
|
||||
tc->setDisplayName(displayName); // reset display name
|
||||
tc->setPlatformCodeGenFlags(splitString(m_platformCodeGenFlagsLineEdit->text()));
|
||||
|
@@ -71,6 +71,7 @@ public:
|
||||
|
||||
Abi targetAbi() const override;
|
||||
QString originalTargetTriple() const override;
|
||||
Utils::FilePath installDir() const override;
|
||||
QString version() const;
|
||||
Abis supportedAbis() const override;
|
||||
void setTargetAbi(const Abi &);
|
||||
@@ -129,6 +130,7 @@ protected:
|
||||
void setCompilerCommand(const Utils::FilePath &path);
|
||||
void setSupportedAbis(const Abis &abis);
|
||||
void setOriginalTargetTriple(const QString &targetTriple);
|
||||
void setInstallDir(const Utils::FilePath &installDir);
|
||||
void setMacroCache(const QStringList &allCxxflags, const Macros ¯oCache) const;
|
||||
Macros macroCache(const QStringList &allCxxflags) const;
|
||||
|
||||
@@ -137,6 +139,7 @@ protected:
|
||||
|
||||
virtual DetectedAbisResult detectSupportedAbis() const;
|
||||
virtual QString detectVersion() const;
|
||||
virtual Utils::FilePath detectInstallDir() const;
|
||||
|
||||
// Reinterpret options for compiler drivers inheriting from GccToolChain (e.g qcc) to apply -Wp option
|
||||
// that passes the initial options directly down to the gcc compiler
|
||||
@@ -196,6 +199,7 @@ private:
|
||||
mutable QString m_originalTargetTriple;
|
||||
mutable HeaderPaths m_headerPaths;
|
||||
mutable QString m_version;
|
||||
mutable Utils::FilePath m_installDir;
|
||||
|
||||
friend class Internal::GccToolChainConfigWidget;
|
||||
friend class Internal::GccToolChainFactory;
|
||||
|
@@ -184,6 +184,7 @@ ToolChainInfo::ToolChainInfo(const ToolChain *toolChain,
|
||||
wordWidth = toolChain->targetAbi().wordWidth();
|
||||
targetTriple = toolChain->originalTargetTriple();
|
||||
extraCodeModelFlags = toolChain->extraCodeModelFlags();
|
||||
installDir = toolChain->installDir();
|
||||
|
||||
// ...and save the potentially expensive operations for later so that
|
||||
// they can be run from a worker thread.
|
||||
|
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <utils/cpplanguage_details.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
@@ -152,6 +153,7 @@ public:
|
||||
bool isMsvc2015ToolChain = false;
|
||||
unsigned wordWidth = 0;
|
||||
QString targetTriple;
|
||||
Utils::FilePath installDir;
|
||||
QStringList extraCodeModelFlags;
|
||||
|
||||
QString sysRootPath; // For headerPathsRunner.
|
||||
|
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <utils/cpplanguage_details.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
@@ -114,6 +115,7 @@ public:
|
||||
virtual ProjectExplorer::Abis supportedAbis() const;
|
||||
virtual QString originalTargetTriple() const { return QString(); }
|
||||
virtual QStringList extraCodeModelFlags() const { return QStringList(); }
|
||||
virtual Utils::FilePath installDir() const { return Utils::FilePath(); }
|
||||
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <cpptools/headerpathfilter.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -248,6 +249,51 @@ TEST_F(HeaderPathFilter, ClangHeadersAndCppIncludesPathsOrderLinux)
|
||||
HasBuiltIn("/builtin_path")));
|
||||
}
|
||||
|
||||
// Include paths below the installation dir should be removed as they confuse clang.
|
||||
TEST_F(HeaderPathFilter, RemoveGccInternalPaths)
|
||||
{
|
||||
projectPart.toolChainInstallDir = Utils::FilePath::fromUtf8("/usr/lib/gcc/x86_64-linux-gnu/7");
|
||||
projectPart.toolchainType = ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID;
|
||||
projectPart.headerPaths = {
|
||||
HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/7/include", HeaderPathType::BuiltIn},
|
||||
HeaderPath{"/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed", HeaderPathType::BuiltIn},
|
||||
};
|
||||
CppTools::HeaderPathFilter filter{projectPart,
|
||||
CppTools::UseTweakedHeaderPaths::Yes,
|
||||
"6.0",
|
||||
CLANG_RESOURCE_DIR};
|
||||
|
||||
filter.process();
|
||||
|
||||
ASSERT_THAT(filter.builtInHeaderPaths, ElementsAre(HasBuiltIn(CLANG_RESOURCE_DIR)));
|
||||
}
|
||||
|
||||
// MinGW ships the standard library headers in "<installdir>/include/c++".
|
||||
// Ensure that we do not remove include paths pointing there.
|
||||
TEST_F(HeaderPathFilter, RemoveGccInternalPathsExceptForStandardPaths)
|
||||
{
|
||||
projectPart.toolChainInstallDir = Utils::FilePath::fromUtf8(
|
||||
"c:/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0");
|
||||
projectPart.toolchainType = ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID;
|
||||
projectPart.headerPaths = {
|
||||
HeaderPath{"c:/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++", HeaderPathType::BuiltIn},
|
||||
HeaderPath{"c:/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/x86_64-w64-mingw32", HeaderPathType::BuiltIn},
|
||||
HeaderPath{"c:/mingw730_64/lib/gcc/x86_64-w64-mingw32/7.3.0/include/c++/backward", HeaderPathType::BuiltIn},
|
||||
};
|
||||
|
||||
auto expected = projectPart.headerPaths;
|
||||
expected << HeaderPath{CLANG_RESOURCE_DIR, HeaderPathType::BuiltIn};
|
||||
|
||||
CppTools::HeaderPathFilter filter{projectPart,
|
||||
CppTools::UseTweakedHeaderPaths::Yes,
|
||||
"6.0",
|
||||
CLANG_RESOURCE_DIR};
|
||||
|
||||
filter.process();
|
||||
|
||||
ASSERT_THAT(filter.builtInHeaderPaths, ContainerEq(expected));
|
||||
}
|
||||
|
||||
TEST_F(HeaderPathFilter, ClangHeadersAndCppIncludesPathsOrderNoVersion)
|
||||
{
|
||||
projectPart.headerPaths = {
|
||||
|
Reference in New Issue
Block a user