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
43static QString fromRawStringView(QStringView string)
44{
45 return QString::fromRawData(string.data(), string.size());
46}
47
48static bool pathIsRelative(const QString &path)
49{
50 using FromInternalPath = QFileSystemEntry::FromInternalPath;
51 return !path.startsWith(':'_L1) && QFileSystemEntry(path, FromInternalPath{}).isRelative();
52}
53
54// Resolves and caches the Qt and application prefix roots. Resolution
55// may be costly and is queried repeatedly during startup, so results
56// are memoized. Wrapped in a Q_GLOBAL_STATIC (prefixCache) so lookups
57// during static destruction fall back to resolving from scratch.
59{
60 static QString qtPrefix();
62
63private:
64 // Pure resolvers, without caching, so they're usable even without a
65 // cache instance during static destruction. resolveAppPrefix() returns an
66 // empty string when no stable source is available yet; appPrefix()
67 // then falls back to the (uncached) working directory.
68 static QString resolveQtPrefix();
69 static QString resolveAppPrefix();
70
71 // The directory the application prefix is rooted at: the app bundle on
72 // Apple platforms, or the application directory once a QCoreApplication
73 // exists. Empty when no stable source is available yet.
74 static QString resolveAppDir();
75
76 // The qt.conf "Prefix" entry the application prefix is rooted at,
77 // or its "." default when there's no qt.conf (or settings) to read.
78 static QString qtConfPrefix();
79
80 // Memoizes resolve() in the given member. A resolver may return an
81 // empty string to signal that the result is not yet stable and should
82 // not be cached, in which case it is resolved anew on each call. During
83 // static destruction prefixCache() returns nullptr and resolve() is
84 // used directly.
85 static QString cached(QString QLibraryPrefixes::*member, QString (*resolve)());
86
87 QString m_qt;
88 QString m_app;
89};
90Q_GLOBAL_STATIC(QLibraryPrefixes, prefixCache)
91
92QString QLibraryPrefixes::cached(QString QLibraryPrefixes::*member, QString (*resolve)())
93{
94 QLibraryPrefixes *cache = prefixCache();
95 if (cache && !(cache->*member).isEmpty())
96 return cache->*member;
97 QString prefix = resolve();
98 if (cache && !prefix.isEmpty())
99 cache->*member = prefix;
100 return prefix;
101}
102
103#if QT_CONFIG(settings)
104
105static std::unique_ptr<QSettings> findConfiguration();
106
107struct QLibrarySettings
108{
109 QLibrarySettings();
110 void load();
111 bool havePaths();
112 QSettings *configuration();
113 QVariant value(QLibraryInfo::LibraryPath path);
114 QList<QString> paths(QLibraryInfo::LibraryPath location);
115
116 std::unique_ptr<QSettings> settings;
117 bool configHasPaths;
118 bool reloadOnQAppAvailable;
119};
120Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
121
122QLibrarySettings::QLibrarySettings() : configHasPaths(false), reloadOnQAppAvailable(false)
123{
124 load();
125}
126
127QSettings *QLibrarySettings::configuration()
128{
129 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
130 load();
131 return settings.get();
132}
133
134bool QLibrarySettings::havePaths()
135{
136 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
137 load();
138 return configHasPaths;
139}
140
141void QLibrarySettings::load()
142{
143 // If we get any settings here, those won't change when the application shows up.
144 settings = findConfiguration();
145 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
146
147 if (settings) {
148 // This code needs to be in the regular library, as otherwise a qt.conf that
149 // works for qmake would break things for dynamically built Qt tools.
150 QStringList children = settings->childGroups();
151 configHasPaths = !children.contains("Platforms"_L1)
152 || children.contains("Paths"_L1);
153 } else {
154 configHasPaths = false;
155 }
156}
157
158/*!
159 Returns the value for a given \a path from \c qt.conf
160
161 If no \c qt.conf is found, or the configuration doesn't
162 specify a value for the given \a path a null-variant is
163 returned.
164
165 \internal
166*/
167QVariant QLibrarySettings::value(QLibraryInfo::LibraryPath path)
168{
169 const auto locationInfo = QLibraryInfoPrivate::locationInfo(path);
170 if (locationInfo.key.isNull())
171 return {};
172
173 QSettings *config = configuration();
174 if (!settings || !configHasPaths)
175 return {};
176
177 config->beginGroup("Paths"_L1);
178 auto cleanup = qScopeGuard([&]() { config->endGroup(); });
179 QVariant value = config->value(locationInfo.key);
180 if (!value.isValid() && !locationInfo.fallbackKey.isNull())
181 value = config->value(locationInfo.fallbackKey);
182 return value;
183}
184
185QList<QString> QLibrarySettings::paths(QLibraryInfo::LibraryPath location)
186{
187 QList<QString> ret;
188 if (QVariant v = value(location); v.isValid()) {
189 if (auto *asList = get_if<QList<QString>>(&v))
190 ret = std::move(*asList);
191 else
192 ret << v.toString();
193
194 for (qsizetype i = 0, end = ret.size(); i < end; ++i)
195 ret[i] = QLibraryInfoPrivate::expandEnvVariables(ret[i]);
196 }
197 return ret;
198}
199
200namespace {
201const QString *qtconfManualPath = nullptr;
202}
203
204void QLibraryInfoPrivate::setQtconfManualPath(const QString *path)
205{
206 qtconfManualPath = path;
207}
208
209static std::unique_ptr<QSettings> findConfiguration()
210{
211 if (qtconfManualPath)
212 return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
213
214 QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
215 if (QResource(qtconfig, QLocale::c()).isValid())
216 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
217#ifdef Q_OS_DARWIN
218 CFBundleRef bundleRef = CFBundleGetMainBundle();
219 if (bundleRef) {
220 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
221 QCFString("qt.conf"_L1),
222 0,
223 0);
224 if (urlRef) {
225 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
226 qtconfig = QDir::cleanPath(path);
227 if (QFile::exists(qtconfig))
228 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
229 }
230 }
231#endif
232 if (QCoreApplication::instanceExists()) {
233 QString pwd = QCoreApplication::applicationDirPath();
234 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR) ".conf"_s;
235 if (QFile::exists(qtconfig))
236 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
237 qtconfig = pwd + u"/qt.conf";
238 if (QFile::exists(qtconfig))
239 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
240 }
241 return nullptr; //no luck
242}
243
244QSettings *QLibraryInfoPrivate::configuration()
245{
246 QLibrarySettings *ls = qt_library_settings();
247 return ls ? ls->configuration() : nullptr;
248}
249#endif // settings
250
251void QLibraryInfoPrivate::reload()
252{
253#if QT_CONFIG(settings)
254 if (qt_library_settings.exists())
255 qt_library_settings->load();
256#endif
257 if (prefixCache.exists())
258 *prefixCache = {};
259}
260
261/*!
262 \class QLibraryInfo
263 \inmodule QtCore
264 \brief The QLibraryInfo class provides information about the Qt libraries.
265
266 This class provides an abstraction for accessing information about the
267 Qt libraries which the application is using, such as run-time paths,
268 or the build configuration of the Qt libraries.
269
270 The default run-time paths depend on the Qt build configuration, as well
271 as whether the Qt libraries have been relocated, and possibly bundled along
272 with the application.
273
274 You can use a \c qt.conf file to override the default paths,
275 in case your deployment situation does not match the defaults.
276 For more information, see the \l {Using qt.conf} documentation.
277
278 \sa QSysInfo, {Using qt.conf}
279*/
280
281/*!
282 \internal
283
284 You cannot create a QLibraryInfo, instead only the static functions are available to query
285 information.
286*/
287
288QLibraryInfo::QLibraryInfo()
289{ }
290
291#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
292# define COMPILER_STRING __VERSION__ /* already includes the compiler's name */
293#elif defined(Q_CC_GHS)
294# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
295#elif defined(Q_CC_GNU)
296# define COMPILER_STRING "GCC " __VERSION__
297#elif defined(Q_CC_MSVC)
298# if _MSC_VER < 1910
299# define COMPILER_STRING "MSVC 2015"
300# elif _MSC_VER < 1917
301# define COMPILER_STRING "MSVC 2017"
302# elif _MSC_VER < 1930
303# define COMPILER_STRING "MSVC 2019"
304# elif _MSC_VER < 1950
305# define COMPILER_STRING "MSVC 2022"
306# elif _MSC_VER < 2000
307# define COMPILER_STRING "MSVC 2026"
308# else
309# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
310# endif
311#else
312# define COMPILER_STRING "<unknown compiler>"
313#endif
314#ifdef QT_NO_DEBUG
315# define DEBUG_STRING " release"
316#else
317# define DEBUG_STRING " debug"
318#endif
319#ifdef QT_SHARED
320# define SHARED_STRING " shared (dynamic)"
321#else
322# define SHARED_STRING " static"
323#endif
324static const char *qt_build_string() noexcept
325{
326 return "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")";
327}
328
329/*!
330 Returns a string describing how this version of Qt was built.
331
332 \internal
333
334 \since 5.3
335*/
336
337const char *QLibraryInfo::build() noexcept
338{
339 return qt_build_string();
340}
341
342/*!
343 \since 5.0
344 Returns \c true if this build of Qt was built with debugging enabled, or
345 false if it was built in release mode.
346*/
347bool
348QLibraryInfo::isDebugBuild() noexcept
349{
350#ifdef QT_DEBUG
351 return true;
352#else
353 return false;
354#endif
355}
356
357/*!
358 \since 6.5
359 Returns \c true if this is a shared (dynamic) build of Qt.
360*/
361bool QLibraryInfo::isSharedBuild() noexcept
362{
363#ifdef QT_SHARED
364 return true;
365#else
366 return false;
367#endif
368}
369
370/*!
371 \since 5.8
372 Returns the version of the Qt library.
373
374 \sa qVersion()
375*/
376QVersionNumber QLibraryInfo::version() noexcept
377{
378 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
379}
380
381/*!
382 \internal
383
384 Returns the qt.conf "Prefix" entry the application prefix is rooted at,
385 falling back to its "." default when there's no qt.conf with paths (or
386 settings support), so the prefix then resolves to the application directory.
387*/
388QString QLibraryPrefixes::qtConfPrefix()
389{
390#if QT_CONFIG(settings)
391 QLibrarySettings *settings = qt_library_settings();
392 if (settings && settings->havePaths()) {
393 const QString prefix = settings->paths(QLibraryInfo::PrefixPath).value(0);
394 if (!prefix.isEmpty())
395 return prefix;
396 }
397#endif
398 return u"."_s;
399}
400
401/*!
402 \internal
403
404 The directory the application prefix is rooted at: the app bundle on
405 Apple platforms, or the application directory once a QCoreApplication
406 exists. Returns an empty string when no stable source is available yet.
407*/
408QString QLibraryPrefixes::resolveAppDir()
409{
410#if defined(Q_OS_DARWIN)
411 // Resolve the app prefix from the app bundle instead of the
412 // executable, as that correctly handles both the main executable
413 // as well as possibly deeply nested helper tools, and lets us
414 // root the app prefix at the base of the bundle. Note that
415 // CFBundleGetMainBundle returns a bundle representation even
416 // for unbundled apps, so we verify the URL is actually a bundle.
417 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
418 if (QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef)) {
419 const QString bundlePath = QCFString(CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle));
420 if (qt_apple_bundleType(bundlePath)) {
421#if defined(Q_OS_MACOS)
422 // On macOS the prefix is rooted at the bundle's Contents directory.
423 return QFileInfo(bundlePath + "/Contents"_L1).canonicalFilePath();
424#else
425 return QFileInfo(bundlePath).canonicalFilePath(); // iOS
426#endif // Q_OS_MACOS
427 }
428 }
429 }
430#endif // Q_OS_DARWIN
431
432 if (QCoreApplication::instanceExists()) {
433 // We make the prefix path absolute to the executable's directory.
434 return QCoreApplication::applicationDirPath();
435 }
436
437 // Without an application instance there's no stable source; return an
438 // empty string so the result isn't cached, and let appPrefix() fall back
439 // to the (volatile) working directory until a stable source is available.
440 return {};
441}
442
443/*!
444 \internal
445
446 The fully resolved application prefix: the qt.conf "Prefix" entry
447 (explicit, or the "." default) rooted at the application directory.
448 An absolute Prefix is used as-is, independent of the application
449 directory. Without a qt.conf the prefix is the application directory
450 itself, which is also what static builds use as their Qt prefix.
451
452 Returns an empty string when the result would depend on a not-yet-stable
453 application directory, so it isn't cached; appPrefix() then roots the
454 prefix at the (volatile) working directory until a stable source exists.
455*/
456QString QLibraryPrefixes::resolveAppPrefix()
457{
458 const QString prefix = qtConfPrefix();
459 // An absolute qt.conf Prefix is stable on its own, regardless of appDir.
460 if (!pathIsRelative(prefix))
461 return prefix;
462 const QString appDir = resolveAppDir();
463 if (appDir.isEmpty())
464 return {};
465 return QDir::cleanPath(appDir + u'/' + prefix);
466}
467
468QString QLibraryPrefixes::appPrefix()
469{
470 QString prefix = cached(&QLibraryPrefixes::m_app, &QLibraryPrefixes::resolveAppPrefix);
471 if (!prefix.isNull())
472 return prefix;
473
474 // No stable source yet; root the possible qt.conf Prefix at the volatile
475 // working directory, without caching, until one is available.
476 return QDir::cleanPath(QDir::currentPath() + u'/' + qtConfPrefix());
477}
478
479#if QT_CONFIG(relocatable)
480#if !defined(QT_STATIC) && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
481static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
482{
483 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
484 QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
485
486#if QT_CONFIG(framework)
487# if defined(Q_OS_MACOS)
488 // The library in a macOS framework lives in a `Versions/A/` subdirectory
489 libDir += "/../.."_L1;
490# endif
491 // And both macOS and iOS frameworks are `.framework` bundle directories
492 libDir += "/.."_L1;
493#endif
494
495 const QString prefixDir = libDir + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
496 return QDir::cleanPath(prefixDir);
497}
498#endif
499
500#if defined(Q_OS_WIN)
501static HMODULE getWindowsModuleHandle()
502{
503 HMODULE hModule = NULL;
504 GetModuleHandleEx(
505 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
506 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
507 return hModule;
508}
509#endif // Q_OS_WIN
510
511static QString relocatablePrefixFromQt()
512{
513 QString prefixPath;
514
515 // For static builds, the prefix will be the app directory, unless it's a non-sandboxed Apple app.
516 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
517#if defined(QT_STATIC)
518# if defined(Q_OS_APPLE)
519 // The default value for QT_CONFIG(relocatable) for static builds
520 // used to be false, giving end users QT_CONFIGURE_PREFIX_PATH as
521 // the prefix path. We've since changed the default to true for
522 // Apple platforms, since sandboxed applications are always
523 // relocated, even for static builds. To avoid regressions for
524 // those that shipped non-sandboxed apps with static Qt relying
525 // on the previous behavior, we fall back to the Qt configure
526 // prefix for non-sandboxed apps.
527 if (!qt_apple_isSandboxed())
528 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
529# endif
530 prefixPath = QLibraryPrefixes::appPrefix();
531#elif defined(Q_OS_WASM)
532 // Emscripten expects to find shared libraries at the root of the in-memory
533 // file system when resolving dependencies for for dlopen() calls. So that's
534 // where libqt6core.so would be.
535 prefixPath = QStringLiteral("/");
536#elif QT_CONFIG(dlopen)
537 Dl_info info;
538 int result = dladdr(reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), &info);
539 if (result > 0 && info.dli_fname)
540 prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(info.dli_fname));
541#elif defined(Q_OS_WIN)
542 HMODULE hModule = getWindowsModuleHandle();
543 const int kBufferSize = 4096;
544 wchar_t buffer[kBufferSize];
545 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
546 const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize));
547 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
548
549 hModule = reinterpret_cast<HMODULE>(QCoreApplicationPrivate::mainInstanceHandle);
550 pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
551 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath();
552 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
553 // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an
554 // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking
555 // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib.
556 QStringView libdir = qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1);
557 const QLatin1Char slash('/');
558#if defined(Q_CC_MINGW)
559 const QString implibPrefix = QStringLiteral("lib");
560 const QString implibSuffix = QStringLiteral(".a");
561#else
562 const QString implibPrefix;
563 const QString implibSuffix = QStringLiteral(".lib");
564#endif
565 const QString qtCoreImpLibFileName = implibPrefix
566 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
567 const QString qtCoreImpLibPath = qtCoreDirPath
568 + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH
569 + slash + libdir
570 + slash + qtCoreImpLibFileName;
571 if (!QFileInfo::exists(qtCoreImpLibPath)) {
572 // We did not find a corresponding import library and conclude that this is a
573 // windeployqt'ed executable.
574 return exeDirPath;
575 }
576 }
577 if (!qtCoreFilePath.isEmpty())
578 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
579#else
580#error "The chosen platform / config does not support querying for a dynamic prefix."
581#endif
582
583#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
584 // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir.
585 // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0
586 // changelog regarding SSE2 support.
587 QString libdir = fromRawStringView(qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
588 QDir prefixDir(prefixPath);
589 while (!prefixDir.exists(libdir)) {
590 prefixDir.cdUp();
591 prefixPath = prefixDir.absolutePath();
592 if (prefixDir.isRoot()) {
593 prefixPath.clear();
594 break;
595 }
596 }
597#endif
598
599 Q_ASSERT_X(!prefixPath.isEmpty(), "relocatablePrefixFromQt",
600 "Failed to find the Qt prefix path.");
601 return prefixPath;
602}
603#endif
604
605QString QLibraryPrefixes::resolveQtPrefix()
606{
607#if QT_CONFIG(relocatable)
608 return relocatablePrefixFromQt();
609#else
610 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
611#endif
612}
613
614QString QLibraryPrefixes::qtPrefix()
615{
616#if defined(QT_STATIC)
617 // In static builds the Qt prefix resolves via the app directory (see
618 // relocatablePrefixFromQt), which is not stable until an application
619 // instance exists, and is cached and invalidated by appPrefix().
620 // Don't cache it a second time here, to avoid freezing a transient
621 // working-directory value.
622 return resolveQtPrefix();
623#else
624 return cached(&QLibraryPrefixes::m_qt, &QLibraryPrefixes::resolveQtPrefix);
625#endif
626}
627
628QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc)
629{
630 /*
631 * To add a new entry in QLibraryInfo::LibraryPath, add it to the enum
632 * in qtbase/src/corelib/global/qlibraryinfo.h and:
633 * - add its relative path in the qtConfEntries[] array below
634 * (the key is what appears in a qt.conf file)
635 */
636 static constexpr auto qtConfEntries = qOffsetStringArray(
637 "Prefix", ".",
638 "Documentation", "doc", // should be ${Data}/doc
639 "Headers", "include",
640 "Libraries", "lib",
641#ifdef Q_OS_WIN
642 "LibraryExecutables", "bin",
643#else
644 "LibraryExecutables", "libexec", // should be ${ArchData}/libexec
645#endif
646 "Binaries", "bin",
647 "Plugins", "plugins", // should be ${ArchData}/plugins
648
649 "QmlImports", "qml", // should be ${ArchData}/qml
650
651 "ArchData", ".",
652 "Data", ".",
653 "Translations", "translations", // should be ${Data}/translations
654 "Examples", "examples",
655 "Tests", "tests"
656 );
657 [[maybe_unused]]
658 constexpr QByteArrayView dot{"."};
659
660 LocationInfo result;
661
662 if (int(loc) < qtConfEntries.count()) {
663 result.key = QLatin1StringView(qtConfEntries.viewAt(loc * 2));
664 result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(loc * 2 + 1));
665 if (result.key == u"QmlImports")
666 result.fallbackKey = u"Qml2Imports"_s;
667#if !defined(Q_OS_WIN) // On Windows we use the registry
668 } else if (loc == QLibraryInfo::SettingsPath) {
669 result.key = "Settings"_L1;
670 result.defaultValue = QLatin1StringView(dot);
671#endif
672 }
673
674 return result;
675}
676
677/*! \fn QString QLibraryInfo::location(LibraryLocation loc)
678 \deprecated [6.0] Use path() instead.
679
680 Returns the path specified by \a loc.
681*/
682
683/*!
684 \since 6.0
685 Returns the path specified by \a p.
686
687 If there is more than one path listed in qt.conf, it will
688 only return the first one.
689 \sa paths
690*/
691QString QLibraryInfo::path(LibraryPath p)
692{
693 return QLibraryInfoPrivate::path(p);
694}
695
696/*!
697 \since 6.8
698 Returns all paths specificied by \a p.
699
700 \sa path
701 */
702QStringList QLibraryInfo::paths(LibraryPath p)
703{
704 return QLibraryInfoPrivate::paths(p);
705}
706
707/*!
708 Returns whether the existence of a \c qt.conf with explicit
709 paths should not trigger the stable fallback-values from
710 QLibraryInfoPrivate::locationInfo() as usual, but instead
711 fall back to the Qt configure defaults (which may differ
712 from Qt installation to Qt installtion).
713
714 This mechanism is used by QtQml's internal build machinery
715 for making QML modules across different paths available
716 during development.
717
718 \internal
719*/
720static bool keepQtBuildDefaults()
721{
722#if QT_CONFIG(settings)
723 QSettings *config = QLibraryInfoPrivate::configuration();
724 Q_ASSERT(config != nullptr);
725 return config->value("Config/MergeQtConf", false).toBool();
726#else
727 return false;
728#endif
729}
730
731#if QT_CONFIG(settings)
732QString QLibraryInfoPrivate::expandEnvVariables(QString ret)
733{
734 qsizetype startIndex = 0;
735 /* We support placeholders of the form $(<ENV_VAR>) in qt.conf.
736 The loop below tries to find all such placeholders, and replaces
737 them with the actual value of the ENV_VAR environment variable
738 */
739 while (true) {
740 startIndex = ret.indexOf(u'$', startIndex);
741 if (startIndex < 0)
742 break;
743 if (ret.size() < startIndex + 3)
744 break;
745 if (ret.at(startIndex + 1) != u'(') {
746 startIndex++;
747 continue;
748 }
749 qsizetype endIndex = ret.indexOf(u')', startIndex + 2);
750 if (endIndex < 0)
751 break;
752 auto envVarName = QStringView{ret}.sliced(startIndex + 2, endIndex - startIndex - 2);
753 QString value = qEnvironmentVariable(envVarName.toLocal8Bit().constData());
754 ret.replace(startIndex, endIndex - startIndex + 1, value);
755 startIndex += value.size();
756 }
757 return QDir::fromNativeSeparators(ret);
758}
759
760#endif // settings
761
762/*!
763 \internal
764
765 Roots any relative entries in \a paths at the directory returned by
766 \a resolveBaseDir, which is resolved lazily (only when there's actually a
767 relative path to root, and at most once).
768*/
769static QList<QString> makeAbsolute(QList<QString> paths, QString (*resolveBaseDir)())
770{
771 QString baseDir;
772 for (QString &path : paths) {
773 if (pathIsRelative(path)) {
774 if (baseDir.isNull())
775 baseDir = resolveBaseDir();
776 path = QDir::cleanPath(baseDir + u'/' + std::move(path));
777 }
778 }
779 return paths;
780}
781
782QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath location)
783{
784 QList<QString> ret = appPaths(location);
785
786 if (ret.isEmpty() || keepQtBuildDefaults())
787 ret += qtPaths(location);
788
789 return ret;
790}
791
792/*!
793 \internal
794
795 The application-prefixed paths for \a location, rooted at the app prefix,
796 sourced from a qt.conf with explicit paths. Returns empty when there's no
797 such qt.conf, signaling the caller to fall through to the Qt-prefixed paths.
798*/
799QList<QString> QLibraryInfoPrivate::appPaths(QLibraryInfo::LibraryPath location)
800{
801#if QT_CONFIG(settings)
802 QLibrarySettings *qtConfSettings = qt_library_settings();
803 if (qtConfSettings && qtConfSettings->havePaths()) {
804 if (location == QLibraryInfo::PrefixPath)
805 return { QLibraryPrefixes::appPrefix() };
806
807 QList<QString> paths = qtConfSettings->paths(location);
808
809 // Fall back to a stable default for missing qt.conf values
810 if (paths.isEmpty()) {
811 const auto locationInfo = QLibraryInfoPrivate::locationInfo(location);
812 if (!locationInfo.defaultValue.isNull())
813 paths << locationInfo.defaultValue;
814 }
815
816 return makeAbsolute(std::move(paths), &QLibraryPrefixes::appPrefix);
817 }
818#endif
819 return {};
820}
821
822/*!
823 \internal
824
825 The Qt-prefixed paths for \a location, rooted at the Qt prefix, from the
826 paths baked in at configure time.
827*/
828QList<QString> QLibraryInfoPrivate::qtPaths(QLibraryInfo::LibraryPath location)
829{
830 if (location == QLibraryInfo::PrefixPath)
831 return { QLibraryPrefixes::qtPrefix() };
832
833 QList<QString> paths;
834
835 if (int(location) <= qt_configure_strs.count()) {
836 paths << fromRawStringView(qt_configure_strs.viewAt(location - 1));
837#if !defined(Q_OS_WIN) // On Windows we use the registry
838 } else if (location == QLibraryInfo::SettingsPath) {
839 constexpr QStringView path = u"" QT_CONFIGURE_SETTINGS_PATH;
840 paths << fromRawStringView(path);
841#endif
842 }
843
844 return makeAbsolute(std::move(paths), &QLibraryPrefixes::qtPrefix);
845}
846
847/*
848 Returns the path specified by \a p.
849 */
850QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p)
851{
852 return paths(p).value(0, QString());
853}
854
855/*!
856 Returns additional arguments to the platform plugin matching
857 \a platformName which can be specified as a string list using
858 the key \c Arguments in a group called \c Platforms of the
859 \c qt.conf file.
860
861 sa {Using qt.conf}
862
863 \internal
864
865 \since 5.3
866*/
867
868QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
869{
870#if QT_CONFIG(settings)
871 if (const QSettings *settings = QLibraryInfoPrivate::configuration()) {
872 const QString key = "Platforms/"_L1
873 + platformName
874 + "Arguments"_L1;
875 return settings->value(key).toStringList();
876 }
877#else
878 Q_UNUSED(platformName);
879#endif // settings
880 return QStringList();
881}
882
883/*!
884 \enum QLibraryInfo::LibraryPath
885
886 \keyword library location
887
888 This enum type is used to query for a specific path:
889
890 \value PrefixPath The default prefix for all paths.
891 \value DocumentationPath The path to documentation upon install.
892 \value HeadersPath The path to all headers.
893 \value LibrariesPath The path to installed libraries.
894 \value LibraryExecutablesPath The path to installed executables required by libraries at runtime.
895 \value BinariesPath The path to installed Qt binaries (tools and applications).
896 \value PluginsPath The path to installed Qt plugins.
897 \value QmlImportsPath The path to installed QML extensions to import.
898 \value Qml2ImportsPath This value is deprecated. Use QmlImportsPath instead.
899 \value ArchDataPath The path to general architecture-dependent Qt data.
900 \value DataPath The path to general architecture-independent Qt data.
901 \value TranslationsPath The path to translation information for Qt strings.
902 \value ExamplesPath The path to examples upon install.
903 \value TestsPath The path to installed Qt testcases.
904 \value SettingsPath The path to Qt settings. Not applicable on Windows.
905
906 \sa path()
907*/
908
909/*!
910 \typealias QLibraryInfo::LibraryLocation
911 \deprecated [6.0] Use LibraryPath with QLibraryInfo::path() instead.
912*/
913
914/*!
915 \headerfile <QtVersion>
916 \inmodule QtCore
917 \ingroup funclists
918 \brief Information about which Qt version the application is running on,
919 and the version it was compiled against.
920*/
921
922/*!
923 \macro QT_VERSION_STR
924 \relates <QtVersion>
925
926 This macro expands to a string that specifies Qt's version number (for
927 example, "6.1.2"). This is the version with which the application is
928 compiled. This may be a different version than the version the application
929 will find itself using at \e runtime.
930
931 \sa qVersion(), QT_VERSION
932*/
933
934/*!
935 \relates <QtVersion>
936
937 Returns the version number of Qt at runtime as a string (for example,
938 "6.1.2"). This is the version of the Qt library in use at \e runtime,
939 which need not be the version the application was \e compiled with.
940
941 \sa QT_VERSION_STR, QLibraryInfo::version()
942*/
943
944const char *qVersion() noexcept
945{
946 return QT_VERSION_STR;
947}
948
949#if QT_DEPRECATED_SINCE(6, 9)
950
951bool qSharedBuild() noexcept
952{
953 return QLibraryInfo::isSharedBuild();
954}
955
956#endif // QT_DEPRECATED_SINCE(6, 9)
957
958QT_END_NAMESPACE
959
960#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
961# include <elf.h>
962# include <stdio.h>
963# include <stdlib.h>
964
965#include "private/qcoreapplication_p.h"
966
967QT_WARNING_DISABLE_GCC("-Wformat-overflow")
968QT_WARNING_DISABLE_GCC("-Wattributes")
969QT_WARNING_DISABLE_CLANG("-Wattributes")
970QT_WARNING_DISABLE_INTEL(2621)
971
972# if defined(Q_OS_LINUX)
973# include "minimum-linux_p.h"
974# endif
975# ifdef QT_ELF_NOTE_OS_TYPE
976struct ElfNoteAbiTag
977{
978 static_assert(sizeof(Elf32_Nhdr) == sizeof(Elf64_Nhdr),
979 "The size of an ELF note is wrong (should be 12 bytes)");
980 struct Payload {
981 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
982 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
983 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
984# ifdef QT_ELF_NOTE_OS_PATCH
985 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
986# endif
987 };
988
989 Elf32_Nhdr header = {
990 .n_namesz = sizeof(name),
991 .n_descsz = sizeof(Payload),
992 .n_type = NT_GNU_ABI_TAG
993 };
994 char name[sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU; // yes, include the null terminator
995 Payload payload = {};
996};
997__attribute__((section(".note.ABI-tag"), aligned(4), used))
998extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
999# endif
1000
1001extern const char qt_core_interpreter[] __attribute__((section(".interp")))
1002 = ELF_INTERPRETER;
1003
1004extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
1005void qt_core_boilerplate()
1006{
1007 QT_USE_NAMESPACE
1008
1009 printf("This is the QtCore library version %s\n"
1010 "%s\n"
1011 "Contact: https://www.qt.io/licensing/\n"
1012 "\n",
1013 QT_PREPEND_NAMESPACE(qt_build_string)(),
1014 QT_COPYRIGHT);
1015
1016 QByteArray libPath =
1017 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1).toUtf8();
1018 QByteArray pluginPath =
1019 qt_configure_strs.viewAt(QLibraryInfo::PluginsPath - 1).toUtf8();
1020#if QT_CONFIG(relocatable)
1021 QByteArray prefix = QLibraryPrefixes::qtPrefix().toUtf8();
1022#else
1023 QByteArrayView prefix = QT_CONFIGURE_PREFIX_PATH;
1024#endif
1025 printf("Installation prefix: %s\n"
1026 "Library path: %s\n"
1027 "Plugin path: %s\n",
1028 prefix.data(),
1029 libPath.data(),
1030 pluginPath.data());
1031
1032 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
1033
1034 exit(0);
1035}
1036
1037#endif
#define ARCH_FULL
static QString fromRawStringView(QStringView string)
static bool pathIsRelative(const QString &path)
void qDumpCPUFeatures()
Definition qsimd.cpp:683
#define SHARED_STRING
#define COMPILER_STRING
#define DEBUG_STRING
static QString qtPrefix()
static QString appPrefix()