18#include "private/qcoreapplication_p.h"
19#include "private/qfilesystementry_p.h"
24# include "private/qcore_mac_p.h"
27#if QT_CONFIG(relocatable) && QT_CONFIG(dlopen)
31#if QT_CONFIG(relocatable) && defined(Q_OS_WIN)
32# include <qt_windows.h>
39using namespace Qt::StringLiterals;
45 return QString::fromRawData(string.data(), string.size());
50 using FromInternalPath = QFileSystemEntry::FromInternalPath;
51 return !path.startsWith(
':'_L1) && QFileSystemEntry(path, FromInternalPath{}).isRelative();
68 static QString resolveQtPrefix();
69 static QString resolveAppPrefix();
74 static QString resolveAppDir();
78 static QString qtConfPrefix();
85 static QString cached(QString QLibraryPrefixes::*member, QString (*resolve)());
90Q_GLOBAL_STATIC(QLibraryPrefixes, prefixCache)
92QString QLibraryPrefixes::cached(QString QLibraryPrefixes::*member, QString (*resolve)())
94 QLibraryPrefixes *cache = prefixCache();
95 if (cache && !(cache->*member).isEmpty())
96 return cache->*member;
97 QString prefix = resolve();
98 if (cache && !prefix.isEmpty())
99 cache->*member = prefix;
103#if QT_CONFIG(settings)
105static std::unique_ptr<QSettings> findConfiguration();
107struct QLibrarySettings
112 QSettings *configuration();
113 QVariant value(QLibraryInfo::LibraryPath path);
114 QList<QString> paths(QLibraryInfo::LibraryPath location);
116 std::unique_ptr<QSettings> settings;
118 bool reloadOnQAppAvailable;
120Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
122QLibrarySettings::QLibrarySettings() : configHasPaths(
false), reloadOnQAppAvailable(
false)
127QSettings *QLibrarySettings::configuration()
129 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
131 return settings.get();
134bool QLibrarySettings::havePaths()
136 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
138 return configHasPaths;
141void QLibrarySettings::load()
144 settings = findConfiguration();
145 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
150 QStringList children = settings->childGroups();
151 configHasPaths = !children.contains(
"Platforms"_L1)
152 || children.contains(
"Paths"_L1);
154 configHasPaths =
false;
159
160
161
162
163
164
165
166
167QVariant QLibrarySettings::value(QLibraryInfo::LibraryPath path)
169 const auto locationInfo = QLibraryInfoPrivate::locationInfo(path);
170 if (locationInfo.key.isNull())
173 QSettings *config = configuration();
174 if (!settings || !configHasPaths)
177 config->beginGroup(
"Paths"_L1);
178 auto cleanup = qScopeGuard([&]() { config->endGroup(); });
179 QVariant value = config->value(locationInfo.key);
180 if (!value.isValid() && !locationInfo.fallbackKey.isNull())
181 value = config->value(locationInfo.fallbackKey);
185QList<QString> QLibrarySettings::paths(QLibraryInfo::LibraryPath location)
188 if (QVariant v = value(location); v.isValid()) {
189 if (
auto *asList = get_if<QList<QString>>(&v))
190 ret = std::move(*asList);
194 for (qsizetype i = 0, end = ret.size(); i < end; ++i)
195 ret[i] = QLibraryInfoPrivate::expandEnvVariables(ret[i]);
201const QString *qtconfManualPath =
nullptr;
204void QLibraryInfoPrivate::setQtconfManualPath(
const QString *path)
206 qtconfManualPath = path;
209static std::unique_ptr<QSettings> findConfiguration()
211 if (qtconfManualPath)
212 return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
214 QString qtconfig = QStringLiteral(
":/qt/etc/qt.conf");
215 if (QResource(qtconfig, QLocale::c()).isValid())
216 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
218 CFBundleRef bundleRef = CFBundleGetMainBundle();
220 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
221 QCFString(
"qt.conf"_L1),
225 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
226 qtconfig = QDir::cleanPath(path);
227 if (QFile::exists(qtconfig))
228 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
232 if (QCoreApplication::instanceExists()) {
233 QString pwd = QCoreApplication::applicationDirPath();
234 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR)
".conf"_s;
235 if (QFile::exists(qtconfig))
236 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
237 qtconfig = pwd + u"/qt.conf";
238 if (QFile::exists(qtconfig))
239 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
244QSettings *QLibraryInfoPrivate::configuration()
246 QLibrarySettings *ls = qt_library_settings();
247 return ls ? ls->configuration() :
nullptr;
251void QLibraryInfoPrivate::reload()
253#if QT_CONFIG(settings)
254 if (qt_library_settings.exists())
255 qt_library_settings->load();
257 if (prefixCache.exists())
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
282
283
284
285
286
288QLibraryInfo::QLibraryInfo()
291#if defined(Q_CC_CLANG)
292# define COMPILER_STRING __VERSION__
293#elif defined(Q_CC_GHS)
294# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
295#elif defined(Q_CC_GNU)
296# define COMPILER_STRING "GCC " __VERSION__
297#elif defined(Q_CC_MSVC)
299# define COMPILER_STRING "MSVC 2015"
300# elif _MSC_VER < 1917
301# define COMPILER_STRING "MSVC 2017"
302# elif _MSC_VER < 1930
303# define COMPILER_STRING "MSVC 2019"
304# elif _MSC_VER < 1950
305# define COMPILER_STRING "MSVC 2022"
306# elif _MSC_VER < 2000
307# define COMPILER_STRING "MSVC 2026"
309# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
312# define COMPILER_STRING "<unknown compiler>"
315# define DEBUG_STRING " release"
317# define DEBUG_STRING " debug"
320# define SHARED_STRING " shared (dynamic)"
322# define SHARED_STRING " static"
324static const char *qt_build_string()
noexcept
330
331
332
333
334
335
337const char *QLibraryInfo::build()
noexcept
339 return qt_build_string();
343
344
345
346
348QLibraryInfo::isDebugBuild()
noexcept
358
359
360
361bool QLibraryInfo::isSharedBuild()
noexcept
371
372
373
374
375
376QVersionNumber QLibraryInfo::version()
noexcept
378 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
382
383
384
385
386
387
388QString QLibraryPrefixes::qtConfPrefix()
390#if QT_CONFIG(settings)
391 QLibrarySettings *settings = qt_library_settings();
392 if (settings && settings->havePaths()) {
393 const QString prefix = settings->paths(QLibraryInfo::PrefixPath).value(0);
394 if (!prefix.isEmpty())
402
403
404
405
406
407
408QString QLibraryPrefixes::resolveAppDir()
410#if defined(Q_OS_DARWIN)
417 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
418 if (QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef)) {
419 const QString bundlePath = QCFString(CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle));
420 if (qt_apple_bundleType(bundlePath)) {
421#if defined(Q_OS_MACOS)
423 return QFileInfo(bundlePath +
"/Contents"_L1).canonicalFilePath();
425 return QFileInfo(bundlePath).canonicalFilePath();
432 if (QCoreApplication::instanceExists()) {
434 return QCoreApplication::applicationDirPath();
444
445
446
447
448
449
450
451
452
453
454
455
456QString QLibraryPrefixes::resolveAppPrefix()
458 const QString prefix = qtConfPrefix();
460 if (!pathIsRelative(prefix))
462 const QString appDir = resolveAppDir();
463 if (appDir.isEmpty())
465 return QDir::cleanPath(appDir + u'/' + prefix);
468QString QLibraryPrefixes::appPrefix()
470 QString prefix = cached(&QLibraryPrefixes::m_app, &QLibraryPrefixes::resolveAppPrefix);
471 if (!prefix.isNull())
476 return QDir::cleanPath(QDir::currentPath() + u'/' + qtConfPrefix());
479#if QT_CONFIG(relocatable)
480#if !defined(QT_STATIC) && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
481static QString prefixFromQtCoreLibraryHelper(
const QString &qtCoreLibraryPath)
483 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
484 QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
486#if QT_CONFIG(framework)
487# if defined(Q_OS_MACOS)
489 libDir +=
"/../.."_L1;
495 const QString prefixDir = libDir +
"/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
496 return QDir::cleanPath(prefixDir);
501static HMODULE getWindowsModuleHandle()
503 HMODULE hModule = NULL;
505 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
506 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
511static QString relocatablePrefixFromQt()
517#if defined(QT_STATIC)
518# if defined(Q_OS_APPLE)
527 if (!qt_apple_isSandboxed())
528 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
530 prefixPath = QLibraryPrefixes::appPrefix();
531#elif defined(Q_OS_WASM)
535 prefixPath = QStringLiteral(
"/");
536#elif QT_CONFIG(dlopen)
538 int result = dladdr(
reinterpret_cast<
void *>(&QLibraryInfo::isDebugBuild), &info);
539 if (result > 0 && info.dli_fname)
540 prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(info.dli_fname));
541#elif defined(Q_OS_WIN)
542 HMODULE hModule = getWindowsModuleHandle();
543 const int kBufferSize = 4096;
544 wchar_t buffer[kBufferSize];
545 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
546 const QString qtCoreFilePath = QString::fromWCharArray(buffer,
int(pathSize));
547 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
549 hModule =
reinterpret_cast<HMODULE>(QCoreApplicationPrivate::mainInstanceHandle);
550 pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
551 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer,
int(pathSize))).absolutePath();
552 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
556 QStringView libdir = qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1);
557 const QLatin1Char slash(
'/');
558#if defined(Q_CC_MINGW)
559 const QString implibPrefix = QStringLiteral(
"lib");
560 const QString implibSuffix = QStringLiteral(
".a");
562 const QString implibPrefix;
563 const QString implibSuffix = QStringLiteral(
".lib");
565 const QString qtCoreImpLibFileName = implibPrefix
566 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
567 const QString qtCoreImpLibPath = qtCoreDirPath
568 + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH
570 + slash + qtCoreImpLibFileName;
571 if (!QFileInfo::exists(qtCoreImpLibPath)) {
577 if (!qtCoreFilePath.isEmpty())
578 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
580#error "The chosen platform / config does not support querying for a dynamic prefix."
583#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
587 QString libdir = fromRawStringView(qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
588 QDir prefixDir(prefixPath);
589 while (!prefixDir.exists(libdir)) {
591 prefixPath = prefixDir.absolutePath();
592 if (prefixDir.isRoot()) {
599 Q_ASSERT_X(!prefixPath.isEmpty(),
"relocatablePrefixFromQt",
600 "Failed to find the Qt prefix path.");
605QString QLibraryPrefixes::resolveQtPrefix()
607#if QT_CONFIG(relocatable)
608 return relocatablePrefixFromQt();
610 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
614QString QLibraryPrefixes::qtPrefix()
616#if defined(QT_STATIC)
622 return resolveQtPrefix();
624 return cached(&QLibraryPrefixes::m_qt, &QLibraryPrefixes::resolveQtPrefix);
628QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc)
631
632
633
634
635
636 static constexpr auto qtConfEntries = qOffsetStringArray(
638 "Documentation",
"doc",
639 "Headers",
"include",
642 "LibraryExecutables",
"bin",
644 "LibraryExecutables",
"libexec",
647 "Plugins",
"plugins",
653 "Translations",
"translations",
654 "Examples",
"examples",
658 constexpr QByteArrayView dot{
"."};
662 if (
int(loc) < qtConfEntries.count()) {
663 result.key = QLatin1StringView(qtConfEntries.viewAt(loc * 2));
664 result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(loc * 2 + 1));
665 if (result.key == u"QmlImports")
666 result.fallbackKey = u"Qml2Imports"_s;
667#if !defined(Q_OS_WIN)
668 }
else if (loc == QLibraryInfo::SettingsPath) {
669 result.key =
"Settings"_L1;
670 result.defaultValue = QLatin1StringView(dot);
678
679
680
681
684
685
686
687
688
689
690
691QString QLibraryInfo::path(LibraryPath p)
693 return QLibraryInfoPrivate::path(p);
697
698
699
700
701
702QStringList QLibraryInfo::paths(LibraryPath p)
704 return QLibraryInfoPrivate::paths(p);
708
709
710
711
712
713
714
715
716
717
718
719
720static bool keepQtBuildDefaults()
722#if QT_CONFIG(settings)
723 QSettings *config = QLibraryInfoPrivate::configuration();
724 Q_ASSERT(config !=
nullptr);
725 return config->value(
"Config/MergeQtConf",
false).toBool();
731#if QT_CONFIG(settings)
732QString QLibraryInfoPrivate::expandEnvVariables(QString ret)
734 qsizetype startIndex = 0;
736
737
738
740 startIndex = ret.indexOf(u'$', startIndex);
743 if (ret.size() < startIndex + 3)
745 if (ret.at(startIndex + 1) != u'(') {
749 qsizetype endIndex = ret.indexOf(u')', startIndex + 2);
752 auto envVarName = QStringView{ret}.sliced(startIndex + 2, endIndex - startIndex - 2);
753 QString value = qEnvironmentVariable(envVarName.toLocal8Bit().constData());
754 ret.replace(startIndex, endIndex - startIndex + 1, value);
755 startIndex += value.size();
757 return QDir::fromNativeSeparators(ret);
763
764
765
766
767
768
769static QList<QString> makeAbsolute(QList<QString> paths, QString (*resolveBaseDir)())
772 for (QString &path : paths) {
773 if (pathIsRelative(path)) {
774 if (baseDir.isNull())
775 baseDir = resolveBaseDir();
776 path = QDir::cleanPath(baseDir + u'/' + std::move(path));
782QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath location)
784 QList<QString> ret = appPaths(location);
786 if (ret.isEmpty() || keepQtBuildDefaults())
787 ret += qtPaths(location);
793
794
795
796
797
798
799QList<QString> QLibraryInfoPrivate::appPaths(QLibraryInfo::LibraryPath location)
801#if QT_CONFIG(settings)
802 QLibrarySettings *qtConfSettings = qt_library_settings();
803 if (qtConfSettings && qtConfSettings->havePaths()) {
804 if (location == QLibraryInfo::PrefixPath)
805 return { QLibraryPrefixes::appPrefix() };
807 QList<QString> paths = qtConfSettings->paths(location);
810 if (paths.isEmpty()) {
811 const auto locationInfo = QLibraryInfoPrivate::locationInfo(location);
812 if (!locationInfo.defaultValue.isNull())
813 paths << locationInfo.defaultValue;
816 return makeAbsolute(std::move(paths), &QLibraryPrefixes::appPrefix);
823
824
825
826
827
828QList<QString> QLibraryInfoPrivate::qtPaths(QLibraryInfo::LibraryPath location)
830 if (location == QLibraryInfo::PrefixPath)
831 return { QLibraryPrefixes::qtPrefix() };
833 QList<QString> paths;
835 if (
int(location) <= qt_configure_strs.count()) {
836 paths << fromRawStringView(qt_configure_strs.viewAt(location - 1));
837#if !defined(Q_OS_WIN)
838 }
else if (location == QLibraryInfo::SettingsPath) {
839 constexpr QStringView path = u"" QT_CONFIGURE_SETTINGS_PATH;
840 paths << fromRawStringView(path);
844 return makeAbsolute(std::move(paths), &QLibraryPrefixes::qtPrefix);
848
849
850QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p)
852 return paths(p).value(0, QString());
856
857
858
859
860
861
862
863
864
865
866
868QStringList QLibraryInfo::platformPluginArguments(
const QString &platformName)
870#if QT_CONFIG(settings)
871 if (
const QSettings *settings = QLibraryInfoPrivate::configuration()) {
872 const QString key =
"Platforms/"_L1
875 return settings->value(key).toStringList();
878 Q_UNUSED(platformName);
880 return QStringList();
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
910
911
912
915
916
917
918
919
920
923
924
925
926
927
928
929
930
931
932
935
936
937
938
939
940
941
942
944const char *qVersion()
noexcept
946 return QT_VERSION_STR;
949#if QT_DEPRECATED_SINCE(6
, 9
)
951bool qSharedBuild()
noexcept
953 return QLibraryInfo::isSharedBuild();
960#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
965#include "private/qcoreapplication_p.h"
967QT_WARNING_DISABLE_GCC(
"-Wformat-overflow")
968QT_WARNING_DISABLE_GCC(
"-Wattributes")
969QT_WARNING_DISABLE_CLANG(
"-Wattributes")
970QT_WARNING_DISABLE_INTEL(2621)
972# if defined(Q_OS_LINUX)
973# include "minimum-linux_p.h"
975# ifdef QT_ELF_NOTE_OS_TYPE
978 static_assert(
sizeof(Elf32_Nhdr) ==
sizeof(Elf64_Nhdr),
979 "The size of an ELF note is wrong (should be 12 bytes)");
981 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
982 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
983 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
984# ifdef QT_ELF_NOTE_OS_PATCH
985 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
989 Elf32_Nhdr header = {
990 .n_namesz =
sizeof(name),
991 .n_descsz =
sizeof(Payload),
992 .n_type = NT_GNU_ABI_TAG
994 char name[
sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU;
995 Payload payload = {};
997__attribute__((section(
".note.ABI-tag"), aligned(4), used))
998extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
1001extern const char qt_core_interpreter[]
__attribute__((section(
".interp")))
1004extern "C" void qt_core_boilerplate()
__attribute__((force_align_arg_pointer));
1005void qt_core_boilerplate()
1009 printf(
"This is the QtCore library version %s\n"
1011 "Contact: https://www.qt.io/licensing/\n"
1013 QT_PREPEND_NAMESPACE(qt_build_string)(),
1016 QByteArray libPath =
1017 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1).toUtf8();
1018 QByteArray pluginPath =
1019 qt_configure_strs.viewAt(QLibraryInfo::PluginsPath - 1).toUtf8();
1020#if QT_CONFIG(relocatable)
1021 QByteArray prefix = QLibraryPrefixes::qtPrefix().toUtf8();
1023 QByteArrayView prefix = QT_CONFIGURE_PREFIX_PATH;
1025 printf(
"Installation prefix: %s\n"
1026 "Library path: %s\n"
1027 "Plugin path: %s\n",
1032 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
static QString fromRawStringView(QStringView string)
static bool pathIsRelative(const QString &path)
static QString qtPrefix()
static QString appPrefix()