17#include "private/qcoreapplication_p.h"
18#include "private/qfilesystementry_p.h"
23# include "private/qcore_mac_p.h"
26#if QT_CONFIG(relocatable) && QT_CONFIG(dlopen) && !QT_CONFIG(framework)
30#if QT_CONFIG(relocatable) && defined(Q_OS_WIN)
31# include <qt_windows.h>
38using namespace Qt::StringLiterals;
42#if QT_CONFIG(settings)
44static std::unique_ptr<QSettings> findConfiguration();
46struct QLibrarySettings
51 QSettings *configuration();
53 std::unique_ptr<QSettings> settings;
55 bool reloadOnQAppAvailable;
57Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
59QLibrarySettings::QLibrarySettings() : paths(
false), reloadOnQAppAvailable(
false)
64QSettings *QLibrarySettings::configuration()
66 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
68 return settings.get();
71bool QLibrarySettings::havePaths()
73 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
78void QLibrarySettings::load()
81 settings = findConfiguration();
82 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
87 QStringList children = settings->childGroups();
88 paths = !children.contains(
"Platforms"_L1)
89 || children.contains(
"Paths"_L1);
94const QString *qtconfManualPath =
nullptr;
97void QLibraryInfoPrivate::setQtconfManualPath(
const QString *path)
99 qtconfManualPath = path;
102static std::unique_ptr<QSettings> findConfiguration()
104 if (qtconfManualPath)
105 return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
107 QString qtconfig = QStringLiteral(
":/qt/etc/qt.conf");
108 if (QResource(qtconfig, QLocale::c()).isValid())
109 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
111 CFBundleRef bundleRef = CFBundleGetMainBundle();
113 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
114 QCFString(
"qt.conf"_L1),
118 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
119 qtconfig = QDir::cleanPath(path);
120 if (QFile::exists(qtconfig))
121 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
125 if (QCoreApplication::instanceExists()) {
126 QString pwd = QCoreApplication::applicationDirPath();
127 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR)
".conf"_s;
128 if (QFile::exists(qtconfig))
129 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
130 qtconfig = pwd + u"/qt.conf";
131 if (QFile::exists(qtconfig))
132 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
137QSettings *QLibraryInfoPrivate::configuration()
139 QLibrarySettings *ls = qt_library_settings();
140 return ls ? ls->configuration() :
nullptr;
143void QLibraryInfoPrivate::reload()
145 if (qt_library_settings.exists())
146 qt_library_settings->load();
149static bool havePaths() {
150 QLibrarySettings *ls = qt_library_settings();
151 return ls && ls->havePaths();
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
175
176
177
178
179
181QLibraryInfo::QLibraryInfo()
184#if defined(Q_CC_CLANG)
185# define COMPILER_STRING __VERSION__
186#elif defined(Q_CC_GHS)
187# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
188#elif defined(Q_CC_GNU)
189# define COMPILER_STRING "GCC " __VERSION__
190#elif defined(Q_CC_MSVC)
192# define COMPILER_STRING "MSVC 2015"
193# elif _MSC_VER < 1917
194# define COMPILER_STRING "MSVC 2017"
195# elif _MSC_VER < 1930
196# define COMPILER_STRING "MSVC 2019"
197# elif _MSC_VER < 2000
198# define COMPILER_STRING "MSVC 2022"
200# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
203# define COMPILER_STRING "<unknown compiler>"
206# define DEBUG_STRING " release"
208# define DEBUG_STRING " debug"
211# define SHARED_STRING " shared (dynamic)"
213# define SHARED_STRING " static"
221
222
223
224
225
226
228const char *QLibraryInfo::build()
noexcept
230 return qt_build_string();
234
235
236
237
239QLibraryInfo::isDebugBuild()
noexcept
249
250
251
252bool QLibraryInfo::isSharedBuild()
noexcept
262
263
264
265
266
267QVersionNumber QLibraryInfo::version()
noexcept
269 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
274 if (QCoreApplication::instanceExists()) {
276 CFBundleRef bundleRef = CFBundleGetMainBundle();
278 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
280 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
282 QString bundleContentsDir = QString(path) +
"/Contents/"_L1;
283 if (QDir(bundleContentsDir).exists())
284 return QDir::cleanPath(bundleContentsDir);
286 return QDir::cleanPath(QString(path));
292 return QCoreApplication::applicationDirPath();
294 return QDir::currentPath();
298#if QT_CONFIG(relocatable)
299#if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework))
300 && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
301static QString prefixFromQtCoreLibraryHelper(
const QString &qtCoreLibraryPath)
303 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
304 const QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
305 const QString prefixDir = libDir +
"/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
306 return QDir::cleanPath(prefixDir);
311static HMODULE getWindowsModuleHandle()
313 HMODULE hModule = NULL;
315 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
316 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
321static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
327#if defined(QT_STATIC)
328 prefixPath = prefixFromAppDirHelper();
329 if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) {
331 constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1);
332 constexpr size_t binDirLength = binDir.size() + 1;
333 prefixPath.chop(binDirLength);
335#elif defined(Q_OS_DARWIN) && QT_CONFIG(framework)
338 #define QT_LIBINFIX ""
340 auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR(
"org.qt-project.QtCore" QT_LIBINFIX));
347 auto allBundles = CFBundleGetAllBundles();
348 auto bundleCount = CFArrayGetCount(allBundles);
349 for (
int i = 0; i < bundleCount; ++i) {
350 auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i));
351 auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle));
352 auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
353 if (CFStringHasSuffix(path, CFSTR(
"/QtCore" QT_LIBINFIX
".framework"))) {
354 qtCoreBundle = bundle;
359 Q_ASSERT(qtCoreBundle);
361 QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle);
362 Q_ASSERT(qtCorePath);
364 QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath);
365 Q_ASSERT(qtCorePathAbsolute);
367 QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute);
369 const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle);
371 const QString prefixDir = QString(libDirCFString) +
"/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
373 prefixPath = QDir::cleanPath(prefixDir);
374#elif defined(Q_OS_WASM)
378 prefixPath = QStringLiteral(
"/");
379#elif QT_CONFIG(dlopen)
382 int result = dladdr(
reinterpret_cast<
void *>(&QLibraryInfo::isDebugBuild), &info);
383 if (result > 0 && info.dli_fname)
384 prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(info.dli_fname));
385#elif defined(Q_OS_WIN)
387 HMODULE hModule = getWindowsModuleHandle();
388 const int kBufferSize = 4096;
389 wchar_t buffer[kBufferSize];
390 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
391 const QString qtCoreFilePath = QString::fromWCharArray(buffer,
int(pathSize));
392 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
394 hModule =
reinterpret_cast<HMODULE>(QCoreApplicationPrivate::mainInstanceHandle);
395 pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
396 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer,
int(pathSize))).absolutePath();
397 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
401 const QString libdir = QString::fromLocal8Bit(
402 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
403 const QLatin1Char slash(
'/');
404#if defined(Q_CC_MINGW)
405 const QString implibPrefix = QStringLiteral(
"lib");
406 const QString implibSuffix = QStringLiteral(
".a");
408 const QString implibPrefix;
409 const QString implibSuffix = QStringLiteral(
".lib");
411 const QString qtCoreImpLibFileName = implibPrefix
412 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
413 const QString qtCoreImpLibPath = qtCoreDirPath
414 + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH
416 + slash + qtCoreImpLibFileName;
417 if (!QFileInfo::exists(qtCoreImpLibPath)) {
423 if (!qtCoreFilePath.isEmpty())
424 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
426#error "The chosen platform / config does not support querying for a dynamic prefix."
429#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
433 const QString libdir = QString::fromLocal8Bit(
434 qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1));
435 QDir prefixDir(prefixPath);
436 while (!prefixDir.exists(libdir)) {
438 prefixPath = prefixDir.absolutePath();
439 if (prefixDir.isRoot()) {
446 Q_ASSERT_X(!prefixPath.isEmpty(),
"getRelocatablePrefix",
447 "Failed to find the Qt prefix path.");
454#if QT_CONFIG(relocatable)
455 return getRelocatablePrefix(usageMode);
458 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
462QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc)
465
466
467
468
469
470 static constexpr auto qtConfEntries = qOffsetStringArray(
472 "Documentation",
"doc",
473 "Headers",
"include",
476 "LibraryExecutables",
"bin",
478 "LibraryExecutables",
"libexec",
481 "Plugins",
"plugins",
487 "Translations",
"translations",
488 "Examples",
"examples",
492 constexpr QByteArrayView dot{
"."};
496 if (
int(loc) < qtConfEntries.count()) {
497 result.key = QLatin1StringView(qtConfEntries.viewAt(loc * 2));
498 result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(loc * 2 + 1));
499 if (result.key == u"QmlImports")
500 result.fallbackKey = u"Qml2Imports"_s;
502 }
else if (loc == QLibraryInfo::SettingsPath) {
503 result.key =
"Settings"_L1;
504 result.defaultValue = QLatin1StringView(dot);
512
513
514
515
518
519
520
521
522
523
524
525QString QLibraryInfo::path(LibraryPath p)
527 return QLibraryInfoPrivate::path(p);
531
532
533
534
535
536QStringList QLibraryInfo::paths(LibraryPath p)
538 return QLibraryInfoPrivate::paths(p);
543#if QT_CONFIG(settings)
544 QSettings *config = QLibraryInfoPrivate::configuration();
545 Q_ASSERT(config !=
nullptr);
546 return config->value(
"Config/MergeQtConf",
false).toBool();
552#if QT_CONFIG(settings)
553static QString normalizePath(QString ret)
555 qsizetype startIndex = 0;
557
558
559
561 startIndex = ret.indexOf(u'$', startIndex);
564 if (ret.size() < startIndex + 3)
566 if (ret.at(startIndex + 1) != u'(') {
570 qsizetype endIndex = ret.indexOf(u')', startIndex + 2);
573 auto envVarName = QStringView{ret}.sliced(startIndex + 2, endIndex - startIndex - 2);
574 QString value = qEnvironmentVariable(envVarName.toLocal8Bit().constData());
575 ret.replace(startIndex, endIndex - startIndex + 1, value);
576 startIndex += value.size();
578 return QDir::fromNativeSeparators(ret);
581static QVariant libraryPathToValue(QLibraryInfo::LibraryPath loc)
584 auto li = QLibraryInfoPrivate::locationInfo(loc);
587 QSettings *config = QLibraryInfoPrivate::configuration();
588 Q_ASSERT(config !=
nullptr);
591 QVariant defaultValue = keepQtBuildDefaults()
593 : QVariant(li.defaultValue);
594 config->beginGroup(
"Paths"_L1);
595 auto cleanup = qScopeGuard([&]() { config->endGroup(); });
596 if (li.fallbackKey.isNull()) {
597 value = config->value(li.key, defaultValue);
599 value = config->value(li.key);
600 if (!value.isValid())
601 value = config->value(li.fallbackKey, defaultValue);
612 using FromInternalPath = QFileSystemEntry::FromInternalPath;
613 return !path.startsWith(
':'_L1) && QFileSystemEntry(path, FromInternalPath{}).isRelative();
618 using FromInternalPath = QFileSystemEntry::FromInternalPath;
619 return path.startsWith(
':'_L1) || QFileSystemEntry(path, FromInternalPath{}).isAbsolute();
622QStringList QLibraryInfoPrivate::paths(QLibraryInfo::LibraryPath p,
625 const QLibraryInfo::LibraryPath loc = p;
627 bool fromConf =
false;
628 bool pathsAreAbsolute =
true;
629#if QT_CONFIG(settings)
633 QVariant value = libraryPathToValue(loc);
634 if (value.isValid()) {
635 if (
auto *asList = get_if<QList<QString>>(&value))
636 ret = std::move(*asList);
638 ret = QList<QString>({ std::move(value).toString()});
639 for (qsizetype i = 0, end = ret.size(); i < end; ++i) {
640 ret[i] = normalizePath(ret[i]);
641 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(ret[i]);
647 if (!fromConf || keepQtBuildDefaults()) {
648 QString noConfResult;
649 if (loc == QLibraryInfo::PrefixPath) {
650 noConfResult = getPrefix(usageMode);
651 }
else if (
int(loc) <= qt_configure_strs.count()) {
652 noConfResult = QString::fromLocal8Bit(qt_configure_strs.viewAt(loc - 1));
654 }
else if (loc == QLibraryInfo::SettingsPath) {
659 const char *
volatile path = QT_CONFIGURE_SETTINGS_PATH;
660 noConfResult = QString::fromLocal8Bit(path);
663 if (!noConfResult.isEmpty()) {
664 pathsAreAbsolute = pathsAreAbsolute && pathIsAbsolute(noConfResult);
665 ret.push_back(std::move(noConfResult));
668 if (ret.isEmpty() || pathsAreAbsolute)
672 if (loc == QLibraryInfo::PrefixPath) {
673 baseDir = prefixFromAppDirHelper();
676 baseDir = QLibraryInfoPrivate::path(QLibraryInfo::PrefixPath, usageMode);
678 for (qsizetype i = 0, end = ret.size(); i < end; ++i)
679 if (pathIsRelative(ret[i]))
680 ret[i] = QDir::cleanPath(baseDir + u'/' + std::move(ret[i]));
685
686
687
688
689
690QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMode)
692 return paths(p, usageMode).value(0, QString());
696
697
698
699
700
701
702
703
704
705
706
708QStringList QLibraryInfo::platformPluginArguments(
const QString &platformName)
710#if QT_CONFIG(settings)
711 if (
const auto settings = findConfiguration()) {
712 const QString key =
"Platforms/"_L1
715 return settings->value(key).toStringList();
718 Q_UNUSED(platformName);
720 return QStringList();
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
750
751
752
755
756
757
758
759
760
761
762
763
764
767
768
769
770
771
772
773
774
776const char *qVersion()
noexcept
778 return QT_VERSION_STR;
781#if QT_DEPRECATED_SINCE(6
, 9
)
783bool qSharedBuild()
noexcept
785 return QLibraryInfo::isSharedBuild();
792#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
797#include "private/qcoreapplication_p.h"
799QT_WARNING_DISABLE_GCC(
"-Wformat-overflow")
800QT_WARNING_DISABLE_GCC(
"-Wattributes")
801QT_WARNING_DISABLE_CLANG(
"-Wattributes")
802QT_WARNING_DISABLE_INTEL(2621)
804# if defined(Q_OS_LINUX)
805# include "minimum-linux_p.h"
807# ifdef QT_ELF_NOTE_OS_TYPE
810 static_assert(
sizeof(Elf32_Nhdr) ==
sizeof(Elf64_Nhdr),
811 "The size of an ELF note is wrong (should be 12 bytes)");
813 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
814 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
815 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
816# ifdef QT_ELF_NOTE_OS_PATCH
817 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
821 Elf32_Nhdr header = {
822 .n_namesz =
sizeof(name),
823 .n_descsz =
sizeof(Payload),
824 .n_type = NT_GNU_ABI_TAG
826 char name[
sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU;
827 Payload payload = {};
829__attribute__((section(
".note.ABI-tag"), aligned(4), used))
830extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
833extern const char qt_core_interpreter[]
__attribute__((section(
".interp")))
836extern "C" void qt_core_boilerplate()
__attribute__((force_align_arg_pointer));
837void qt_core_boilerplate()
839 printf(
"This is the QtCore library version %s\n"
841 "Contact: https://www.qt.io/licensing/\n"
843 "Installation prefix: %s\n"
846 QT_PREPEND_NAMESPACE(qt_build_string)(),
848 QT_CONFIGURE_PREFIX_PATH,
849 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
850 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
852 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
static const char * qt_build_string() noexcept
static bool pathIsRelative(const QString &path)
static QString getPrefix(QLibraryInfoPrivate::UsageMode usageMode)
static bool pathIsAbsolute(const QString &path)
static QString prefixFromAppDirHelper()
static bool keepQtBuildDefaults()