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

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