diff options
Diffstat (limited to 'sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp')
-rw-r--r-- | sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp | 122 |
1 files changed, 89 insertions, 33 deletions
diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp index 8c3eeb592..20224020b 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp @@ -3,6 +3,7 @@ #include "compilersupport.h" #include "header_paths.h" +#include "clangutils.h" #include <reporthandler.h> @@ -93,13 +94,19 @@ bool setPlatform(const QString &name) return result; } +// 3/2024: Use a recent MSVC2022 for libclang 18.X +static QByteArray msvcCompatVersion() +{ + return libClangVersion() >= QVersionNumber(0, 64) ? "19.39"_ba : "19.26"_ba; +} + static bool runProcess(const QString &program, const QStringList &arguments, QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr) { QProcess process; process.start(program, arguments, QProcess::ReadWrite); if (!process.waitForStarted()) { - qWarning().noquote().nospace() << "Unable to start " + qCWarning(lcShiboken).noquote().nospace() << "Unable to start " << process.program() << ": " << process.errorString(); return false; } @@ -112,18 +119,18 @@ static bool runProcess(const QString &program, const QStringList &arguments, *stdOutIn = process.readAllStandardOutput(); if (!finished) { - qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr; + qCWarning(lcShiboken).noquote().nospace() << process.program() << " timed out: " << stdErr; process.kill(); return false; } if (process.exitStatus() != QProcess::NormalExit) { - qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr; + qCWarning(lcShiboken).noquote().nospace() << process.program() << " crashed: " << stdErr; return false; } if (process.exitCode() != 0) { - qWarning().noquote().nospace() << process.program() << " exited " + qCWarning(lcShiboken).noquote().nospace() << process.program() << " exited " << process.exitCode() << ": " << stdErr; return false; } @@ -178,6 +185,13 @@ static HeaderPaths gppInternalIncludePaths(const QString &compiler) return result; const QByteArrayList stdErrLines = stdErr.split('\n'); bool isIncludeDir = false; + + if (ReportHandler::isDebug(ReportHandler::MediumDebug)) + qCInfo(lcShiboken()).noquote().nospace() + << "gppInternalIncludePaths:\n compiler: " << compiler + << "\n stdOut: " << stdOut + << "\n stdErr: " << stdErr; + for (const QByteArray &line : stdErrLines) { if (isIncludeDir) { if (line.startsWith(QByteArrayLiteral("End of search list"))) { @@ -239,6 +253,23 @@ static bool needsClangBuiltinIncludes() return platform() != Platform::macOS; } +static QString queryLlvmConfigDir(const QString &arg) +{ + static const QString llvmConfig = QStandardPaths::findExecutable(u"llvm-config"_s); + if (llvmConfig.isEmpty()) + return {}; + QByteArray stdOut; + if (!runProcess(llvmConfig, QStringList{arg}, &stdOut)) + return {}; + const QString path = QFile::decodeName(stdOut.trimmed()); + if (!QFileInfo::exists(path)) { + qCWarning(lcShiboken, R"(%s: "%s" as returned by llvm-config "%s" does not exist.)", + __FUNCTION__, qPrintable(QDir::toNativeSeparators(path)), qPrintable(arg)); + return {}; + } + return path; +} + static QString findClangLibDir() { for (const char *envVar : {"LLVM_INSTALL_DIR", "CLANG_INSTALL_DIR"}) { @@ -246,21 +277,11 @@ static QString findClangLibDir() const QString path = QFile::decodeName(qgetenv(envVar)) + u"/lib"_s; if (QFileInfo::exists(path)) return path; - qWarning("%s: %s as pointed to by %s does not exist.", __FUNCTION__, qPrintable(path), envVar); - } - } - const QString llvmConfig = - QStandardPaths::findExecutable(u"llvm-config"_s); - if (!llvmConfig.isEmpty()) { - QByteArray stdOut; - if (runProcess(llvmConfig, QStringList{u"--libdir"_s}, &stdOut)) { - const QString path = QFile::decodeName(stdOut.trimmed()); - if (QFileInfo::exists(path)) - return path; - qWarning("%s: %s as returned by llvm-config does not exist.", __FUNCTION__, qPrintable(path)); + qCWarning(lcShiboken, "%s: %s as pointed to by %s does not exist.", + __FUNCTION__, qPrintable(path), envVar); } } - return QString(); + return queryLlvmConfigDir(u"--libdir"_s); } static QString findClangBuiltInIncludesDir() @@ -269,13 +290,23 @@ static QString findClangBuiltInIncludesDir() const QString clangPathLibDir = findClangLibDir(); if (!clangPathLibDir.isEmpty()) { QString candidate; + QString clangDirName = clangPathLibDir + u"/clang"_s; + // PYSIDE-2769: llvm-config --libdir may report /usr/lib64 on manylinux_2_28_x86_64 + // whereas the includes are under /usr/lib/clang/../include. + if (!QFileInfo::exists(clangDirName) && clangPathLibDir.endsWith("64"_L1)) { + const QString fallback = clangPathLibDir.sliced(0, clangPathLibDir.size() - 2); + clangDirName = fallback + u"/clang"_s; + qCWarning(lcShiboken, "%s: Falling back from %s to %s.", + __FUNCTION__, qPrintable(clangPathLibDir), qPrintable(fallback)); + } + QVersionNumber lastVersionNumber(1, 0, 0); - const QString clangDirName = clangPathLibDir + u"/clang"_s; QDir clangDir(clangDirName); const QFileInfoList versionDirs = clangDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); if (versionDirs.isEmpty()) - qWarning("%s: No subdirectories found in %s.", __FUNCTION__, qPrintable(clangDirName)); + qCWarning(lcShiboken, "%s: No subdirectories found in %s.", + __FUNCTION__, qPrintable(clangDirName)); for (const QFileInfo &fi : versionDirs) { const QString fileName = fi.fileName(); if (fileName.at(0).isDigit()) { @@ -287,22 +318,44 @@ static QString findClangBuiltInIncludesDir() } } if (!candidate.isEmpty()) - return candidate + QStringLiteral("/include"); + return candidate + "/include"_L1; } - return QString(); + return queryLlvmConfigDir(u"--includedir"_s); } +QString compilerFromCMake() +{ +#ifdef CMAKE_CXX_COMPILER + return QString::fromLocal8Bit(CMAKE_CXX_COMPILER); +#else + return {}; +#endif +} + +// Return a compiler suitable for determining the internal include paths static QString compilerFromCMake(const QString &defaultCompiler) { if (!compilerPath().isEmpty()) return compilerPath(); -// Added !defined(Q_OS_DARWIN) due to PYSIDE-1032 - QString result = defaultCompiler; -#ifdef CMAKE_CXX_COMPILER - if (platform() != Platform::macOS) - result = QString::fromLocal8Bit(CMAKE_CXX_COMPILER); -#endif - return result; + // Exclude macOS since cmakeCompiler returns the full path instead of the + // /usr/bin/clang shim, which results in the default SDK sysroot path + // missing (PYSIDE-1032) + if (platform() == Platform::macOS) + return defaultCompiler; + QString cmakeCompiler = compilerFromCMake(); + if (cmakeCompiler.isEmpty()) + return defaultCompiler; + QFileInfo fi(cmakeCompiler); + // Should be absolute by default, but a user may specify -DCMAKE_CXX_COMPILER=cl.exe + if (fi.isRelative()) + return cmakeCompiler; + if (fi.exists()) + return fi.absoluteFilePath(); + // The compiler may not exist in case something like icecream or + // a non-standard-path was used on the build machine. Check + // the executable. + cmakeCompiler = QStandardPaths::findExecutable(fi.fileName()); + return cmakeCompiler.isEmpty() ? defaultCompiler : cmakeCompiler; } static void appendClangBuiltinIncludes(HeaderPaths *p) @@ -314,7 +367,8 @@ static void appendClangBuiltinIncludes(HeaderPaths *p) "(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", + qCInfo(lcShiboken, "CLANG v%d.%d, builtins includes directory: %s", + CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR, qPrintable(clangBuiltinIncludesDir)); p->append(HeaderPath{QFile::encodeName(clangBuiltinIncludesDir), HeaderType::System}); @@ -322,15 +376,17 @@ static void appendClangBuiltinIncludes(HeaderPaths *p) } // Returns clang options needed for emulating the host compiler -QByteArrayList emulatedCompilerOptions() +QByteArrayList emulatedCompilerOptions(LanguageLevel level) { QByteArrayList result; HeaderPaths headerPaths; switch (compiler()) { case Compiler::Msvc: - result.append(QByteArrayLiteral("-fms-compatibility-version=19.26.28806")); - result.append(QByteArrayLiteral("-fdelayed-template-parsing")); + result.append("-fms-compatibility-version="_ba + msvcCompatVersion()); + if (level < LanguageLevel::Cpp20) + result.append("-fdelayed-template-parsing"_ba); result.append(QByteArrayLiteral("-Wno-microsoft-enum-value")); + result.append("/Zc:__cplusplus"_ba); // Fix yvals_core.h: STL1000: Unexpected compiler version, expected Clang 7 or newer (MSVC2017 update) result.append(QByteArrayLiteral("-D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH")); if (needsClangBuiltinIncludes()) @@ -346,7 +402,7 @@ QByteArrayList emulatedCompilerOptions() // Append the c++ include paths since Clang is unable to find // <type_traits> etc (g++ 11.3). - const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(u"g++"_qs)); + const HeaderPaths gppPaths = gppInternalIncludePaths(compilerFromCMake(u"g++"_s)); for (const HeaderPath &h : gppPaths) { if (h.path.contains("c++") || h.path.contains("sysroot")) headerPaths.append(h); |