1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2021 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:execute-external-code
5
6#include "qdir.h"
7#include "qstringlist.h"
8#include "qfile.h"
9#if QT_CONFIG(settings)
10#include "qresource.h"
11#include "qsettings.h"
12#endif
13#include "qlibraryinfo.h"
14#include "qlibraryinfo_p.h"
15
16#include "qcoreapplication.h"
17
18#include "private/qcoreapplication_p.h"
19#include "private/qfilesystementry_p.h"
20#include "archdetect.cpp"
21#include "qconfig.cpp"
22
23#ifdef Q_OS_DARWIN
24# include "private/qcore_mac_p.h"
25#endif // Q_OS_DARWIN
26
27#if QT_CONFIG(relocatable) && QT_CONFIG(dlopen) && !QT_CONFIG(framework)
28# include <dlfcn.h>
29#endif
30
31#if QT_CONFIG(relocatable) && defined(Q_OS_WIN)
32# include <qt_windows.h>
33#endif
34
35#include <memory>
36
37QT_BEGIN_NAMESPACE
38
39using namespace Qt::StringLiterals;
40
41extern void qDumpCPUFeatures(); // in qsimd.cpp
42
43#if QT_CONFIG(settings)
44
45static std::unique_ptr<QSettings> findConfiguration();
46
47struct QLibrarySettings
48{
49 QLibrarySettings();
50 void load();
51 bool havePaths();
52 QSettings *configuration();
53
54 std::unique_ptr<QSettings> settings;
55 bool paths;
56 bool reloadOnQAppAvailable;
57};
58Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
59
60QLibrarySettings::QLibrarySettings() : paths(false), reloadOnQAppAvailable(false)
61{
62 load();
63}
64
65QSettings *QLibrarySettings::configuration()
66{
67 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
68 load();
69 return settings.get();
70}
71
72bool QLibrarySettings::havePaths()
73{
74 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
75 load();
76 return paths;
77}
78
79void QLibrarySettings::load()
80{
81 // If we get any settings here, those won't change when the application shows up.
82 settings = findConfiguration();
83 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
84
85 if (settings) {
86 // This code needs to be in the regular library, as otherwise a qt.conf that
87 // works for qmake would break things for dynamically built Qt tools.
88 QStringList children = settings->childGroups();
89 paths = !children.contains(str: "Platforms"_L1)
90 || children.contains(str: "Paths"_L1);
91 }
92}
93
94namespace {
95const QString *qtconfManualPath = nullptr;
96}
97
98void QLibraryInfoPrivate::setQtconfManualPath(const QString *path)
99{
100 qtconfManualPath = path;
101}
102
103static std::unique_ptr<QSettings> findConfiguration()
104{
105 if (qtconfManualPath)
106 return std::make_unique<QSettings>(args: *qtconfManualPath, args: QSettings::IniFormat);
107
108 QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
109 if (QResource(qtconfig, QLocale::c()).isValid())
110 return std::make_unique<QSettings>(args&: qtconfig, args: QSettings::IniFormat);
111#ifdef Q_OS_DARWIN
112 CFBundleRef bundleRef = CFBundleGetMainBundle();
113 if (bundleRef) {
114 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
115 QCFString("qt.conf"_L1),
116 0,
117 0);
118 if (urlRef) {
119 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
120 qtconfig = QDir::cleanPath(path);
121 if (QFile::exists(qtconfig))
122 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
123 }
124 }
125#endif
126 if (QCoreApplication::instanceExists()) {
127 QString pwd = QCoreApplication::applicationDirPath();
128 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR) ".conf"_s;
129 if (QFile::exists(fileName: qtconfig))
130 return std::make_unique<QSettings>(args&: qtconfig, args: QSettings::IniFormat);
131 qtconfig = pwd + u"/qt.conf";
132 if (QFile::exists(fileName: qtconfig))
133 return std::make_unique<QSettings>(args&: qtconfig, args: QSettings::IniFormat);
134 }
135 return nullptr; //no luck
136}
137
138QSettings *QLibraryInfoPrivate::configuration()
139{
140 QLibrarySettings *ls = qt_library_settings();
141 return ls ? ls->configuration() : nullptr;
142}
143
144void QLibraryInfoPrivate::reload()
145{
146 if (qt_library_settings.exists())
147 qt_library_settings->load();
148}
149
150static bool havePaths() {
151 QLibrarySettings *ls = qt_library_settings();
152 return ls && ls->havePaths();
153}
154
155#endif // settings
156
157/*!
158 \class QLibraryInfo
159 \inmodule QtCore
160 \brief The QLibraryInfo class provides information about the Qt library.
161
162 Many pieces of information are established when Qt is configured and built.
163 This class provides an abstraction for accessing that information.
164 By using the static functions of this class, an application can obtain
165 information about the instance of the Qt library which the application
166 is using at run-time.
167
168 You can also use a \c qt.conf file to override the hard-coded paths
169 that are compiled into the Qt library. For more information, see
170 the \l {Using qt.conf} documentation.
171
172 \sa QSysInfo, {Using qt.conf}
173*/
174
175/*!
176 \internal
177
178 You cannot create a QLibraryInfo, instead only the static functions are available to query
179 information.
180*/
181
182QLibraryInfo::QLibraryInfo()
183{ }
184
185#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
186# define COMPILER_STRING __VERSION__ /* already includes the compiler's name */
187#elif defined(Q_CC_GHS)
188# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
189#elif defined(Q_CC_GNU)
190# define COMPILER_STRING "GCC " __VERSION__
191#elif defined(Q_CC_MSVC)
192# if _MSC_VER < 1910
193# define COMPILER_STRING "MSVC 2015"
194# elif _MSC_VER < 1917
195# define COMPILER_STRING "MSVC 2017"
196# elif _MSC_VER < 1930
197# define COMPILER_STRING "MSVC 2019"
198# elif _MSC_VER < 2000
199# define COMPILER_STRING "MSVC 2022"
200# else
201# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
202# endif
203#else
204# define COMPILER_STRING "<unknown compiler>"
205#endif
206#ifdef QT_NO_DEBUG
207# define DEBUG_STRING " release"
208#else
209# define DEBUG_STRING " debug"
210#endif
211#ifdef QT_SHARED
212# define SHARED_STRING " shared (dynamic)"
213#else
214# define SHARED_STRING " static"
215#endif
216static const char *qt_build_string() noexcept
217{
218 return "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")";
219}
220
221/*!
222 Returns a string describing how this version of Qt was built.
223
224 \internal
225
226 \since 5.3
227*/
228
229const char *QLibraryInfo::build() noexcept
230{
231 return qt_build_string();
232}
233
234/*!
235 \since 5.0
236 Returns \c true if this build of Qt was built with debugging enabled, or
237 false if it was built in release mode.
238*/
239bool
240QLibraryInfo::isDebugBuild() noexcept
241{
242#ifdef QT_DEBUG
243 return true;
244#else
245 return false;
246#endif
247}
248
249/*!
250 \since 6.5
251 Returns \c true if this is a shared (dynamic) build of Qt.
252*/
253bool QLibraryInfo::isSharedBuild() noexcept
254{
255#ifdef QT_SHARED
256 return true;
257#else
258 return false;
259#endif
260}
261
262/*!
263 \since 5.8
264 Returns the version of the Qt library.
265
266 \sa qVersion()
267*/
268QVersionNumber QLibraryInfo::version() noexcept
269{
270 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
271}
272
273static QString prefixFromAppDirHelper()
274{
275 if (QCoreApplication::instanceExists()) {
276#ifdef Q_OS_DARWIN
277 CFBundleRef bundleRef = CFBundleGetMainBundle();
278 if (bundleRef) {
279 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
280 if (urlRef) {
281 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
282#ifdef Q_OS_MACOS
283 QString bundleContentsDir = QString(path) + "/Contents/"_L1;
284 if (QDir(bundleContentsDir).exists())
285 return QDir::cleanPath(bundleContentsDir);
286#else
287 return QDir::cleanPath(QString(path)); // iOS
288#endif // Q_OS_MACOS
289 }
290 }
291#endif // Q_OS_DARWIN
292 // We make the prefix path absolute to the executable's directory.
293 return QCoreApplication::applicationDirPath();
294 } else {
295 return QDir::currentPath();
296 }
297}
298
299#if QT_CONFIG(relocatable)
300#if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework)) \
301 && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
302static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
303{
304 const QString qtCoreLibrary = QDir::fromNativeSeparators(pathName: qtCoreLibraryPath);
305 const QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
306 const QString prefixDir = libDir + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
307 return QDir::cleanPath(path: prefixDir);
308}
309#endif
310
311#if defined(Q_OS_WIN)
312static HMODULE getWindowsModuleHandle()
313{
314 HMODULE hModule = NULL;
315 GetModuleHandleEx(
316 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
317 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
318 return hModule;
319}
320#endif // Q_OS_WIN
321
322static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
323{
324 QString prefixPath;
325
326 // For static builds, the prefix will be the app directory.
327 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
328#if defined(QT_STATIC)
329 prefixPath = prefixFromAppDirHelper();
330 if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) {
331 // For Qt tools in a static build, we must chop off the bin directory.
332 constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1);
333 constexpr size_t binDirLength = binDir.size() + 1;
334 prefixPath.chop(binDirLength);
335 }
336#elif defined(Q_OS_DARWIN) && QT_CONFIG(framework)
337 Q_UNUSED(usageMode);
338#ifndef QT_LIBINFIX
339 #define QT_LIBINFIX ""
340#endif
341 auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtCore" QT_LIBINFIX));
342 if (!qtCoreBundle) {
343 // When running Qt apps over Samba shares, CoreFoundation will fail to find
344 // the Resources directory inside the bundle, This directory is a symlink,
345 // and CF relies on readdir() and dtent.dt_type to detect symlinks, which
346 // does not work reliably for Samba shares. We work around it by manually
347 // looking for the QtCore bundle.
348 auto allBundles = CFBundleGetAllBundles();
349 auto bundleCount = CFArrayGetCount(allBundles);
350 for (int i = 0; i < bundleCount; ++i) {
351 auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i));
352 auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle));
353 auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
354 if (CFStringHasSuffix(path, CFSTR("/QtCore" QT_LIBINFIX ".framework"))) {
355 qtCoreBundle = bundle;
356 break;
357 }
358 }
359 }
360 Q_ASSERT(qtCoreBundle);
361
362 QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle);
363 Q_ASSERT(qtCorePath);
364
365 QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath);
366 Q_ASSERT(qtCorePathAbsolute);
367
368 QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute);
369
370 const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle);
371
372 const QString prefixDir = QString(libDirCFString) + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
373
374 prefixPath = QDir::cleanPath(prefixDir);
375#elif defined(Q_OS_WASM)
376 // Emscripten expects to find shared libraries at the root of the in-memory
377 // file system when resolving dependencies for for dlopen() calls. So that's
378 // where libqt6core.so would be.
379 prefixPath = QStringLiteral("/");
380#elif QT_CONFIG(dlopen)
381 Q_UNUSED(usageMode);
382 Dl_info info;
383 int result = dladdr(address: reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), info: &info);
384 if (result > 0 && info.dli_fname)
385 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreLibraryPath: QString::fromLocal8Bit(ba: info.dli_fname));
386#elif defined(Q_OS_WIN)
387 Q_UNUSED(usageMode);
388 HMODULE hModule = getWindowsModuleHandle();
389 const int kBufferSize = 4096;
390 wchar_t buffer[kBufferSize];
391 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
392 const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize));
393 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
394
395 hModule = reinterpret_cast<HMODULE>(QCoreApplicationPrivate::mainInstanceHandle);
396 pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
397 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath();
398 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
399 // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an
400 // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking
401 // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib.
402 const QString libdir = QString::fromLocal8Bit(
403 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
404 const QLatin1Char slash('/');
405#if defined(Q_CC_MINGW)
406 const QString implibPrefix = QStringLiteral("lib");
407 const QString implibSuffix = QStringLiteral(".a");
408#else
409 const QString implibPrefix;
410 const QString implibSuffix = QStringLiteral(".lib");
411#endif
412 const QString qtCoreImpLibFileName = implibPrefix
413 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
414 const QString qtCoreImpLibPath = qtCoreDirPath
415 + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH
416 + slash + libdir
417 + slash + qtCoreImpLibFileName;
418 if (!QFileInfo::exists(qtCoreImpLibPath)) {
419 // We did not find a corresponding import library and conclude that this is a
420 // windeployqt'ed executable.
421 return exeDirPath;
422 }
423 }
424 if (!qtCoreFilePath.isEmpty())
425 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
426#else
427#error "The chosen platform / config does not support querying for a dynamic prefix."
428#endif
429
430#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
431 // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir.
432 // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0
433 // changelog regarding SSE2 support.
434 const QString libdir = QString::fromLocal8Bit(
435 ba: qt_configure_strs.viewAt(index: QLibraryInfo::LibrariesPath - 1));
436 QDir prefixDir(prefixPath);
437 while (!prefixDir.exists(name: libdir)) {
438 prefixDir.cdUp();
439 prefixPath = prefixDir.absolutePath();
440 if (prefixDir.isRoot()) {
441 prefixPath.clear();
442 break;
443 }
444 }
445#endif
446
447 Q_ASSERT_X(!prefixPath.isEmpty(), "getRelocatablePrefix",
448 "Failed to find the Qt prefix path.");
449 return prefixPath;
450}
451#endif
452
453static QString getPrefix(QLibraryInfoPrivate::UsageMode usageMode)
454{
455#if QT_CONFIG(relocatable)
456 return getRelocatablePrefix(usageMode);
457#else
458 Q_UNUSED(usageMode);
459 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
460#endif
461}
462
463QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc)
464{
465 /*
466 * To add a new entry in QLibraryInfo::LibraryPath, add it to the enum
467 * in qtbase/src/corelib/global/qlibraryinfo.h and:
468 * - add its relative path in the qtConfEntries[] array below
469 * (the key is what appears in a qt.conf file)
470 */
471 static constexpr auto qtConfEntries = qOffsetStringArray(
472 strings: "Prefix", strings: ".",
473 strings: "Documentation", strings: "doc", // should be ${Data}/doc
474 strings: "Headers", strings: "include",
475 strings: "Libraries", strings: "lib",
476#ifdef Q_OS_WIN
477 "LibraryExecutables", "bin",
478#else
479 strings: "LibraryExecutables", strings: "libexec", // should be ${ArchData}/libexec
480#endif
481 strings: "Binaries", strings: "bin",
482 strings: "Plugins", strings: "plugins", // should be ${ArchData}/plugins
483
484 strings: "QmlImports", strings: "qml", // should be ${ArchData}/qml
485
486 strings: "ArchData", strings: ".",
487 strings: "Data", strings: ".",
488 strings: "Translations", strings: "translations", // should be ${Data}/translations
489 strings: "Examples", strings: "examples",
490 strings: "Tests", strings: "tests"
491 );
492 [[maybe_unused]]
493 constexpr QByteArrayView dot{"."};
494
495 LocationInfo result;
496
497 if (int(loc) < qtConfEntries.count()) {
498 result.key = QLatin1StringView(qtConfEntries.viewAt(index: loc * 2));
499 result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(index: loc * 2 + 1));
500 if (result.key == u"QmlImports")
501 result.fallbackKey = u"Qml2Imports"_s;
502#ifndef Q_OS_WIN // On Windows we use the registry
503 } else if (loc == QLibraryInfo::SettingsPath) {
504 result.key = "Settings"_L1;
505 result.defaultValue = QLatin1StringView(dot);
506#endif
507 }
508
509 return result;
510}
511
512/*! \fn QString QLibraryInfo::location(LibraryLocation loc)
513 \deprecated [6.0] Use path() instead.
514
515 Returns the path specified by \a loc.
516*/
517
518/*!
519 \since 6.0
520 Returns the path specified by \a p.
521
522 If there is more than one path listed in qt.conf, it will
523 only return the first one.
524 \sa paths
525*/
526QString QLibraryInfo::path(LibraryPath p)
527{
528 return QLibraryInfoPrivate::path(p);
529}
530
531/*!
532 \since 6.8
533 Returns all paths specificied by \a p.
534
535 \sa path
536 */
537QStringList QLibraryInfo::paths(LibraryPath p)
538{
539 return QLibraryInfoPrivate::paths(p);
540}
541
542static bool keepQtBuildDefaults()
543{
544#if QT_CONFIG(settings)
545 QSettings *config = QLibraryInfoPrivate::configuration();
546 Q_ASSERT(config != nullptr);
547 return config->value(key: "Config/MergeQtConf", defaultValue: false).toBool();
548#else
549 return false;
550#endif
551}
552
553#if QT_CONFIG(settings)
554static QString normalizePath(QString ret)
555{
556 qsizetype startIndex = 0;
557 /* We support placeholders of the form $(<ENV_VAR>) in qt.conf.
558 The loop below tries to find all such placeholders, and replaces
559 them with the actual value of the ENV_VAR environment variable
560 */
561 while (true) {
562 startIndex = ret.indexOf(c: u'$', from: startIndex);
563 if (startIndex < 0)
564 break;
565 if (ret.size() < startIndex + 3)
566 break;
567 if (ret.at(i: startIndex + 1) != u'(') {
568 startIndex++;
569 continue;
570 }
571 qsizetype endIndex = ret.indexOf(c: u')', from: startIndex + 2);
572 if (endIndex < 0)
573 break;
574 auto envVarName = QStringView{ret}.sliced(pos: startIndex + 2, n: endIndex - startIndex - 2);
575 QString value = qEnvironmentVariable(varName: envVarName.toLocal8Bit().constData());
576 ret.replace(i: startIndex, len: endIndex - startIndex + 1, after: value);
577 startIndex += value.size();
578 }
579 return QDir::fromNativeSeparators(pathName: ret);
580};
581
582static QVariant libraryPathToValue(QLibraryInfo::LibraryPath loc)
583{
584 QVariant value;
585 auto li = QLibraryInfoPrivate::locationInfo(loc);
586 if (li.key.isNull())
587 return value;
588 QSettings *config = QLibraryInfoPrivate::configuration();
589 Q_ASSERT(config != nullptr);
590 // if keepQtBuildDefaults returns true,
591 // we only consider explicit values listed in qt.conf
592 QVariant defaultValue = keepQtBuildDefaults()
593 ? QVariant()
594 : QVariant(li.defaultValue);
595 config->beginGroup(prefix: "Paths"_L1);
596 auto cleanup = qScopeGuard(f: [&]() { config->endGroup(); });
597 if (li.fallbackKey.isNull()) {
598 value = config->value(key: li.key, defaultValue);
599 } else {
600 value = config->value(key: li.key);
601 if (!value.isValid())
602 value = config->value(key: li.fallbackKey, defaultValue);
603 }
604 return value;
605}
606#endif // settings
607
608// TODO: There apparently are paths that are both absolute and relative for QFileSystemEntry.
609// In particular on windows.
610
611static bool pathIsRelative(const QString &path)
612{
613 using FromInternalPath = QFileSystemEntry::FromInternalPath;
614 return !path.startsWith(c: ':'_L1) && QFileSystemEntry(path, FromInternalPath{}).isRelative();
615}
616
617static bool pathIsAbsolute(const QString &path)
618{
619 using FromInternalPath = QFileSystemEntry::FromInternalPath;
620 return path.startsWith(c: ':'_L1) || QFileSystemEntry(path, FromInternalPath{}).isAbsolute();
621}
622
623QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath p,
624 UsageMode usageMode)
625{
626 const QLibraryInfo::LibraryPath loc = p;
627 QList<QString> ret;
628 bool fromConf = false;
629 bool pathsAreAbsolute = true;
630#if QT_CONFIG(settings)
631 if (havePaths()) {
632 fromConf = true;
633
634 QVariant value = libraryPathToValue(loc);
635 if (value.isValid()) {
636 if (auto *asList = get_if<QList<QString>>(v: &value))
637 ret = std::move(*asList);
638 else
639 ret = QList<QString>({ std::move(value).toString()});
640 for (qsizetype i = 0, end = ret.size(); i < end; ++i) {
641 ret[i] = normalizePath(ret: ret[i]);
642 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(path: ret[i]);
643 }
644 }
645 }
646#endif // settings
647
648 if (!fromConf || keepQtBuildDefaults()) {
649 QString noConfResult;
650 if (loc == QLibraryInfo::PrefixPath) {
651 noConfResult = getPrefix(usageMode);
652 } else if (int(loc) <= qt_configure_strs.count()) {
653 noConfResult = QString::fromLocal8Bit(ba: qt_configure_strs.viewAt(index: loc - 1));
654#ifndef Q_OS_WIN // On Windows we use the registry
655 } else if (loc == QLibraryInfo::SettingsPath) {
656 // Use of volatile is a hack to discourage compilers from calling
657 // strlen(), in the inlined fromLocal8Bit(const char *)'s body, at
658 // compile-time, as Qt installers binary-patch the path, replacing
659 // the dummy path seen at compile-time, typically changing length.
660 const char *volatile path = QT_CONFIGURE_SETTINGS_PATH;
661 noConfResult = QString::fromLocal8Bit(ba: path);
662#endif
663 }
664 if (!noConfResult.isEmpty()) {
665 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(path: noConfResult);
666 ret.push_back(t: std::move(noConfResult));
667 }
668 }
669 if (ret.isEmpty() || pathsAreAbsolute)
670 return ret;
671
672 QString baseDir;
673 if (loc == QLibraryInfo::PrefixPath) {
674 baseDir = prefixFromAppDirHelper();
675 } else {
676 // we make any other path absolute to the prefix directory
677 baseDir = QLibraryInfoPrivate::path(p: QLibraryInfo::PrefixPath, usageMode);
678 }
679 for (qsizetype i = 0, end = ret.size(); i < end; ++i)
680 if (pathIsRelative(path: ret[i]))
681 ret[i] = QDir::cleanPath(path: baseDir + u'/' + std::move(ret[i]));
682 return ret;
683}
684
685/*
686 Returns the path specified by \a p.
687
688 The usage mode can be set to UsedFromQtBinDir to enable special handling for executables that
689 live in <install-prefix>/bin.
690 */
691QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMode)
692{
693 return paths(p, usageMode).value(i: 0, defaultValue: QString());
694}
695
696/*!
697 Returns additional arguments to the platform plugin matching
698 \a platformName which can be specified as a string list using
699 the key \c Arguments in a group called \c Platforms of the
700 \c qt.conf file.
701
702 sa {Using qt.conf}
703
704 \internal
705
706 \since 5.3
707*/
708
709QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
710{
711#if QT_CONFIG(settings)
712 if (const auto settings = findConfiguration()) {
713 const QString key = "Platforms/"_L1
714 + platformName
715 + "Arguments"_L1;
716 return settings->value(key).toStringList();
717 }
718#else
719 Q_UNUSED(platformName);
720#endif // settings
721 return QStringList();
722}
723
724/*!
725 \enum QLibraryInfo::LibraryPath
726
727 \keyword library location
728
729 This enum type is used to query for a specific path:
730
731 \value PrefixPath The default prefix for all paths.
732 \value DocumentationPath The path to documentation upon install.
733 \value HeadersPath The path to all headers.
734 \value LibrariesPath The path to installed libraries.
735 \value LibraryExecutablesPath The path to installed executables required by libraries at runtime.
736 \value BinariesPath The path to installed Qt binaries (tools and applications).
737 \value PluginsPath The path to installed Qt plugins.
738 \value QmlImportsPath The path to installed QML extensions to import.
739 \value Qml2ImportsPath This value is deprecated. Use QmlImportsPath instead.
740 \value ArchDataPath The path to general architecture-dependent Qt data.
741 \value DataPath The path to general architecture-independent Qt data.
742 \value TranslationsPath The path to translation information for Qt strings.
743 \value ExamplesPath The path to examples upon install.
744 \value TestsPath The path to installed Qt testcases.
745 \value SettingsPath The path to Qt settings. Not applicable on Windows.
746
747 \sa path()
748*/
749
750/*!
751 \typealias QLibraryInfo::LibraryLocation
752 \deprecated [6.0] Use LibraryPath with QLibraryInfo::path() instead.
753*/
754
755/*!
756 \headerfile <QtVersion>
757 \inmodule QtCore
758 \ingroup funclists
759 \brief Information about which Qt version the application is running on,
760 and the version it was compiled against.
761*/
762
763/*!
764 \macro QT_VERSION_STR
765 \relates <QtVersion>
766
767 This macro expands to a string that specifies Qt's version number (for
768 example, "6.1.2"). This is the version with which the application is
769 compiled. This may be a different version than the version the application
770 will find itself using at \e runtime.
771
772 \sa qVersion(), QT_VERSION
773*/
774
775/*!
776 \relates <QtVersion>
777
778 Returns the version number of Qt at runtime as a string (for example,
779 "6.1.2"). This is the version of the Qt library in use at \e runtime,
780 which need not be the version the application was \e compiled with.
781
782 \sa QT_VERSION_STR, QLibraryInfo::version()
783*/
784
785const char *qVersion() noexcept
786{
787 return QT_VERSION_STR;
788}
789
790#if QT_DEPRECATED_SINCE(6, 9)
791
792bool qSharedBuild() noexcept
793{
794 return QLibraryInfo::isSharedBuild();
795}
796
797#endif // QT_DEPRECATED_SINCE(6, 9)
798
799QT_END_NAMESPACE
800
801#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
802# include <elf.h>
803# include <stdio.h>
804# include <stdlib.h>
805
806#include "private/qcoreapplication_p.h"
807
808QT_WARNING_DISABLE_GCC("-Wformat-overflow")
809QT_WARNING_DISABLE_GCC("-Wattributes")
810QT_WARNING_DISABLE_CLANG("-Wattributes")
811QT_WARNING_DISABLE_INTEL(2621)
812
813# if defined(Q_OS_LINUX)
814# include "minimum-linux_p.h"
815# endif
816# ifdef QT_ELF_NOTE_OS_TYPE
817struct ElfNoteAbiTag
818{
819 static_assert(sizeof(Elf32_Nhdr) == sizeof(Elf64_Nhdr),
820 "The size of an ELF note is wrong (should be 12 bytes)");
821 struct Payload {
822 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
823 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
824 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
825# ifdef QT_ELF_NOTE_OS_PATCH
826 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
827# endif
828 };
829
830 Elf32_Nhdr header = {
831 .n_namesz = sizeof(name),
832 .n_descsz = sizeof(Payload),
833 .n_type = NT_GNU_ABI_TAG
834 };
835 char name[sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU; // yes, include the null terminator
836 Payload payload = {};
837};
838__attribute__((section(".note.ABI-tag"), aligned(4), used))
839extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
840# endif
841
842extern const char qt_core_interpreter[] __attribute__((section(".interp")))
843 = ELF_INTERPRETER;
844
845extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
846void qt_core_boilerplate()
847{
848 printf(format: "This is the QtCore library version %s\n"
849 "%s\n"
850 "Contact: https://www.qt.io/licensing/\n"
851 "\n"
852 "Installation prefix: %s\n"
853 "Library path: %s\n"
854 "Plugin path: %s\n",
855 QT_PREPEND_NAMESPACE(qt_build_string)(),
856 QT_COPYRIGHT,
857 QT_CONFIGURE_PREFIX_PATH,
858 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
859 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
860
861 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
862
863 exit(status: 0);
864}
865
866#endif
867

source code of qtbase/src/corelib/global/qlibraryinfo.cpp