Clang: Android: fix clang code model errors

Add missing gcc include directories in Android toolchain.
This introduces the similar "magic" that we have in qmake
(*qtsource*/qtbase/mkspecs/common/android-base-head.conf)
but allows us to have those paths wherever we use android
toolchain.

Change-Id: I5740f1f2339fd30670567f24db2be2454f665f41
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ivan Donchevskii
2017-11-06 16:00:25 +01:00
parent 1601f53542
commit 08e3d8f011
5 changed files with 119 additions and 40 deletions

View File

@@ -40,6 +40,7 @@
#include <utils/algorithm.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>
#include <utils/synchronousprocess.h>
#include <QDir>
#include <QDirIterator>
@@ -91,6 +92,56 @@ AndroidToolChain::AndroidToolChain(const AndroidToolChain &tc) :
AndroidToolChain::~AndroidToolChain()
{ }
static QString getArch(const QString &triple)
{
if (triple.indexOf("x86_64") == 0)
return "x86_64";
if (triple.indexOf("i686") == 0)
return "x86";
if (triple.indexOf("mips64") == 0)
return "mips64";
if (triple.indexOf("mips") == 0)
return "mips";
if (triple.indexOf("aarch64") == 0)
return "arm64-v8a";
return "armeabi-v7a";
}
// Paths added here are those that were used by qmake. They were taken from
// *qtsource*/qtbase/mkspecs/common/android-base-head.conf
// Adding them here allows us to use them for all build systems.
static void addSystemHeaderPaths(QList<ProjectExplorer::HeaderPath> &paths,
const QString &triple, const QString &version)
{
const Utils::FileName ndkPath = AndroidConfigurations::currentConfig().ndkLocation();
// Get short version (for example 4.9)
const QString clangVersion = version.left(version.lastIndexOf('.'));
Utils::FileName stdcppPath = ndkPath;
stdcppPath.appendPath("sources/cxx-stl/gnu-libstdc++/" + clangVersion);
Utils::FileName includePath = stdcppPath;
Utils::FileName cppLibsPath = stdcppPath;
cppLibsPath.appendPath("libs/" + getArch(triple) + "/include/");
paths.prepend({cppLibsPath.toString(), ProjectExplorer::HeaderPath::GlobalHeaderPath});
includePath.appendPath("include/");
paths.prepend({includePath.toString(), ProjectExplorer::HeaderPath::GlobalHeaderPath});
paths.prepend({ndkPath.toString() + "/sysroot/usr/include/" + triple,
ProjectExplorer::HeaderPath::GlobalHeaderPath});
paths.prepend({ndkPath.toString() + "/sysroot/usr/include",
ProjectExplorer::HeaderPath::GlobalHeaderPath});
}
AndroidToolChain::SystemHeaderPathsRunner AndroidToolChain::createSystemHeaderPathsRunner() const
{
const QString triple = originalTargetTriple();
const QString version = this->version();
initExtraHeaderPathsFunction([triple, version] (QList<HeaderPath> &paths) {
addSystemHeaderPaths(paths, triple, version);
});
return GccToolChain::createSystemHeaderPathsRunner();
}
QString AndroidToolChain::typeDisplayName() const
{
return AndroidToolChainFactory::tr("Android GCC");
@@ -246,7 +297,9 @@ void AndroidToolChain::setSecondaryToolChain(bool b)
GccToolChain::DetectedAbisResult AndroidToolChain::detectSupportedAbis() const
{
return QList<Abi>() << targetAbi();
GccToolChain::DetectedAbisResult supportedAbis = GccToolChain::detectSupportedAbis();
supportedAbis.supportedAbis = {targetAbi()};
return supportedAbis;
}
// --------------------------------------------------------------------------
@@ -415,6 +468,7 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath,
ToolChain::AutoDetection);
tc->resetToolChain(compilerPath);
}
QTC_ASSERT(!tc->originalTargetTriple().isEmpty(), continue);
result.append(tc);
toolChainBundle.append(tc);
}

View File

@@ -45,7 +45,7 @@ public:
bool operator ==(const ProjectExplorer::ToolChain &) const override;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() override;
virtual Utils::FileName suggestedDebugger() const override;
Utils::FileName suggestedDebugger() const override;
Utils::FileName suggestedGdbServer() const;
QVariantMap toMap() const override;
@@ -58,6 +58,8 @@ public:
bool isSecondaryToolChain() const;
void setSecondaryToolChain(bool b);
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override;
protected:
DetectedAbisResult detectSupportedAbis() const override;

View File

