diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp | 91 |
1 files changed, 82 insertions, 9 deletions
diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp index e7de8fdb3..9f4f7dc03 100644 --- a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp @@ -29,8 +29,14 @@ #include "compilersupport.h" #include "header_paths.h" +#include <reporthandler.h> + #include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> #include <QtCore/QProcess> +#include <QtCore/QStandardPaths> #include <QtCore/QStringList> #include <QtCore/QVersionNumber> @@ -155,6 +161,68 @@ static inline bool isRedHat74() static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); } #endif +// The clang builtin includes directory is used to find the definitions for +// intrinsic functions and builtin types. It is necessary to use the clang +// includes to prevent redefinition errors. The default toolchain includes +// should be picked up automatically by clang without specifying +// them implicitly. + +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) +# define NEED_CLANG_BUILTIN_INCLUDES 1 +#else +# define NEED_CLANG_BUILTIN_INCLUDES 0 +#endif + +#if NEED_CLANG_BUILTIN_INCLUDES +static QString findClang() +{ + for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) { + if (qEnvironmentVariableIsSet(envVar)) { + const QString path = QFile::decodeName(qgetenv(envVar)); + if (QFileInfo::exists(path)) + return path; + } + } + const QString llvmConfig = + QStandardPaths::findExecutable(QLatin1String("llvm-config")); + if (!llvmConfig.isEmpty()) { + QByteArray stdOut; + if (runProcess(llvmConfig, QStringList{QLatin1String("--prefix")}, &stdOut)) { + const QString path = QFile::decodeName(stdOut.trimmed()); + if (QFileInfo::exists(path)) + return path; + } + } + return QString(); +} + +static QString findClangBuiltInIncludesDir() +{ + // Find the include directory of the highest version. + const QString clangPath = findClang(); + if (!clangPath.isEmpty()) { + QString candidate; + QVersionNumber lastVersionNumber(1, 0, 0); + QDir clangDir(clangPath + QLatin1String("/lib/clang")); + const QFileInfoList versionDirs = + clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QFileInfo &fi : versionDirs) { + const QString fileName = fi.fileName(); + if (fileName.at(0).isDigit()) { + const QVersionNumber versionNumber = QVersionNumber::fromString(fileName.at(0)); + if (!versionNumber.isNull() && versionNumber > lastVersionNumber) { + candidate = fi.absoluteFilePath(); + lastVersionNumber = versionNumber; + } + } + } + if (!candidate.isEmpty()) + return candidate + QStringLiteral("/include"); + } + return QString(); +} +#endif // NEED_CLANG_BUILTIN_INCLUDES + // Returns clang options needed for emulating the host compiler QByteArrayList emulatedCompilerOptions() { @@ -169,16 +237,21 @@ QByteArrayList emulatedCompilerOptions() #elif defined(Q_CC_GNU) HeaderPaths headerPaths; - // The clang builtin includes directory is used to find the definitions for intrinsic functions - // and builtin types. It is necessary to use the clang includes to prevent redefinition errors. - // The default toolchain includes should be picked up automatically by clang without specifying - // them implicitly. - QByteArray clangBuiltinIncludesDir(CLANG_BUILTIN_INCLUDES_DIR); - - if (!clangBuiltinIncludesDir.isEmpty()) { - result.append(QByteArrayLiteral("-isystem")); - result.append(clangBuiltinIncludesDir); +#if NEED_CLANG_BUILTIN_INCLUDES + const QString clangBuiltinIncludesDir = + QDir::toNativeSeparators(findClangBuiltInIncludesDir()); + if (clangBuiltinIncludesDir.isEmpty()) { + qCWarning(lcShiboken, "Unable to locate Clang's built-in include directory " + "(neither by checking the environment variables LLVM_INSTALL_DIR, CLANG_INSTALL_DIR " + " nor running llvm-config). This may lead to parse errors."); + } else { + qCInfo(lcShiboken, "CLANG builtins includes directory: %s", + qPrintable(clangBuiltinIncludesDir)); + headerPaths.append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), + HeaderType::System}); } +#endif // NEED_CLANG_BUILTIN_INCLUDES + // Append the c++ include paths since Clang is unable to find <list> etc // on RHEL 7.4 with g++ 6.3. A fix for this has been added to Clang 5.0, // so, the code can be removed once Clang 5.0 is the minimum version. |