1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qdir.h"
42#include "qstringlist.h"
43#include "qfile.h"
44#if QT_CONFIG(settings)
45#include "qsettings.h"
46#endif
47#include "qlibraryinfo.h"
48#include "qscopedpointer.h"
49
50#ifdef QT_BUILD_QMAKE
51QT_BEGIN_NAMESPACE
52extern QString qmake_libraryInfoFile();
53QT_END_NAMESPACE
54#else
55# include "qcoreapplication.h"
56#endif
57
58#ifndef QT_BUILD_QMAKE_BOOTSTRAP
59# include "private/qglobal_p.h"
60# include "qconfig.cpp"
61#endif
62
63#ifdef Q_OS_DARWIN
64# include "private/qcore_mac_p.h"
65#endif // Q_OS_DARWIN
66
67#include "archdetect.cpp"
68
69#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(relocatable) && QT_CONFIG(dlopen) && !QT_CONFIG(framework)
70# include <dlfcn.h>
71#endif
72
73#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(relocatable) && defined(Q_OS_WIN)
74# include <qt_windows.h>
75#endif
76
77QT_BEGIN_NAMESPACE
78
79extern void qDumpCPUFeatures(); // in qsimd.cpp
80
81#if QT_CONFIG(settings)
82
83struct QLibrarySettings
84{
85 QLibrarySettings();
86 void load();
87
88 QScopedPointer<QSettings> settings;
89#ifdef QT_BUILD_QMAKE
90 bool haveDevicePaths;
91 bool haveEffectiveSourcePaths;
92 bool haveEffectivePaths;
93 bool havePaths;
94#else
95 bool reloadOnQAppAvailable;
96#endif
97};
98Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
99
100class QLibraryInfoPrivate
101{
102public:
103 static QSettings *findConfiguration();
104#ifdef QT_BUILD_QMAKE
105 static void reload()
106 {
107 if (qt_library_settings.exists())
108 qt_library_settings->load();
109 }
110 static bool haveGroup(QLibraryInfo::PathGroup group)
111 {
112 QLibrarySettings *ls = qt_library_settings();
113 return ls ? (group == QLibraryInfo::EffectiveSourcePaths
114 ? ls->haveEffectiveSourcePaths
115 : group == QLibraryInfo::EffectivePaths
116 ? ls->haveEffectivePaths
117 : group == QLibraryInfo::DevicePaths
118 ? ls->haveDevicePaths
119 : ls->havePaths) : false;
120 }
121#endif
122 static QSettings *configuration()
123 {
124 QLibrarySettings *ls = qt_library_settings();
125 if (ls) {
126#ifndef QT_BUILD_QMAKE
127 if (ls->reloadOnQAppAvailable && QCoreApplication::instance() != nullptr)
128 ls->load();
129#endif
130 return ls->settings.data();
131 } else {
132 return nullptr;
133 }
134 }
135};
136
137static const char platformsSection[] = "Platforms";
138
139QLibrarySettings::QLibrarySettings()
140{
141 load();
142}
143
144void QLibrarySettings::load()
145{
146 // If we get any settings here, those won't change when the application shows up.
147 settings.reset(other: QLibraryInfoPrivate::findConfiguration());
148#ifndef QT_BUILD_QMAKE
149 reloadOnQAppAvailable = (settings.data() == nullptr && QCoreApplication::instance() == nullptr);
150 bool haveDevicePaths;
151 bool haveEffectivePaths;
152 bool havePaths;
153#endif
154 if (settings) {
155 // This code needs to be in the regular library, as otherwise a qt.conf that
156 // works for qmake would break things for dynamically built Qt tools.
157 QStringList children = settings->childGroups();
158 haveDevicePaths = children.contains(str: QLatin1String("DevicePaths"));
159#ifdef QT_BUILD_QMAKE
160 haveEffectiveSourcePaths = children.contains(QLatin1String("EffectiveSourcePaths"));
161#else
162 // EffectiveSourcePaths is for the Qt build only, so needs no backwards compat trickery.
163 bool haveEffectiveSourcePaths = false;
164#endif
165 haveEffectivePaths = haveEffectiveSourcePaths || children.contains(str: QLatin1String("EffectivePaths"));
166 // Backwards compat: an existing but empty file is claimed to contain the Paths section.
167 havePaths = (!haveDevicePaths && !haveEffectivePaths
168 && !children.contains(str: QLatin1String(platformsSection)))
169 || children.contains(str: QLatin1String("Paths"));
170#ifndef QT_BUILD_QMAKE
171 if (!havePaths)
172 settings.reset(other: nullptr);
173#else
174 } else {
175 haveDevicePaths = false;
176 haveEffectiveSourcePaths = false;
177 haveEffectivePaths = false;
178 havePaths = false;
179#endif
180 }
181}
182
183QSettings *QLibraryInfoPrivate::findConfiguration()
184{
185#ifdef QT_BUILD_QMAKE
186 QString qtconfig = qmake_libraryInfoFile();
187 if (QFile::exists(qtconfig))
188 return new QSettings(qtconfig, QSettings::IniFormat);
189#else
190 QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
191 if (QFile::exists(fileName: qtconfig))
192 return new QSettings(qtconfig, QSettings::IniFormat);
193#ifdef Q_OS_DARWIN
194 CFBundleRef bundleRef = CFBundleGetMainBundle();
195 if (bundleRef) {
196 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
197 QCFString(QLatin1String("qt.conf")),
198 0,
199 0);
200 if (urlRef) {
201 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
202 qtconfig = QDir::cleanPath(path);
203 if (QFile::exists(qtconfig))
204 return new QSettings(qtconfig, QSettings::IniFormat);
205 }
206 }
207#endif
208 if (QCoreApplication::instance()) {
209 QDir pwd(QCoreApplication::applicationDirPath());
210 qtconfig = pwd.filePath(fileName: QLatin1String("qt.conf"));
211 if (QFile::exists(fileName: qtconfig))
212 return new QSettings(qtconfig, QSettings::IniFormat);
213 }
214#endif
215 return nullptr; //no luck
216}
217
218#endif // settings
219
220/*!
221 \class QLibraryInfo
222 \inmodule QtCore
223 \brief The QLibraryInfo class provides information about the Qt library.
224
225 Many pieces of information are established when Qt is configured and built.
226 This class provides an abstraction for accessing that information.
227 By using the static functions of this class, an application can obtain
228 information about the instance of the Qt library which the application
229 is using at run-time.
230
231 You can also use a \c qt.conf file to override the hard-coded paths
232 that are compiled into the Qt library. For more information, see
233 the \l {Using qt.conf} documentation.
234
235 \sa QSysInfo, {Using qt.conf}
236*/
237
238#ifndef QT_BUILD_QMAKE
239
240/*!
241 \internal
242
243 You cannot create a QLibraryInfo, instead only the static functions are available to query
244 information.
245*/
246
247QLibraryInfo::QLibraryInfo()
248{ }
249
250/*!
251 \deprecated
252 This function used to return the person to whom this build of Qt is licensed, now returns an empty string.
253*/
254
255#if QT_DEPRECATED_SINCE(5, 8)
256QString
257QLibraryInfo::licensee()
258{
259 return QString();
260}
261#endif
262
263/*!
264 \deprecated
265 This function used to return the products that the license for this build of Qt has access to, now returns an empty string.
266*/
267
268#if QT_DEPRECATED_SINCE(5, 8)
269QString
270QLibraryInfo::licensedProducts()
271{
272 return QString();
273}
274#endif
275
276/*!
277 \since 4.6
278 \deprecated
279 This function used to return the installation date for this build of Qt, but now returns a constant date.
280*/
281#if QT_CONFIG(datestring)
282#if QT_DEPRECATED_SINCE(5, 5)
283QDate
284QLibraryInfo::buildDate()
285{
286 return QDate::fromString(s: QString::fromLatin1(str: "2012-12-20"), f: Qt::ISODate);
287}
288#endif
289#endif // datestring
290
291#if defined(Q_CC_INTEL) // must be before GNU, Clang and MSVC because ICC/ICL claim to be them
292# ifdef __INTEL_CLANG_COMPILER
293# define ICC_COMPAT "Clang"
294# elif defined(__INTEL_MS_COMPAT_LEVEL)
295# define ICC_COMPAT "Microsoft"
296# elif defined(__GNUC__)
297# define ICC_COMPAT "GCC"
298# else
299# define ICC_COMPAT "no"
300# endif
301# if __INTEL_COMPILER == 1300
302# define ICC_VERSION "13.0"
303# elif __INTEL_COMPILER == 1310
304# define ICC_VERSION "13.1"
305# elif __INTEL_COMPILER == 1400
306# define ICC_VERSION "14.0"
307# elif __INTEL_COMPILER == 1500
308# define ICC_VERSION "15.0"
309# else
310# define ICC_VERSION QT_STRINGIFY(__INTEL_COMPILER)
311# endif
312# ifdef __INTEL_COMPILER_UPDATE
313# define COMPILER_STRING "Intel(R) C++ " ICC_VERSION "." QT_STRINGIFY(__INTEL_COMPILER_UPDATE) \
314 " build " QT_STRINGIFY(__INTEL_COMPILER_BUILD_DATE) " [" \
315 ICC_COMPAT " compatibility]"
316# else
317# define COMPILER_STRING "Intel(R) C++ " ICC_VERSION \
318 " build " QT_STRINGIFY(__INTEL_COMPILER_BUILD_DATE) " [" \
319 ICC_COMPAT " compatibility]"
320# endif
321#elif defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
322# ifdef __apple_build_version__ // Apple clang has other version numbers
323# define COMPILER_STRING "Clang " __clang_version__ " (Apple)"
324# else
325# define COMPILER_STRING "Clang " __clang_version__
326# endif
327#elif defined(Q_CC_GHS)
328# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
329#elif defined(Q_CC_GNU)
330# define COMPILER_STRING "GCC " __VERSION__
331#elif defined(Q_CC_MSVC)
332# if _MSC_VER < 1910
333# define COMPILER_STRING "MSVC 2015"
334# elif _MSC_VER < 1917
335# define COMPILER_STRING "MSVC 2017"
336# elif _MSC_VER < 1930
337# define COMPILER_STRING "MSVC 2019"
338# elif _MSC_VER < 2000
339# define COMPILER_STRING "MSVC 2022"
340# else
341# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
342# endif
343#else
344# define COMPILER_STRING "<unknown compiler>"
345#endif
346#ifdef QT_NO_DEBUG
347# define DEBUG_STRING " release"
348#else
349# define DEBUG_STRING " debug"
350#endif
351#ifdef QT_SHARED
352# define SHARED_STRING " shared (dynamic)"
353#else
354# define SHARED_STRING " static"
355#endif
356#define QT_BUILD_STR "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")"
357
358/*!
359 Returns a string describing how this version of Qt was built.
360
361 \internal
362
363 \since 5.3
364*/
365
366const char *QLibraryInfo::build() noexcept
367{
368 return QT_BUILD_STR;
369}
370
371/*!
372 \since 5.0
373 Returns \c true if this build of Qt was built with debugging enabled, or
374 false if it was built in release mode.
375*/
376bool
377QLibraryInfo::isDebugBuild()
378{
379#ifdef QT_DEBUG
380 return true;
381#else
382 return false;
383#endif
384}
385
386#ifndef QT_BOOTSTRAPPED
387/*!
388 \since 5.8
389 Returns the version of the Qt library.
390
391 \sa qVersion()
392*/
393QVersionNumber QLibraryInfo::version() noexcept
394{
395 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
396}
397#endif // QT_BOOTSTRAPPED
398
399#endif // QT_BUILD_QMAKE
400
401/*
402 * To add a new entry in QLibrary::LibraryLocation, add it to the enum above the bootstrapped values and:
403 * - add its relative path in the qtConfEntries[] array below
404 * (the key is what appears in a qt.conf file)
405 * - add a property name in qmake/property.cpp propList[] array
406 * (it's used with qmake -query)
407 * - add to qt_config.prf, qt_module.prf, qt_module_fwdpri.prf
408 */
409
410static const struct {
411 char key[19], value[13];
412} qtConfEntries[] = {
413 { .key: "Prefix", .value: "." },
414 { .key: "Documentation", .value: "doc" }, // should be ${Data}/doc
415 { .key: "Headers", .value: "include" },
416 { .key: "Libraries", .value: "lib" },
417#ifdef Q_OS_WIN
418 { "LibraryExecutables", "bin" },
419#else
420 { .key: "LibraryExecutables", .value: "libexec" }, // should be ${ArchData}/libexec
421#endif
422 { .key: "Binaries", .value: "bin" },
423 { .key: "Plugins", .value: "plugins" }, // should be ${ArchData}/plugins
424 { .key: "Imports", .value: "imports" }, // should be ${ArchData}/imports
425 { .key: "Qml2Imports", .value: "qml" }, // should be ${ArchData}/qml
426 { .key: "ArchData", .value: "." },
427 { .key: "Data", .value: "." },
428 { .key: "Translations", .value: "translations" }, // should be ${Data}/translations
429 { .key: "Examples", .value: "examples" },
430 { .key: "Tests", .value: "tests" },
431#ifdef QT_BUILD_QMAKE
432 { "Sysroot", "" },
433 { "SysrootifyPrefix", "" },
434 { "HostBinaries", "bin" },
435 { "HostLibraries", "lib" },
436 { "HostData", "." },
437 { "TargetSpec", "" },
438 { "HostSpec", "" },
439 { "HostPrefix", "" },
440#endif
441};
442
443#ifdef QT_BUILD_QMAKE
444void QLibraryInfo::reload()
445{
446 QLibraryInfoPrivate::reload();
447}
448
449void QLibraryInfo::sysrootify(QString *path)
450{
451 if (!QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool())
452 return;
453
454 const QString sysroot = rawLocation(SysrootPath, FinalPaths);
455 if (sysroot.isEmpty())
456 return;
457
458 if (path->length() > 2 && path->at(1) == QLatin1Char(':')
459 && (path->at(2) == QLatin1Char('/') || path->at(2) == QLatin1Char('\\'))) {
460 path->replace(0, 2, sysroot); // Strip out the drive on Windows targets
461 } else {
462 path->prepend(sysroot);
463 }
464}
465#endif // QT_BUILD_QMAKE
466
467#ifndef QT_BUILD_QMAKE
468static QString prefixFromAppDirHelper()
469{
470 QString appDir;
471
472 if (QCoreApplication::instance()) {
473#ifdef Q_OS_DARWIN
474 CFBundleRef bundleRef = CFBundleGetMainBundle();
475 if (bundleRef) {
476 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
477 if (urlRef) {
478 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
479#ifdef Q_OS_MACOS
480 QString bundleContentsDir = QString(path) + QLatin1String("/Contents/");
481 if (QDir(bundleContentsDir).exists())
482 return QDir::cleanPath(bundleContentsDir);
483#else
484 return QDir::cleanPath(QString(path)); // iOS
485#endif // Q_OS_MACOS
486 }
487 }
488#endif // Q_OS_DARWIN
489 // We make the prefix path absolute to the executable's directory.
490 appDir = QCoreApplication::applicationDirPath();
491 } else {
492 appDir = QDir::currentPath();
493 }
494
495 return appDir;
496}
497#endif
498
499#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(relocatable)
500#if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework)) \
501 && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
502static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
503{
504 const QString qtCoreLibrary = QDir::fromNativeSeparators(pathName: qtCoreLibraryPath);
505 const QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
506 const QString prefixDir = libDir + QLatin1Char('/')
507 + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH);
508 return QDir::cleanPath(path: prefixDir);
509}
510#endif
511
512#if defined(Q_OS_WIN)
513#if defined(Q_OS_WINRT)
514EXTERN_C IMAGE_DOS_HEADER __ImageBase;
515static HMODULE getWindowsModuleHandle()
516{
517 return reinterpret_cast<HMODULE>(&__ImageBase);
518}
519#else // Q_OS_WINRT
520static HMODULE getWindowsModuleHandle()
521{
522 HMODULE hModule = NULL;
523 GetModuleHandleEx(
524 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
525 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
526 return hModule;
527}
528#endif // !Q_OS_WINRT
529#endif // Q_OS_WIN
530
531static QString getRelocatablePrefix()
532{
533 QString prefixPath;
534
535 // For static builds, the prefix will be the app directory.
536 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
537#if defined(QT_STATIC)
538 prefixPath = prefixFromAppDirHelper();
539#elif defined(Q_OS_DARWIN) && QT_CONFIG(framework)
540#ifndef QT_LIBINFIX
541 #define QT_LIBINFIX ""
542#endif
543 auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtCore" QT_LIBINFIX));
544 if (!qtCoreBundle) {
545 // When running Qt apps over Samba shares, CoreFoundation will fail to find
546 // the Resources directory inside the bundle, This directory is a symlink,
547 // and CF relies on readdir() and dtent.dt_type to detect symlinks, which
548 // does not work reliably for Samba shares. We work around it by manually
549 // looking for the QtCore bundle.
550 auto allBundles = CFBundleGetAllBundles();
551 auto bundleCount = CFArrayGetCount(allBundles);
552 for (int i = 0; i < bundleCount; ++i) {
553 auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i));
554 auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle));
555 auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
556 if (CFStringHasSuffix(path, CFSTR("/QtCore" QT_LIBINFIX ".framework"))) {
557 qtCoreBundle = bundle;
558 break;
559 }
560 }
561 }
562 Q_ASSERT(qtCoreBundle);
563
564 QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle);
565 Q_ASSERT(qtCorePath);
566
567 QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath);
568 Q_ASSERT(qtCorePathAbsolute);
569
570 QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute);
571
572 const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle);
573
574 const QString prefixDir = QString(libDirCFString) + QLatin1Char('/')
575 + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH);
576
577 prefixPath = QDir::cleanPath(prefixDir);
578#elif QT_CONFIG(dlopen)
579 Dl_info info;
580 int result = dladdr(address: reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), info: &info);
581 if (result > 0 && info.dli_fname)
582 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreLibraryPath: QString::fromLocal8Bit(str: info.dli_fname));
583#elif defined(Q_OS_WIN)
584 HMODULE hModule = getWindowsModuleHandle();
585 const int kBufferSize = 4096;
586 wchar_t buffer[kBufferSize];
587 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
588 const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize));
589 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
590 pathSize = GetModuleFileName(NULL, buffer, kBufferSize);
591 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath();
592 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
593 // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an
594 // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking
595 // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib.
596 const QString libdir = QString::fromLocal8Bit(
597 qt_configure_strs + qt_configure_str_offsets[QLibraryInfo::LibrariesPath - 1]);
598 const QLatin1Char slash('/');
599#if defined(Q_CC_MINGW)
600 const QString implibPrefix = QStringLiteral("lib");
601 const QString implibSuffix = QStringLiteral(".a");
602#else
603 const QString implibPrefix;
604 const QString implibSuffix = QStringLiteral(".lib");
605#endif
606 const QString qtCoreImpLibFileName = implibPrefix
607 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
608 const QString qtCoreImpLibPath = qtCoreDirPath
609 + slash + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH)
610 + slash + libdir
611 + slash + qtCoreImpLibFileName;
612 if (!QFileInfo::exists(qtCoreImpLibPath)) {
613 // We did not find a corresponding import library and conclude that this is a
614 // windeployqt'ed executable.
615 return exeDirPath;
616 }
617 }
618 if (!qtCoreFilePath.isEmpty())
619 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
620#else
621#error "The chosen platform / config does not support querying for a dynamic prefix."
622#endif
623
624#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
625 // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir.
626 // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0
627 // changelog regarding SSE2 support.
628 const QString libdir = QString::fromLocal8Bit(
629 str: qt_configure_strs + qt_configure_str_offsets[QLibraryInfo::LibrariesPath - 1]);
630 QDir prefixDir(prefixPath);
631 while (!prefixDir.exists(name: libdir)) {
632 prefixDir.cdUp();
633 prefixPath = prefixDir.absolutePath();
634 if (prefixDir.isRoot()) {
635 prefixPath.clear();
636 break;
637 }
638 }
639#endif
640
641 Q_ASSERT_X(!prefixPath.isEmpty(), "getRelocatablePrefix",
642 "Failed to find the Qt prefix path.");
643 return prefixPath;
644}
645#endif
646
647#if defined(QT_BUILD_QMAKE) && !defined(QT_BUILD_QMAKE_BOOTSTRAP)
648QString qmake_abslocation();
649
650static QString getPrefixFromHostBinDir(const char *hostBinDirToPrefixPath)
651{
652 const QFileInfo qmfi = QFileInfo(qmake_abslocation()).canonicalFilePath();
653 return QDir::cleanPath(qmfi.absolutePath() + QLatin1Char('/')
654 + QLatin1String(hostBinDirToPrefixPath));
655}
656
657static QString getExtPrefixFromHostBinDir()
658{
659 return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH);
660}
661
662static QString getHostPrefixFromHostBinDir()
663{
664 return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH);
665}
666#endif
667
668#ifndef QT_BUILD_QMAKE_BOOTSTRAP
669static QString getPrefix(
670#ifdef QT_BUILD_QMAKE
671 QLibraryInfo::PathGroup group
672#endif
673 )
674{
675#if defined(QT_BUILD_QMAKE)
676# if QT_CONFIGURE_CROSSBUILD
677 if (group == QLibraryInfo::DevicePaths)
678 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
679# endif
680 return getExtPrefixFromHostBinDir();
681#elif QT_CONFIG(relocatable)
682 return getRelocatablePrefix();
683#else
684 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
685#endif
686}
687#endif // QT_BUILD_QMAKE_BOOTSTRAP
688
689/*!
690 Returns the location specified by \a loc.
691*/
692QString
693QLibraryInfo::location(LibraryLocation loc)
694{
695#ifdef QT_BUILD_QMAKE // ends inside rawLocation !
696 QString ret = rawLocation(loc, FinalPaths);
697
698 // Automatically prepend the sysroot to target paths
699 if (loc < SysrootPath || loc > LastHostPath)
700 sysrootify(&ret);
701
702 return ret;
703}
704
705QString
706QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group)
707{
708#endif // QT_BUILD_QMAKE, started inside location !
709 QString ret;
710 bool fromConf = false;
711#if QT_CONFIG(settings)
712#ifdef QT_BUILD_QMAKE
713 // Logic for choosing the right data source: if EffectivePaths are requested
714 // and qt.conf with that section is present, use it, otherwise fall back to
715 // FinalPaths. For FinalPaths, use qt.conf if present and contains not only
716 // [EffectivePaths], otherwise fall back to builtins.
717 // EffectiveSourcePaths falls back to EffectivePaths.
718 // DevicePaths falls back to FinalPaths.
719 PathGroup orig_group = group;
720 if (QLibraryInfoPrivate::haveGroup(group)
721 || (group == EffectiveSourcePaths
722 && (group = EffectivePaths, QLibraryInfoPrivate::haveGroup(group)))
723 || ((group == EffectivePaths || group == DevicePaths)
724 && (group = FinalPaths, QLibraryInfoPrivate::haveGroup(group)))
725 || (group = orig_group, false))
726#else
727 if (QLibraryInfoPrivate::configuration())
728#endif
729 {
730 fromConf = true;
731
732 QString key;
733 QString defaultValue;
734 if (unsigned(loc) < sizeof(qtConfEntries)/sizeof(qtConfEntries[0])) {
735 key = QLatin1String(qtConfEntries[loc].key);
736 defaultValue = QLatin1String(qtConfEntries[loc].value);
737 }
738#ifndef Q_OS_WIN // On Windows we use the registry
739 else if (loc == SettingsPath) {
740 key = QLatin1String("Settings");
741 defaultValue = QLatin1String(".");
742 }
743#endif
744
745 if(!key.isNull()) {
746 QSettings *config = QLibraryInfoPrivate::configuration();
747 config->beginGroup(prefix: QLatin1String(
748#ifdef QT_BUILD_QMAKE
749 group == DevicePaths ? "DevicePaths" :
750 group == EffectiveSourcePaths ? "EffectiveSourcePaths" :
751 group == EffectivePaths ? "EffectivePaths" :
752#endif
753 "Paths"));
754
755 ret = config->value(key, defaultValue).toString();
756
757#ifdef QT_BUILD_QMAKE
758 if (ret.isEmpty()) {
759 if (loc == HostPrefixPath)
760 ret = config->value(QLatin1String(qtConfEntries[PrefixPath].key),
761 QLatin1String(qtConfEntries[PrefixPath].value)).toString();
762 else if (loc == TargetSpecPath || loc == HostSpecPath || loc == SysrootifyPrefixPath)
763 fromConf = false;
764 // The last case here is SysrootPath, which can be legitimately empty.
765 // All other keys have non-empty fallbacks to start with.
766 }
767#endif
768
769 int startIndex = 0;
770 forever {
771 startIndex = ret.indexOf(c: QLatin1Char('$'), from: startIndex);
772 if (startIndex < 0)
773 break;
774 if (ret.length() < startIndex + 3)
775 break;
776 if (ret.at(i: startIndex + 1) != QLatin1Char('(')) {
777 startIndex++;
778 continue;
779 }
780 int endIndex = ret.indexOf(c: QLatin1Char(')'), from: startIndex + 2);
781 if (endIndex < 0)
782 break;
783 QStringRef envVarName = ret.midRef(position: startIndex + 2, n: endIndex - startIndex - 2);
784 QString value = QString::fromLocal8Bit(str: qgetenv(varName: envVarName.toLocal8Bit().constData()));
785 ret.replace(i: startIndex, len: endIndex - startIndex + 1, after: value);
786 startIndex += value.length();
787 }
788
789 config->endGroup();
790
791 ret = QDir::fromNativeSeparators(pathName: ret);
792 }
793 }
794#endif // settings
795
796#ifndef QT_BUILD_QMAKE_BOOTSTRAP
797 if (!fromConf) {
798 // "volatile" here is a hack to prevent compilers from doing a
799 // compile-time strlen() on "path". The issue is that Qt installers
800 // will binary-patch the Qt installation paths -- in such scenarios, Qt
801 // will be built with a dummy path, thus the compile-time result of
802 // strlen is meaningless.
803 const char * volatile path = nullptr;
804 if (loc == PrefixPath) {
805 ret = getPrefix(
806#ifdef QT_BUILD_QMAKE
807 group
808#endif
809 );
810 } else if (unsigned(loc) <= sizeof(qt_configure_str_offsets)/sizeof(qt_configure_str_offsets[0])) {
811 path = qt_configure_strs + qt_configure_str_offsets[loc - 1];
812#ifndef Q_OS_WIN // On Windows we use the registry
813 } else if (loc == SettingsPath) {
814 path = QT_CONFIGURE_SETTINGS_PATH;
815#endif
816# ifdef QT_BUILD_QMAKE
817 } else if (loc == HostPrefixPath) {
818 static const QByteArray hostPrefixPath = getHostPrefixFromHostBinDir().toLatin1();
819 path = hostPrefixPath.constData();
820# endif
821 }
822
823 if (path)
824 ret = QString::fromLocal8Bit(str: path);
825 }
826#endif
827
828#ifdef QT_BUILD_QMAKE
829 // These values aren't actually paths and thus need to be returned verbatim.
830 if (loc == TargetSpecPath || loc == HostSpecPath || loc == SysrootifyPrefixPath)
831 return ret;
832#endif
833
834 if (!ret.isEmpty() && QDir::isRelativePath(path: ret)) {
835 QString baseDir;
836#ifdef QT_BUILD_QMAKE
837 if (loc == HostPrefixPath || loc == PrefixPath || loc == SysrootPath) {
838 // We make the prefix/sysroot path absolute to the executable's directory.
839 // loc == PrefixPath while a sysroot is set would make no sense here.
840 // loc == SysrootPath only makes sense if qmake lives inside the sysroot itself.
841 baseDir = QFileInfo(qmake_libraryInfoFile()).absolutePath();
842 } else if (loc > SysrootPath && loc <= LastHostPath) {
843 // We make any other host path absolute to the host prefix directory.
844 baseDir = rawLocation(HostPrefixPath, group);
845 } else {
846 // we make any other path absolute to the prefix directory
847 baseDir = rawLocation(PrefixPath, group);
848 if (group == EffectivePaths)
849 sysrootify(&baseDir);
850 }
851#else
852 if (loc == PrefixPath) {
853 baseDir = prefixFromAppDirHelper();
854 } else {
855 // we make any other path absolute to the prefix directory
856 baseDir = location(loc: PrefixPath);
857 }
858#endif // QT_BUILD_QMAKE
859 ret = QDir::cleanPath(path: baseDir + QLatin1Char('/') + ret);
860 }
861 return ret;
862}
863
864/*!
865 Returns additional arguments to the platform plugin matching
866 \a platformName which can be specified as a string list using
867 the key \c Arguments in a group called \c Platforms of the
868 \c qt.conf file.
869
870 sa {Using qt.conf}
871
872 \internal
873
874 \since 5.3
875*/
876
877QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
878{
879#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(settings)
880 QScopedPointer<const QSettings> settings(QLibraryInfoPrivate::findConfiguration());
881 if (!settings.isNull()) {
882 const QString key = QLatin1String(platformsSection)
883 + QLatin1Char('/')
884 + platformName
885 + QLatin1String("Arguments");
886 return settings->value(key).toStringList();
887 }
888#else
889 Q_UNUSED(platformName);
890#endif // !QT_BUILD_QMAKE && settings
891 return QStringList();
892}
893
894/*!
895 \enum QLibraryInfo::LibraryLocation
896
897 \keyword library location
898
899 This enum type is used to specify a specific location
900 specifier:
901
902 \value PrefixPath The default prefix for all paths.
903 \value DocumentationPath The location for documentation upon install.
904 \value HeadersPath The location for all headers.
905 \value LibrariesPath The location of installed libraries.
906 \value LibraryExecutablesPath The location of installed executables required by libraries at runtime.
907 \value BinariesPath The location of installed Qt binaries (tools and applications).
908 \value PluginsPath The location of installed Qt plugins.
909 \value ImportsPath The location of installed QML extensions to import (QML 1.x).
910 \value Qml2ImportsPath The location of installed QML extensions to import (QML 2.x).
911 \value ArchDataPath The location of general architecture-dependent Qt data.
912 \value DataPath The location of general architecture-independent Qt data.
913 \value TranslationsPath The location of translation information for Qt strings.
914 \value ExamplesPath The location for examples upon install.
915 \value TestsPath The location of installed Qt testcases.
916 \value SettingsPath The location for Qt settings. Not applicable on Windows.
917
918 \sa location()
919*/
920
921QT_END_NAMESPACE
922
923#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
924# include <stdio.h>
925# include <stdlib.h>
926
927#include "private/qcoreapplication_p.h"
928
929QT_WARNING_DISABLE_GCC("-Wattributes")
930QT_WARNING_DISABLE_CLANG("-Wattributes")
931QT_WARNING_DISABLE_INTEL(2621)
932
933extern const char qt_core_interpreter[] __attribute__((section(".interp")))
934 = ELF_INTERPRETER;
935
936extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
937void qt_core_boilerplate()
938{
939 printf(format: "This is the QtCore library version " QT_BUILD_STR "\n"
940 "Copyright (C) 2016 The Qt Company Ltd.\n"
941 "Contact: http://www.qt.io/licensing/\n"
942 "\n"
943 "Installation prefix: %s\n"
944 "Library path: %s\n"
945 "Plugin path: %s\n",
946 qt_configure_prefix_path_str + 12,
947 qt_configure_strs + qt_configure_str_offsets[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
948 qt_configure_strs + qt_configure_str_offsets[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
949
950 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
951
952 exit(status: 0);
953}
954
955#endif
956

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