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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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