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
5#include "qdir.h"
6#include "qstringlist.h"
7#include "qfile.h"
8#if QT_CONFIG(settings)
9#include "qresource.h"
10#include "qsettings.h"
11#endif
12#include "qlibraryinfo.h"
13#include "qlibraryinfo_p.h"
14
16
17#include "private/qcoreapplication_p.h"
18#include "private/qfilesystementry_p.h"
19#include "archdetect.cpp"
20#include "qconfig.cpp"
21
22#ifdef Q_OS_DARWIN
23# include "private/qcore_mac_p.h"
24#endif // Q_OS_DARWIN
25
26#if QT_CONFIG(relocatable) && QT_CONFIG(dlopen) && !QT_CONFIG(framework)
27# include <dlfcn.h>
28#endif
29
30#if QT_CONFIG(relocatable) && defined(Q_OS_WIN)
31# include <qt_windows.h>
32#endif
33
34#include <memory>
35
36QT_BEGIN_NAMESPACE
37
38using namespace Qt::StringLiterals;
39
40extern void qDumpCPUFeatures(); // in qsimd.cpp
41
42#if QT_CONFIG(settings)
43
44static std::unique_ptr<QSettings> findConfiguration();
45
46struct QLibrarySettings
47{
48 QLibrarySettings();
49 void load();
50 bool havePaths();
51 QSettings *configuration();
52
53 std::unique_ptr<QSettings> settings;
54 bool paths;
55 bool reloadOnQAppAvailable;
56};
57Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
58
59QLibrarySettings::QLibrarySettings() : paths(false), reloadOnQAppAvailable(false)
60{
61 load();
62}
63
64QSettings *QLibrarySettings::configuration()
65{
66 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
67 load();
68 return settings.get();
69}
70
71bool QLibrarySettings::havePaths()
72{
73 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
74 load();
75 return paths;
76}
77
78void QLibrarySettings::load()
79{
80 // If we get any settings here, those won't change when the application shows up.
81 settings = findConfiguration();
82 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
83
84 if (settings) {
85 // This code needs to be in the regular library, as otherwise a qt.conf that
86 // works for qmake would break things for dynamically built Qt tools.
87 QStringList children = settings->childGroups();
88 paths = !children.contains("Platforms"_L1)
89 || children.contains("Paths"_L1);
90 }
91}
92
93namespace {
94const QString *qtconfManualPath = nullptr;
95}
96
97void QLibraryInfoPrivate::setQtconfManualPath(const QString *path)
98{
99 qtconfManualPath = path;
100}
101
102static std::unique_ptr<QSettings> findConfiguration()
103{
104 if (qtconfManualPath)
105 return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
106
107 QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
108 if (QResource(qtconfig, QLocale::c()).isValid())
109 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
110#ifdef Q_OS_DARWIN
111 CFBundleRef bundleRef = CFBundleGetMainBundle();
112 if (bundleRef) {
113 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
114 QCFString("qt.conf"_L1),
115 0,
116 0);
117 if (urlRef) {
118 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
119 qtconfig = QDir::cleanPath(path);
120 if (QFile::exists(qtconfig))
121 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
122 }
123 }
124#endif
125 if (QCoreApplication::instanceExists()) {
126 QString pwd = QCoreApplication::applicationDirPath();
127 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR) ".conf"_s;
128 if (QFile::exists(qtconfig))
129 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
130 qtconfig = pwd + u"/qt.conf";
131 if (QFile::exists(qtconfig))
132 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
133 }
134 return nullptr; //no luck
135}
136
137QSettings *QLibraryInfoPrivate::configuration()
138{
139 QLibrarySettings *ls = qt_library_settings();
140 return ls ? ls->configuration() : nullptr;
141}
142
143void QLibraryInfoPrivate::reload()
144{
145 if (qt_library_settings.exists())
146 qt_library_settings->load();
147}
148
149static bool havePaths() {
150 QLibrarySettings *ls = qt_library_settings();
151 return ls && ls->havePaths();
152}
153
154#endif // settings
155
156/*!
157 \class QLibraryInfo
158 \inmodule QtCore
159 \brief The QLibraryInfo class provides information about the Qt library.
160
161 Many pieces of information are established when Qt is configured and built.
162 This class provides an abstraction for accessing that information.
163 By using the static functions of this class, an application can obtain
164 information about the instance of the Qt library which the application
165 is using at run-time.
166
167 You can also use a \c qt.conf file to override the hard-coded paths
168 that are compiled into the Qt library. For more information, see
169 the \l {Using qt.conf} documentation.
170
171 \sa QSysInfo, {Using qt.conf}
172*/
173
174/*!
175 \internal
176
177 You cannot create a QLibraryInfo, instead only the static functions are available to query
178 information.
179*/
180
181QLibraryInfo::QLibraryInfo()
182{ }
183
184#if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
185# define COMPILER_STRING __VERSION__ /* already includes the compiler's name */
186#elif defined(Q_CC_GHS)
187# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
188#elif defined(Q_CC_GNU)
189# define COMPILER_STRING "GCC " __VERSION__
190#elif defined(Q_CC_MSVC)
191# if _MSC_VER < 1910
192# define COMPILER_STRING "MSVC 2015"
193# elif _MSC_VER < 1917
194# define COMPILER_STRING "MSVC 2017"
195# elif _MSC_VER < 1930
196# define COMPILER_STRING "MSVC 2019"
197# elif _MSC_VER < 2000
198# define COMPILER_STRING "MSVC 2022"
199# else
200# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
201# endif
202#else
203# define COMPILER_STRING "<unknown compiler>"
204#endif
205#ifdef QT_NO_DEBUG
206# define DEBUG_STRING " release"
207#else
208# define DEBUG_STRING " debug"
209#endif
210#ifdef QT_SHARED
211# define SHARED_STRING " shared (dynamic)"
212#else
213# define SHARED_STRING " static"
214#endif
215static const char *qt_build_string() noexcept
216{
217 return "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")";
218}
219
220/*!
221 Returns a string describing how this version of Qt was built.
222
223 \internal
224
225 \since 5.3
226*/
227
228const char *QLibraryInfo::build() noexcept
229{
230 return qt_build_string();
231}
232
233/*!
234 \since 5.0
235 Returns \c true if this build of Qt was built with debugging enabled, or
236 false if it was built in release mode.
237*/
238bool
239QLibraryInfo::isDebugBuild() noexcept
240{
241#ifdef QT_DEBUG
242 return true;
243#else
244 return false;
245#endif
246}
247
248/*!
249 \since 6.5
250 Returns \c true if this is a shared (dynamic) build of Qt.
251*/
252bool QLibraryInfo::isSharedBuild() noexcept
253{
254#ifdef QT_SHARED
255 return true;
256#else
257 return false;
258#endif
259}
260
261/*!
262 \since 5.8
263 Returns the version of the Qt library.
264
265 \sa qVersion()
266*/
267QVersionNumber QLibraryInfo::version() noexcept
268{
269 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
270}
271
273{
274 if (QCoreApplication::instanceExists()) {
275#ifdef Q_OS_DARWIN
276 CFBundleRef bundleRef = CFBundleGetMainBundle();
277 if (bundleRef) {
278 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
279 if (urlRef) {
280 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
281#ifdef Q_OS_MACOS
282 QString bundleContentsDir = QString(path) + "/Contents/"_L1;
283 if (QDir(bundleContentsDir).exists())
284 return QDir::cleanPath(bundleContentsDir);
285#else
286 return QDir::cleanPath(QString(path)); // iOS
287#endif // Q_OS_MACOS
288 }
289 }
290#endif // Q_OS_DARWIN
291 // We make the prefix path absolute to the executable's directory.
292 return QCoreApplication::applicationDirPath();
293 } else {
294 return QDir::currentPath();
295 }
296}
297
298#if QT_CONFIG(relocatable)
299#if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework))
300 && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
301static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
302{
303 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
304 const QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
305 const QString prefixDir = libDir + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
306 return QDir::cleanPath(prefixDir);
307}
308#endif
309
310#if defined(Q_OS_WIN)
311static HMODULE getWindowsModuleHandle()
312{
313 HMODULE hModule = NULL;
314 GetModuleHandleEx(
315 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
316 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
317 return hModule;
318}
319#endif // Q_OS_WIN
320
321static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
322{
323 QString prefixPath;
324
325 // For static builds, the prefix will be the app directory.
326 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
327#if defined(QT_STATIC)
328 prefixPath = prefixFromAppDirHelper();
329 if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) {
330 // For Qt tools in a static build, we must chop off the bin directory.
331 constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1);
332 constexpr size_t binDirLength = binDir.size() + 1;
333 prefixPath.chop(binDirLength);
334 }
335#elif defined(Q_OS_DARWIN) && QT_CONFIG(framework)
336 Q_UNUSED(usageMode);
337#ifndef QT_LIBINFIX
338 #define QT_LIBINFIX ""
339#endif
340 auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtCore" QT_LIBINFIX));
341 if (!qtCoreBundle) {
342 // When running Qt apps over Samba shares, CoreFoundation will fail to find
343 // the Resources directory inside the bundle, This directory is a symlink,
344 // and CF relies on readdir() and dtent.dt_type to detect symlinks, which
345 // does not work reliably for Samba shares. We work around it by manually
346 // looking for the QtCore bundle.
347 auto allBundles = CFBundleGetAllBundles();
348 auto bundleCount = CFArrayGetCount(allBundles);
349 for (int i = 0; i < bundleCount; ++i) {
350 auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i));
351 auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle));
352 auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
353 if (CFStringHasSuffix(path, CFSTR("/QtCore" QT_LIBINFIX ".framework"))) {
354 qtCoreBundle = bundle;
355 break;
356 }
357 }
358 }
359 Q_ASSERT(qtCoreBundle);
360
361 QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle);
362 Q_ASSERT(qtCorePath);
363
364 QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath);
365 Q_ASSERT(qtCorePathAbsolute);
366
367 QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute);
368
369 const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle);
370
371 const QString prefixDir = QString(libDirCFString) + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
372
373 prefixPath = QDir::cleanPath(prefixDir);
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 \macro QT_VERSION_STR
756 \relates <QtVersion>
757
758 This macro expands to a string that specifies Qt's version number (for
759 example, "6.1.2"). This is the version with which the application is
760 compiled. This may be a different version than the version the application
761 will find itself using at \e runtime.
762
763 \sa qVersion(), QT_VERSION
764*/
765
766/*!
767 \relates <QtVersion>
768
769 Returns the version number of Qt at runtime as a string (for example,
770 "6.1.2"). This is the version of the Qt library in use at \e runtime,
771 which need not be the version the application was \e compiled with.
772
773 \sa QT_VERSION_STR, QLibraryInfo::version()
774*/
775
776const char *qVersion() noexcept
777{
778 return QT_VERSION_STR;
779}
780
781#if QT_DEPRECATED_SINCE(6, 9)
782
783bool qSharedBuild() noexcept
784{
785 return QLibraryInfo::isSharedBuild();
786}
787
788#endif // QT_DEPRECATED_SINCE(6, 9)
789
790QT_END_NAMESPACE
791
792#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
793# include <elf.h>
794# include <stdio.h>
795# include <stdlib.h>
796
797#include "private/qcoreapplication_p.h"
798
799QT_WARNING_DISABLE_GCC("-Wformat-overflow")
800QT_WARNING_DISABLE_GCC("-Wattributes")
801QT_WARNING_DISABLE_CLANG("-Wattributes")
802QT_WARNING_DISABLE_INTEL(2621)
803
804# if defined(Q_OS_LINUX)
805# include "minimum-linux_p.h"
806# endif
807# ifdef QT_ELF_NOTE_OS_TYPE
808struct ElfNoteAbiTag
809{
810 static_assert(sizeof(Elf32_Nhdr) == sizeof(Elf64_Nhdr),
811 "The size of an ELF note is wrong (should be 12 bytes)");
812 struct Payload {
813 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
814 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
815 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
816# ifdef QT_ELF_NOTE_OS_PATCH
817 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
818# endif
819 };
820
821 Elf32_Nhdr header = {
822 .n_namesz = sizeof(name),
823 .n_descsz = sizeof(Payload),
824 .n_type = NT_GNU_ABI_TAG
825 };
826 char name[sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU; // yes, include the null terminator
827 Payload payload = {};
828};
829__attribute__((section(".note.ABI-tag"), aligned(4), used))
830extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
831# endif
832
833extern const char qt_core_interpreter[] __attribute__((section(".interp")))
834 = ELF_INTERPRETER;
835
836extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
837void qt_core_boilerplate()
838{
839 printf("This is the QtCore library version %s\n"
840 "%s\n"
841 "Contact: https://www.qt.io/licensing/\n"
842 "\n"
843 "Installation prefix: %s\n"
844 "Library path: %s\n"
845 "Plugin path: %s\n",
846 QT_PREPEND_NAMESPACE(qt_build_string)(),
847 QT_COPYRIGHT,
848 QT_CONFIGURE_PREFIX_PATH,
849 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
850 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
851
852 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
853
854 exit(0);
855}
856
857#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