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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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