Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlibraryinfo.cpp
Go to the documentation of this file.
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
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)
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("Platforms"_L1)
90 || children.contains("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>(*qtconfManualPath, QSettings::IniFormat);
107
108 QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
109 if (QResource(qtconfig, QLocale::c()).isValid())
110 return std::make_unique<QSettings>(qtconfig, 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(qtconfig))
130 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
131 qtconfig = pwd + u"/qt.conf";
132 if (QFile::exists(qtconfig))
133 return std::make_unique<QSettings>(qtconfig, 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 libraries.
161
162 This class provides an abstraction for accessing information about the
163 Qt libraries which the application is using, such as run-time paths,
164 or the build configuration of the Qt libraries.
165
166 The default run-time paths depend on the Qt build configuration, as well
167 as whether the Qt libraries have been relocated, and possibly bundled along
168 with the application.
169
170 You can use a \c qt.conf file to override the default paths,
171 in case your deployment situation does not match the defaults.
172 For more information, see the \l {Using qt.conf} documentation.
173
174 \sa QSysInfo, {Using qt.conf}
175*/
176
177/*!
178 \internal
179
180 You cannot create a QLibraryInfo, instead only the static functions are available to query
181 information.
182*/
183
184QLibraryInfo::QLibraryInfo()
185{ }
186
187#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
188# define COMPILER_STRING __VERSION__ /* already includes the compiler's name */
189#elif defined(Q_CC_GHS)
190# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
191#elif defined(Q_CC_GNU)
192# define COMPILER_STRING "GCC " __VERSION__
193#elif defined(Q_CC_MSVC)
194# if _MSC_VER < 1910
195# define COMPILER_STRING "MSVC 2015"
196# elif _MSC_VER < 1917
197# define COMPILER_STRING "MSVC 2017"
198# elif _MSC_VER < 1930
199# define COMPILER_STRING "MSVC 2019"
200# elif _MSC_VER < 1950
201# define COMPILER_STRING "MSVC 2022"
202# elif _MSC_VER < 2000
203# define COMPILER_STRING "MSVC 2026"
204# else
205# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
206# endif
207#else
208# define COMPILER_STRING "<unknown compiler>"
209#endif
210#ifdef QT_NO_DEBUG
211# define DEBUG_STRING " release"
212#else
213# define DEBUG_STRING " debug"
214#endif
215#ifdef QT_SHARED
216# define SHARED_STRING " shared (dynamic)"
217#else
218# define SHARED_STRING " static"
219#endif
220static const char *qt_build_string() noexcept
221{
222 return "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")";
223}
224
225/*!
226 Returns a string describing how this version of Qt was built.
227
228 \internal
229
230 \since 5.3
231*/
232
233const char *QLibraryInfo::build() noexcept
234{
235 return qt_build_string();
236}
237
238/*!
239 \since 5.0
240 Returns \c true if this build of Qt was built with debugging enabled, or
241 false if it was built in release mode.
242*/
243bool
244QLibraryInfo::isDebugBuild() noexcept
245{
246#ifdef QT_DEBUG
247 return true;
248#else
249 return false;
250#endif
251}
252
253/*!
254 \since 6.5
255 Returns \c true if this is a shared (dynamic) build of Qt.
256*/
257bool QLibraryInfo::isSharedBuild() noexcept
258{
259#ifdef QT_SHARED
260 return true;
261#else
262 return false;
263#endif
264}
265
266/*!
267 \since 5.8
268 Returns the version of the Qt library.
269
270 \sa qVersion()
271*/
272QVersionNumber QLibraryInfo::version() noexcept
273{
274 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
275}
276
277/*!
278 \internal
279
280 Used to look up the prefix path for static builds, where we
281 don't have a standalone QtCore library, or for relative paths
282 coming from qt.conf, which are rooted in the app's location.
283*/
285{
286#if defined(Q_OS_DARWIN)
287 // Resolve the app prefix from the app bundle instead of the
288 // executable, as that correctly handles both the main executable
289 // as well as possibly deeply nested helper tools, and lets us
290 // root the app prefix at the base of the bundle. Note that
291 // CFBundleGetMainBundle returns a bundle representation even
292 // for unbundled apps, which is why we can't assume there's a
293 // `Contents` subdirectory in the macOS case.
294 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
295 if (QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef)) {
296 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
297#if defined(Q_OS_MACOS)
298 QString bundleContentsDir = QString(path) + "/Contents/"_L1;
299 if (QFileInfo::exists(bundleContentsDir))
300 return QDir::cleanPath(bundleContentsDir);
301#else
302 return QDir::cleanPath(QString(path)); // iOS
303#endif // Q_OS_MACOS
304 }
305 }
306#endif // Q_OS_DARWIN
307
308 if (QCoreApplication::instanceExists()) {
309 // We make the prefix path absolute to the executable's directory.
310 return QCoreApplication::applicationDirPath();
311 } else {
312 return QDir::currentPath();
313 }
314}
315
316#if QT_CONFIG(relocatable)
317#if !defined(QT_STATIC) && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
318static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
319{
320 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
321 QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
322
323#if QT_CONFIG(framework)
324# if defined(Q_OS_MACOS)
325 // The library in a macOS framework lives in a `Versions/A/` subdirectory
326 libDir += "/../.."_L1;
327# endif
328 // And both macOS and iOS frameworks are `.framework` bundle directories
329 libDir += "/.."_L1;
330#endif
331
332 const QString prefixDir = libDir + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
333 return QDir::cleanPath(prefixDir);
334}
335#endif
336
337#if defined(Q_OS_WIN)
338static HMODULE getWindowsModuleHandle()
339{
340 HMODULE hModule = NULL;
341 GetModuleHandleEx(
342 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
343 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
344 return hModule;
345}
346#endif // Q_OS_WIN
347
348static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
349{
350 QString prefixPath;
351
352 // For static builds, the prefix will be the app directory, unless it's a non-sandboxed Apple app.
353 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
354#if defined(QT_STATIC)
355# if defined(Q_OS_APPLE)
356 // The default value for QT_CONFIG(relocatable) for static builds
357 // used to be false, giving end users QT_CONFIGURE_PREFIX_PATH as
358 // the prefix path. We've since changed the default to true for
359 // Apple platforms, since sandboxed applications are always
360 // relocated, even for static builds. To avoid regressions for
361 // those that shipped non-sandboxed apps with static Qt relying
362 // on the previous behavior, we fall back to the Qt configure
363 // prefix for non-sandboxed apps.
364 if (!qt_apple_isSandboxed())
365 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
366# endif
367 prefixPath = prefixFromAppDirHelper();
368 if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) {
369 // For Qt tools in a static build, we must chop off the bin directory.
370 constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1);
371 constexpr size_t binDirLength = binDir.size() + 1;
372 prefixPath.chop(binDirLength);
373 }
374#elif defined(Q_OS_WASM)
375 // Emscripten expects to find shared libraries at the root of the in-memory
376 // file system when resolving dependencies for for dlopen() calls. So that's
377 // where libqt6core.so would be.
378 prefixPath = QStringLiteral("/");
379#elif QT_CONFIG(dlopen)
380 Q_UNUSED(usageMode);
381 Dl_info info;
382 int result = dladdr(reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), &info);
383 if (result > 0 && info.dli_fname)
384 prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(info.dli_fname));
385#elif defined(Q_OS_WIN)
386 Q_UNUSED(usageMode);
387 HMODULE hModule = getWindowsModuleHandle();
388 const int kBufferSize = 4096;
389 wchar_t buffer[kBufferSize];
390 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
391 const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize));
392 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
393
394 hModule = reinterpret_cast<HMODULE>(QCoreApplicationPrivate::mainInstanceHandle);
395 pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
396 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath();
397 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
398 // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an
399 // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking
400 // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib.
401 const QString libdir = QString::fromLocal8Bit(
402 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
403 const QLatin1Char slash('/');
404#if defined(Q_CC_MINGW)
405 const QString implibPrefix = QStringLiteral("lib");
406 const QString implibSuffix = QStringLiteral(".a");
407#else
408 const QString implibPrefix;
409 const QString implibSuffix = QStringLiteral(".lib");
410#endif
411 const QString qtCoreImpLibFileName = implibPrefix
412 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
413 const QString qtCoreImpLibPath = qtCoreDirPath
414 + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH
415 + slash + libdir
416 + slash + qtCoreImpLibFileName;
417 if (!QFileInfo::exists(qtCoreImpLibPath)) {
418 // We did not find a corresponding import library and conclude that this is a
419 // windeployqt'ed executable.
420 return exeDirPath;
421 }
422 }
423 if (!qtCoreFilePath.isEmpty())
424 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
425#else
426#error "The chosen platform / config does not support querying for a dynamic prefix."
427#endif
428
429#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
430 // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir.
431 // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0
432 // changelog regarding SSE2 support.
433 const QString libdir = QString::fromLocal8Bit(
434 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
435 QDir prefixDir(prefixPath);
436 while (!prefixDir.exists(libdir)) {
437 prefixDir.cdUp();
438 prefixPath = prefixDir.absolutePath();
439 if (prefixDir.isRoot()) {
440 prefixPath.clear();
441 break;
442 }
443 }
444#endif
445
446 Q_ASSERT_X(!prefixPath.isEmpty(), "getRelocatablePrefix",
447 "Failed to find the Qt prefix path.");
448 return prefixPath;
449}
450#endif
451
452static QString getPrefix(QLibraryInfoPrivate::UsageMode usageMode)
453{
454#if QT_CONFIG(relocatable)
455 return getRelocatablePrefix(usageMode);
456#else
457 Q_UNUSED(usageMode);
458 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
459#endif
460}
461
462QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc)
463{
464 /*
465 * To add a new entry in QLibraryInfo::LibraryPath, add it to the enum
466 * in qtbase/src/corelib/global/qlibraryinfo.h and:
467 * - add its relative path in the qtConfEntries[] array below
468 * (the key is what appears in a qt.conf file)
469 */
470 static constexpr auto qtConfEntries = qOffsetStringArray(
471 "Prefix", ".",
472 "Documentation", "doc", // should be ${Data}/doc
473 "Headers", "include",
474 "Libraries", "lib",
475#ifdef Q_OS_WIN
476 "LibraryExecutables", "bin",
477#else
478 "LibraryExecutables", "libexec", // should be ${ArchData}/libexec
479#endif
480 "Binaries", "bin",
481 "Plugins", "plugins", // should be ${ArchData}/plugins
482
483 "QmlImports", "qml", // should be ${ArchData}/qml
484
485 "ArchData", ".",
486 "Data", ".",
487 "Translations", "translations", // should be ${Data}/translations
488 "Examples", "examples",
489 "Tests", "tests"
490 );
491 [[maybe_unused]]
492 constexpr QByteArrayView dot{"."};
493
494 LocationInfo result;
495
496 if (int(loc) < qtConfEntries.count()) {
497 result.key = QLatin1StringView(qtConfEntries.viewAt(loc * 2));
498 result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(loc * 2 + 1));
499 if (result.key == u"QmlImports")
500 result.fallbackKey = u"Qml2Imports"_s;
501#ifndef Q_OS_WIN // On Windows we use the registry
502 } else if (loc == QLibraryInfo::SettingsPath) {
503 result.key = "Settings"_L1;
504 result.defaultValue = QLatin1StringView(dot);
505#endif
506 }
507
508 return result;
509}
510
511/*! \fn QString QLibraryInfo::location(LibraryLocation loc)
512 \deprecated [6.0] Use path() instead.
513
514 Returns the path specified by \a loc.
515*/
516
517/*!
518 \since 6.0
519 Returns the path specified by \a p.
520
521 If there is more than one path listed in qt.conf, it will
522 only return the first one.
523 \sa paths
524*/
525QString QLibraryInfo::path(LibraryPath p)
526{
527 return QLibraryInfoPrivate::path(p);
528}
529
530/*!
531 \since 6.8
532 Returns all paths specificied by \a p.
533
534 \sa path
535 */
536QStringList QLibraryInfo::paths(LibraryPath p)
537{
538 return QLibraryInfoPrivate::paths(p);
539}
540
542{
543#if QT_CONFIG(settings)
544 QSettings *config = QLibraryInfoPrivate::configuration();
545 Q_ASSERT(config != nullptr);
546 return config->value("Config/MergeQtConf", false).toBool();
547#else
548 return false;
549#endif
550}
551
552#if QT_CONFIG(settings)
553static QString normalizePath(QString ret)
554{
555 qsizetype startIndex = 0;
556 /* We support placeholders of the form $(<ENV_VAR>) in qt.conf.
557 The loop below tries to find all such placeholders, and replaces
558 them with the actual value of the ENV_VAR environment variable
559 */
560 while (true) {
561 startIndex = ret.indexOf(u'$', startIndex);
562 if (startIndex < 0)
563 break;
564 if (ret.size() < startIndex + 3)
565 break;
566 if (ret.at(startIndex + 1) != u'(') {
567 startIndex++;
568 continue;
569 }
570 qsizetype endIndex = ret.indexOf(u')', startIndex + 2);
571 if (endIndex < 0)
572 break;
573 auto envVarName = QStringView{ret}.sliced(startIndex + 2, endIndex - startIndex - 2);
574 QString value = qEnvironmentVariable(envVarName.toLocal8Bit().constData());
575 ret.replace(startIndex, endIndex - startIndex + 1, value);
576 startIndex += value.size();
577 }
578 return QDir::fromNativeSeparators(ret);
579};
580
581static QVariant libraryPathToValue(QLibraryInfo::LibraryPath loc)
582{
583 QVariant value;
584 auto li = QLibraryInfoPrivate::locationInfo(loc);
585 if (li.key.isNull())
586 return value;
587 QSettings *config = QLibraryInfoPrivate::configuration();
588 Q_ASSERT(config != nullptr);
589 // if keepQtBuildDefaults returns true,
590 // we only consider explicit values listed in qt.conf
591 QVariant defaultValue = keepQtBuildDefaults()
592 ? QVariant()
593 : QVariant(li.defaultValue);
594 config->beginGroup("Paths"_L1);
595 auto cleanup = qScopeGuard([&]() { config->endGroup(); });
596 if (li.fallbackKey.isNull()) {
597 value = config->value(li.key, defaultValue);
598 } else {
599 value = config->value(li.key);
600 if (!value.isValid())
601 value = config->value(li.fallbackKey, defaultValue);
602 }
603 return value;
604}
605#endif // settings
606
607// TODO: There apparently are paths that are both absolute and relative for QFileSystemEntry.
608// In particular on windows.
609
610static bool pathIsRelative(const QString &path)
611{
612 using FromInternalPath = QFileSystemEntry::FromInternalPath;
613 return !path.startsWith(':'_L1) && QFileSystemEntry(path, FromInternalPath{}).isRelative();
614}
615
616static bool pathIsAbsolute(const QString &path)
617{
618 using FromInternalPath = QFileSystemEntry::FromInternalPath;
619 return path.startsWith(':'_L1) || QFileSystemEntry(path, FromInternalPath{}).isAbsolute();
620}
621
622QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath p,
623 UsageMode usageMode)
624{
625 const QLibraryInfo::LibraryPath loc = p;
626 QList<QString> ret;
627 bool fromConf = false;
628 bool pathsAreAbsolute = true;
629#if QT_CONFIG(settings)
630 if (havePaths()) {
631 fromConf = true;
632
633 QVariant value = libraryPathToValue(loc);
634 if (value.isValid()) {
635 if (auto *asList = get_if<QList<QString>>(&value))
636 ret = std::move(*asList);
637 else
638 ret = QList<QString>({ std::move(value).toString()});
639 for (qsizetype i = 0, end = ret.size(); i < end; ++i) {
640 ret[i] = normalizePath(ret[i]);
641 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(ret[i]);
642 }
643 }
644 }
645#endif // settings
646
647 if (!fromConf || keepQtBuildDefaults()) {
648 QString noConfResult;
649 if (loc == QLibraryInfo::PrefixPath) {
650 noConfResult = getPrefix(usageMode);
651 } else if (int(loc) <= qt_configure_strs.count()) {
652 noConfResult = QString::fromLocal8Bit(qt_configure_strs.viewAt(loc - 1));
653#ifndef Q_OS_WIN // On Windows we use the registry
654 } else if (loc == QLibraryInfo::SettingsPath) {
655 // Use of volatile is a hack to discourage compilers from calling
656 // strlen(), in the inlined fromLocal8Bit(const char *)'s body, at
657 // compile-time, as Qt installers binary-patch the path, replacing
658 // the dummy path seen at compile-time, typically changing length.
659 const char *volatile path = QT_CONFIGURE_SETTINGS_PATH;
660 noConfResult = QString::fromLocal8Bit(path);
661#endif
662 }
663 if (!noConfResult.isEmpty()) {
664 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(noConfResult);
665 ret.push_back(std::move(noConfResult));
666 }
667 }
668 if (ret.isEmpty() || pathsAreAbsolute)
669 return ret;
670
671 QString baseDir;
672 if (loc == QLibraryInfo::PrefixPath) {
673 baseDir = prefixFromAppDirHelper();
674 } else {
675 // we make any other path absolute to the prefix directory
676 baseDir = QLibraryInfoPrivate::path(QLibraryInfo::PrefixPath, usageMode);
677 }
678 for (qsizetype i = 0, end = ret.size(); i < end; ++i)
679 if (pathIsRelative(ret[i]))
680 ret[i] = QDir::cleanPath(baseDir + u'/' + std::move(ret[i]));
681 return ret;
682}
683
684/*
685 Returns the path specified by \a p.
686
687 The usage mode can be set to UsedFromQtBinDir to enable special handling for executables that
688 live in <install-prefix>/bin.
689 */
690QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMode)
691{
692 return paths(p, usageMode).value(0, QString());
693}
694
695/*!
696 Returns additional arguments to the platform plugin matching
697 \a platformName which can be specified as a string list using
698 the key \c Arguments in a group called \c Platforms of the
699 \c qt.conf file.
700
701 sa {Using qt.conf}
702
703 \internal
704
705 \since 5.3
706*/
707
708QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
709{
710#if QT_CONFIG(settings)
711 if (const auto settings = findConfiguration()) {
712 const QString key = "Platforms/"_L1
713 + platformName
714 + "Arguments"_L1;
715 return settings->value(key).toStringList();
716 }
717#else
718 Q_UNUSED(platformName);
719#endif // settings
720 return QStringList();
721}
722
723/*!
724 \enum QLibraryInfo::LibraryPath
725
726 \keyword library location
727
728 This enum type is used to query for a specific path:
729
730 \value PrefixPath The default prefix for all paths.
731 \value DocumentationPath The path to documentation upon install.
732 \value HeadersPath The path to all headers.
733 \value LibrariesPath The path to installed libraries.
734 \value LibraryExecutablesPath The path to installed executables required by libraries at runtime.
735 \value BinariesPath The path to installed Qt binaries (tools and applications).
736 \value PluginsPath The path to installed Qt plugins.
737 \value QmlImportsPath The path to installed QML extensions to import.
738 \value Qml2ImportsPath This value is deprecated. Use QmlImportsPath instead.
739 \value ArchDataPath The path to general architecture-dependent Qt data.
740 \value DataPath The path to general architecture-independent Qt data.
741 \value TranslationsPath The path to translation information for Qt strings.
742 \value ExamplesPath The path to examples upon install.
743 \value TestsPath The path to installed Qt testcases.
744 \value SettingsPath The path to Qt settings. Not applicable on Windows.
745
746 \sa path()
747*/
748
749/*!
750 \typealias QLibraryInfo::LibraryLocation
751 \deprecated [6.0] Use LibraryPath with QLibraryInfo::path() instead.
752*/
753
754/*!
755 \headerfile <QtVersion>
756 \inmodule QtCore
757 \ingroup funclists
758 \brief Information about which Qt version the application is running on,
759 and the version it was compiled against.
760*/
761
762/*!
763 \macro QT_VERSION_STR
764 \relates <QtVersion>
765
766 This macro expands to a string that specifies Qt's version number (for
767 example, "6.1.2"). This is the version with which the application is
768 compiled. This may be a different version than the version the application
769 will find itself using at \e runtime.
770
771 \sa qVersion(), QT_VERSION
772*/
773
774/*!
775 \relates <QtVersion>
776
777 Returns the version number of Qt at runtime as a string (for example,
778 "6.1.2"). This is the version of the Qt library in use at \e runtime,
779 which need not be the version the application was \e compiled with.
780
781 \sa QT_VERSION_STR, QLibraryInfo::version()
782*/
783
784const char *qVersion() noexcept
785{
786 return QT_VERSION_STR;
787}
788
789#if QT_DEPRECATED_SINCE(6, 9)
790
791bool qSharedBuild() noexcept
792{
793 return QLibraryInfo::isSharedBuild();
794}
795
796#endif // QT_DEPRECATED_SINCE(6, 9)
797
798QT_END_NAMESPACE
799
800#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
801# include <elf.h>
802# include <stdio.h>
803# include <stdlib.h>
804
805#include "private/qcoreapplication_p.h"
806
807QT_WARNING_DISABLE_GCC("-Wformat-overflow")
808QT_WARNING_DISABLE_GCC("-Wattributes")
809QT_WARNING_DISABLE_CLANG("-Wattributes")
810QT_WARNING_DISABLE_INTEL(2621)
811
812# if defined(Q_OS_LINUX)
813# include "minimum-linux_p.h"
814# endif
815# ifdef QT_ELF_NOTE_OS_TYPE
816struct ElfNoteAbiTag
817{
818 static_assert(sizeof(Elf32_Nhdr) == sizeof(Elf64_Nhdr),
819 "The size of an ELF note is wrong (should be 12 bytes)");
820 struct Payload {
821 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
822 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
823 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
824# ifdef QT_ELF_NOTE_OS_PATCH
825 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
826# endif
827 };
828
829 Elf32_Nhdr header = {
830 .n_namesz = sizeof(name),
831 .n_descsz = sizeof(Payload),
832 .n_type = NT_GNU_ABI_TAG
833 };
834 char name[sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU; // yes, include the null terminator
835 Payload payload = {};
836};
837__attribute__((section(".note.ABI-tag"), aligned(4), used))
838extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
839# endif
840
841extern const char qt_core_interpreter[] __attribute__((section(".interp")))
842 = ELF_INTERPRETER;
843
844extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
845void qt_core_boilerplate()
846{
847 printf("This is the QtCore library version %s\n"
848 "%s\n"
849 "Contact: https://www.qt.io/licensing/\n"
850 "\n"
851 "Installation prefix: %s\n"
852 "Library path: %s\n"
853 "Plugin path: %s\n",
854 QT_PREPEND_NAMESPACE(qt_build_string)(),
855 QT_COPYRIGHT,
856 QT_CONFIGURE_PREFIX_PATH,
857 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
858 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
859
860 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
861
862 exit(0);
863}
864
865#endif
#define ARCH_FULL
static const char * qt_build_string() noexcept
static bool pathIsRelative(const QString &path)
static QString getPrefix(QLibraryInfoPrivate::UsageMode usageMode)
void qDumpCPUFeatures()
Definition qsimd.cpp:683
static bool pathIsAbsolute(const QString &path)
static QString prefixFromAppDirHelper()
#define SHARED_STRING
static bool keepQtBuildDefaults()
#define COMPILER_STRING
#define DEBUG_STRING