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