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;
43#if QT_CONFIG(settings)
45static std::unique_ptr<QSettings> findConfiguration();
47struct QLibrarySettings
52 QSettings *configuration();
54 std::unique_ptr<QSettings> settings;
56 bool reloadOnQAppAvailable;
58Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
60QLibrarySettings::QLibrarySettings() : paths(
false), reloadOnQAppAvailable(
false)
65QSettings *QLibrarySettings::configuration()
67 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
69 return settings.get();
72bool QLibrarySettings::havePaths()
74 if (reloadOnQAppAvailable && QCoreApplication::instanceExists())
79void QLibrarySettings::load()
82 settings = findConfiguration();
83 reloadOnQAppAvailable = !settings && !QCoreApplication::instanceExists();
88 QStringList children = settings->childGroups();
89 paths = !children.contains(
"Platforms"_L1)
90 || children.contains(
"Paths"_L1);
95const QString *qtconfManualPath =
nullptr;
98void QLibraryInfoPrivate::setQtconfManualPath(
const QString *path)
100 qtconfManualPath = path;
103static std::unique_ptr<QSettings> findConfiguration()
105 if (qtconfManualPath)
106 return std::make_unique<QSettings>(*qtconfManualPath, QSettings::IniFormat);
108 QString qtconfig = QStringLiteral(
":/qt/etc/qt.conf");
109 if (QResource(qtconfig, QLocale::c()).isValid())
110 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
112 CFBundleRef bundleRef = CFBundleGetMainBundle();
114 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
115 QCFString(
"qt.conf"_L1),
119 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
120 qtconfig = QDir::cleanPath(path);
121 if (QFile::exists(qtconfig))
122 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
126 if (QCoreApplication::instanceExists()) {
127 QString pwd = QCoreApplication::applicationDirPath();
128 qtconfig = pwd + u"/qt" QT_STRINGIFY(QT_VERSION_MAJOR)
".conf"_s;
129 if (QFile::exists(qtconfig))
130 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
131 qtconfig = pwd + u"/qt.conf";
132 if (QFile::exists(qtconfig))
133 return std::make_unique<QSettings>(qtconfig, QSettings::IniFormat);
138QSettings *QLibraryInfoPrivate::configuration()
140 QLibrarySettings *ls = qt_library_settings();
141 return ls ? ls->configuration() :
nullptr;
144void QLibraryInfoPrivate::reload()
146 if (qt_library_settings.exists())
147 qt_library_settings->load();
150static bool havePaths() {
151 QLibrarySettings *ls = qt_library_settings();
152 return ls && ls->havePaths();
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
178
179
180
181
182
184QLibraryInfo::QLibraryInfo()
187#if defined(Q_CC_CLANG)
188# define COMPILER_STRING __VERSION__
189#elif defined(Q_CC_GHS)
190# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
191#elif defined(Q_CC_GNU)
192# define COMPILER_STRING "GCC " __VERSION__
193#elif defined(Q_CC_MSVC)
195# define COMPILER_STRING "MSVC 2015"
196# elif _MSC_VER < 1917
197# define COMPILER_STRING "MSVC 2017"
198# elif _MSC_VER < 1930
199# define COMPILER_STRING "MSVC 2019"
200# elif _MSC_VER < 1950
201# define COMPILER_STRING "MSVC 2022"
202# elif _MSC_VER < 2000
203# define COMPILER_STRING "MSVC 2026"
205# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
208# define COMPILER_STRING "<unknown compiler>"
211# define DEBUG_STRING " release"
213# define DEBUG_STRING " debug"
216# define SHARED_STRING " shared (dynamic)"
218# define SHARED_STRING " static"
226
227
228
229
230
231
233const char *QLibraryInfo::build()
noexcept
235 return qt_build_string();
239
240
241
242
244QLibraryInfo::isDebugBuild()
noexcept
254
255
256
257bool QLibraryInfo::isSharedBuild()
noexcept
267
268
269
270
271
272QVersionNumber QLibraryInfo::version()
noexcept
274 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
278
279
280
281
282
283
286#if defined(Q_OS_DARWIN)
294 if (CFBundleRef bundleRef = CFBundleGetMainBundle()) {
295 if (QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef)) {
296 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
297#if defined(Q_OS_MACOS)
298 QString bundleContentsDir = QString(path) +
"/Contents/"_L1;
299 if (QFileInfo::exists(bundleContentsDir))
300 return QDir::cleanPath(bundleContentsDir);
302 return QDir::cleanPath(QString(path));
308 if (QCoreApplication::instanceExists()) {
310 return QCoreApplication::applicationDirPath();
312 return QDir::currentPath();
316#if QT_CONFIG(relocatable)
317#if !defined(QT_STATIC) && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
318static QString prefixFromQtCoreLibraryHelper(
const QString &qtCoreLibraryPath)
320 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
321 QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
323#if QT_CONFIG(framework)
324# if defined(Q_OS_MACOS)
326 libDir +=
"/../.."_L1;
332 const QString prefixDir = libDir +
"/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
333 return QDir::cleanPath(prefixDir);
338static HMODULE getWindowsModuleHandle()
340 HMODULE hModule = NULL;
342 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
343 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
348static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
354#if defined(QT_STATIC)
355# if defined(Q_OS_APPLE)
364 if (!qt_apple_isSandboxed())
365 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
367 prefixPath = prefixFromAppDirHelper();
368 if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) {
370 constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1);
371 constexpr size_t binDirLength = binDir.size() + 1;
372 prefixPath.chop(binDirLength);
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
763
764
765
766
767
768
769
770
771
772
775
776
777
778
779
780
781
782
784const char *qVersion()
noexcept
786 return QT_VERSION_STR;
789#if QT_DEPRECATED_SINCE(6
, 9
)
791bool qSharedBuild()
noexcept
793 return QLibraryInfo::isSharedBuild();
800#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
805#include "private/qcoreapplication_p.h"
807QT_WARNING_DISABLE_GCC(
"-Wformat-overflow")
808QT_WARNING_DISABLE_GCC(
"-Wattributes")
809QT_WARNING_DISABLE_CLANG(
"-Wattributes")
810QT_WARNING_DISABLE_INTEL(2621)
812# if defined(Q_OS_LINUX)
813# include "minimum-linux_p.h"
815# ifdef QT_ELF_NOTE_OS_TYPE
818 static_assert(
sizeof(Elf32_Nhdr) ==
sizeof(Elf64_Nhdr),
819 "The size of an ELF note is wrong (should be 12 bytes)");
821 Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE;
822 Elf32_Word major = QT_ELF_NOTE_OS_MAJOR;
823 Elf32_Word minor = QT_ELF_NOTE_OS_MINOR;
824# ifdef QT_ELF_NOTE_OS_PATCH
825 Elf32_Word patch = QT_ELF_NOTE_OS_PATCH;
829 Elf32_Nhdr header = {
830 .n_namesz =
sizeof(name),
831 .n_descsz =
sizeof(Payload),
832 .n_type = NT_GNU_ABI_TAG
834 char name[
sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU;
835 Payload payload = {};
837__attribute__((section(
".note.ABI-tag"), aligned(4), used))
838extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {};
841extern const char qt_core_interpreter[]
__attribute__((section(
".interp")))
844extern "C" void qt_core_boilerplate()
__attribute__((force_align_arg_pointer));
845void qt_core_boilerplate()
847 printf(
"This is the QtCore library version %s\n"
849 "Contact: https://www.qt.io/licensing/\n"
851 "Installation prefix: %s\n"
854 QT_PREPEND_NAMESPACE(qt_build_string)(),
856 QT_CONFIGURE_PREFIX_PATH,
857 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
858 qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
860 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()