@@ -451,16 +451,10 @@ bool CompilerOptionsBuilder::excludeDefineDirective(const ProjectExplorer::Macro
if (macro.key == "__cplusplus")
return true;
// gcc 4.9 has:
// #define __has_include(STR) __has_include__(STR)
// #define __has_include_next(STR) __has_include_next__(STR)
// The right-hand sides are gcc built-ins that clang does not understand, and they'd
// override clang's own (non-macro, it seems) definitions of the symbols on the left-hand
// side.
if (isGccOrMinGwToolchain(m_projectPart.toolchainType)
&& macro.key.contains("has_include")) {
// Ignore for all compiler toolchains since LLVM has it's own implementation for
// __has_include(STR) and __has_include_next(STR)
if (macro.key.startsWith("__has_include"))
return true;
}
// If _FORTIFY_SOURCE is defined (typically in release mode), it will
// enable the inclusion of extra headers to help catching buffer overflows

View File

@@ -579,6 +579,46 @@ WarningFlags GccToolChain::warningFlags(const QStringList &cflags) const
return flags;
}
QStringList GccToolChain::gccPrepareArguments(const QStringList &flags,
const QString &sysRoot,
const QStringList &platformCodeGenFlags,
Core::Id languageId,
OptionsReinterpreter reinterpretOptions)
{
QStringList arguments;
const bool hasKitSysroot = !sysRoot.isEmpty();
if (hasKitSysroot)
arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot));
QStringList allFlags;
allFlags << platformCodeGenFlags << flags;
for (int i = 0; i < allFlags.size(); ++i) {
const QString &flag = allFlags.at(i);
if (flag.startsWith("-stdlib=") || flag.startsWith("--gcctoolchain=")) {
arguments << flag;
} else if (!hasKitSysroot) {
// pass build system's sysroot to compiler, if we didn't pass one from kit
if (flag.startsWith("--sysroot=")) {
arguments << flag;
} else if ((flag.startsWith("-isysroot") || flag.startsWith("--sysroot"))
&& i < flags.size() - 1) {
arguments << flag << allFlags.at(i + 1);
++i;
}
}
}
arguments << languageOption(languageId) << "-E" << "-v" << "-";
arguments = reinterpretOptions(arguments);
return arguments;
}
// NOTE: extraHeaderPathsFunction must NOT capture this or it's members!!!
void GccToolChain::initExtraHeaderPathsFunction(ExtraHeaderPathsFunction &&extraHeaderPathsFunction) const
{
m_extraHeaderPathsFunction = std::move(extraHeaderPathsFunction);
}
ToolChain::SystemHeaderPathsRunner GccToolChain::createSystemHeaderPathsRunner() const
{
// Using a clean environment breaks ccache/distcc/etc.
@@ -593,42 +633,21 @@ ToolChain::SystemHeaderPathsRunner GccToolChain::createSystemHeaderPathsRunner()
Core::Id languageId = language();
// This runner must be thread-safe!
return [env, compilerCommand, platformCodeGenFlags, reinterpretOptions, headerCache, languageId]
return [env, compilerCommand, platformCodeGenFlags, reinterpretOptions, headerCache, languageId,
extraHeaderPathsFunction = m_extraHeaderPathsFunction]
(const QStringList &flags, const QString &sysRoot) {
// Prepare arguments
QStringList arguments;
const bool hasKitSysroot = !sysRoot.isEmpty();
if (hasKitSysroot)
arguments.append(QString::fromLatin1("--sysroot=%1").arg(sysRoot));
QStringList allFlags;
allFlags << platformCodeGenFlags << flags;
for (int i = 0; i < allFlags.size(); ++i) {
const QString &flag = allFlags.at(i);
if (flag.startsWith("-stdlib=") || flag.startsWith("--gcctoolchain=")) {
arguments << flag;
} else if (!hasKitSysroot) {
// pass build system's sysroot to compiler, if we didn't pass one from kit
if (flag.startsWith("--sysroot=")) {
arguments << flag;
} else if ((flag.startsWith("-isysroot") || flag.startsWith("--sysroot"))
&& i < flags.size() - 1) {
arguments << flag << allFlags.at(i + 1);
++i;
}
}
}
arguments << languageOption(languageId) << "-E" << "-v" << "-";
arguments = reinterpretOptions(arguments);
QStringList arguments = gccPrepareArguments(flags, sysRoot, platformCodeGenFlags,
languageId, reinterpretOptions);
const Utils::optional<QList<HeaderPath>> cachedPaths = headerCache->check(arguments);
if (cachedPaths)
return cachedPaths.value();
const QList<HeaderPath> paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env),
arguments,
env.toStringList());
QList<HeaderPath> paths = gccHeaderPaths(findLocalCompiler(compilerCommand, env),
arguments,
env.toStringList());
extraHeaderPathsFunction(paths);
headerCache->insert(arguments, paths);
qCDebug(gccLog) << "Reporting header paths to code model:";

View File

@@ -208,6 +208,10 @@ protected:
// that passes the initial options directly down to the gcc compiler
using OptionsReinterpreter = std::function<QStringList(const QStringList &options)>;
void setOptionsReinterpreter(const OptionsReinterpreter &optionsReinterpreter);
using ExtraHeaderPathsFunction = std::function<void(QList<HeaderPath> &)>;
void initExtraHeaderPathsFunction(ExtraHeaderPathsFunction &&extraHeaderPathsFunction) const;
static QList<HeaderPath> gccHeaderPaths(const Utils::FileName &gcc, const QStringList &args, const QStringList &env);
class WarningFlagAdder
@@ -229,6 +233,11 @@ private:
explicit GccToolChain(Detection d);
void updateSupportedAbis() const;
static QStringList gccPrepareArguments(const QStringList &flags,
const QString &sysRoot,
const QStringList &platformCodeGenFlags,
Core::Id languageId,
OptionsReinterpreter reinterpretOptions);
Utils::FileName m_compilerCommand;
QStringList m_platformCodeGenFlags;
@@ -244,6 +253,7 @@ private:
mutable std::shared_ptr<Cache<QVector<Macro>, 64>> m_predefinedMacrosCache;
mutable std::shared_ptr<Cache<QList<HeaderPath>>> m_headerPathsCache;
mutable ExtraHeaderPathsFunction m_extraHeaderPathsFunction = [](QList<HeaderPath> &) {};
friend class Internal::GccToolChainConfigWidget;
friend class Internal::GccToolChainFactory;