aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp')
-rw-r--r--sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp122
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);