1/****************************************************************************
2**
3** Copyright (C) 2020 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(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(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(QLatin1String("EffectivePaths"));
166 // Backwards compat: an existing but empty file is claimed to contain the Paths section.
167 havePaths = (!haveDevicePaths && !haveEffectivePaths
168 && !children.contains(QLatin1String(platformsSection)))
169 || children.contains(QLatin1String("Paths"));
170#ifndef QT_BUILD_QMAKE
171 if (!havePaths)
172 settings.reset(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(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(QLatin1String("qt.conf"));
211 if (QFile::exists(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#if defined(Q_CC_INTEL) // must be before GNU, Clang and MSVC because ICC/ICL claim to be them
251# ifdef __INTEL_CLANG_COMPILER
252# define ICC_COMPAT "Clang"
253# elif defined(__INTEL_MS_COMPAT_LEVEL)
254# define ICC_COMPAT "Microsoft"
255# elif defined(__GNUC__)
256# define ICC_COMPAT "GCC"
257# else
258# define ICC_COMPAT "no"
259# endif
260# if __INTEL_COMPILER == 1300
261# define ICC_VERSION "13.0"
262# elif __INTEL_COMPILER == 1310
263# define ICC_VERSION "13.1"
264# elif __INTEL_COMPILER == 1400
265# define ICC_VERSION "14.0"
266# elif __INTEL_COMPILER == 1500
267# define ICC_VERSION "15.0"
268# else
269# define ICC_VERSION QT_STRINGIFY(__INTEL_COMPILER)
270# endif
271# ifdef __INTEL_COMPILER_UPDATE
272# define COMPILER_STRING "Intel(R) C++ " ICC_VERSION "." QT_STRINGIFY(__INTEL_COMPILER_UPDATE) \
273 " build " QT_STRINGIFY(__INTEL_COMPILER_BUILD_DATE) " [" \
274 ICC_COMPAT " compatibility]"
275# else
276# define COMPILER_STRING "Intel(R) C++ " ICC_VERSION \
277 " build " QT_STRINGIFY(__INTEL_COMPILER_BUILD_DATE) " [" \
278 ICC_COMPAT " compatibility]"
279# endif
280#elif defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too
281# ifdef __apple_build_version__ // Apple clang has other version numbers
282# define COMPILER_STRING "Clang " __clang_version__ " (Apple)"
283# else
284# define COMPILER_STRING "Clang " __clang_version__
285# endif
286#elif defined(Q_CC_GHS)
287# define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER)
288#elif defined(Q_CC_GNU)
289# define COMPILER_STRING "GCC " __VERSION__
290#elif defined(Q_CC_MSVC)
291# if _MSC_VER < 1910
292# define COMPILER_STRING "MSVC 2015"
293# elif _MSC_VER < 1917
294# define COMPILER_STRING "MSVC 2017"
295# elif _MSC_VER < 2000
296# define COMPILER_STRING "MSVC 2019"
297# else
298# define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER)
299# endif
300#else
301# define COMPILER_STRING "<unknown compiler>"
302#endif
303#ifdef QT_NO_DEBUG
304# define DEBUG_STRING " release"
305#else
306# define DEBUG_STRING " debug"
307#endif
308#ifdef QT_SHARED
309# define SHARED_STRING " shared (dynamic)"
310#else
311# define SHARED_STRING " static"
312#endif
313#define QT_BUILD_STR "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")"
314
315/*!
316 Returns a string describing how this version of Qt was built.
317
318 \internal
319
320 \since 5.3
321*/
322
323const char *QLibraryInfo::build() noexcept
324{
325 return QT_BUILD_STR;
326}
327
328/*!
329 \since 5.0
330 Returns \c true if this build of Qt was built with debugging enabled, or
331 false if it was built in release mode.
332*/
333bool
334QLibraryInfo::isDebugBuild()
335{
336#ifdef QT_DEBUG
337 return true;
338#else
339 return false;
340#endif
341}
342
343#ifndef QT_BOOTSTRAPPED
344/*!
345 \since 5.8
346 Returns the version of the Qt library.
347
348 \sa qVersion()
349*/
350QVersionNumber QLibraryInfo::version() noexcept
351{
352 return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH);
353}
354#endif // QT_BOOTSTRAPPED
355
356#endif // QT_BUILD_QMAKE
357
358/*
359 * To add a new entry in QLibrary::LibraryPath, add it to the enum above the bootstrapped values and:
360 * - add its relative path in the qtConfEntries[] array below
361 * (the key is what appears in a qt.conf file)
362 * - add a property name in qmake/property.cpp propList[] array
363 * (it's used with qmake -query)
364 * - add to qt_config.prf, qt_module.prf, qt_module_fwdpri.prf
365 */
366
367static const struct {
368 char key[19], value[13];
369} qtConfEntries[] = {
370 { "Prefix", "." },
371 { "Documentation", "doc" }, // should be ${Data}/doc
372 { "Headers", "include" },
373 { "Libraries", "lib" },
374#ifdef Q_OS_WIN
375 { "LibraryExecutables", "bin" },
376#else
377 { "LibraryExecutables", "libexec" }, // should be ${ArchData}/libexec
378#endif
379 { "Binaries", "bin" },
380 { "Plugins", "plugins" }, // should be ${ArchData}/plugins
381 { "Qml2Imports", "qml" }, // should be ${ArchData}/qml
382 { "ArchData", "." },
383 { "Data", "." },
384 { "Translations", "translations" }, // should be ${Data}/translations
385 { "Examples", "examples" },
386 { "Tests", "tests" },
387#ifdef QT_BUILD_QMAKE
388 { "Sysroot", "" },
389 { "SysrootifyPrefix", "" },
390 { "HostBinaries", "bin" },
391 { "HostLibraries", "lib" },
392 { "HostData", "." },
393 { "TargetSpec", "" },
394 { "HostSpec", "" },
395 { "HostPrefix", "" },
396#endif
397};
398
399#ifdef QT_BUILD_QMAKE
400void QLibraryInfo::reload()
401{
402 QLibraryInfoPrivate::reload();
403}
404
405void QLibraryInfo::sysrootify(QString *path)
406{
407 if (!QVariant::fromValue(rawLocation(SysrootifyPrefixPath, FinalPaths)).toBool())
408 return;
409
410 const QString sysroot = rawLocation(SysrootPath, FinalPaths);
411 if (sysroot.isEmpty())
412 return;
413
414 if (path->length() > 2 && path->at(1) == QLatin1Char(':')
415 && (path->at(2) == QLatin1Char('/') || path->at(2) == QLatin1Char('\\'))) {
416 path->replace(0, 2, sysroot); // Strip out the drive on Windows targets
417 } else {
418 path->prepend(sysroot);
419 }
420}
421#endif // QT_BUILD_QMAKE
422
423#ifndef QT_BUILD_QMAKE
424static QString prefixFromAppDirHelper()
425{
426 QString appDir;
427
428 if (QCoreApplication::instance()) {
429#ifdef Q_OS_DARWIN
430 CFBundleRef bundleRef = CFBundleGetMainBundle();
431 if (bundleRef) {
432 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
433 if (urlRef) {
434 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
435#ifdef Q_OS_MACOS
436 QString bundleContentsDir = QString(path) + QLatin1String("/Contents/");
437 if (QDir(bundleContentsDir).exists())
438 return QDir::cleanPath(bundleContentsDir);
439#else
440 return QDir::cleanPath(QString(path)); // iOS
441#endif // Q_OS_MACOS
442 }
443 }
444#endif // Q_OS_DARWIN
445 // We make the prefix path absolute to the executable's directory.
446 appDir = QCoreApplication::applicationDirPath();
447 } else {
448 appDir = QDir::currentPath();
449 }
450
451 return appDir;
452}
453#endif
454
455#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(relocatable)
456#if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework)) \
457 && (QT_CONFIG(dlopen) || defined(Q_OS_WIN))
458static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
459{
460 const QString qtCoreLibrary = QDir::fromNativeSeparators(qtCoreLibraryPath);
461 const QString libDir = QFileInfo(qtCoreLibrary).absolutePath();
462 const QString prefixDir = libDir + QLatin1Char('/')
463 + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH);
464 return QDir::cleanPath(prefixDir);
465}
466#endif
467
468#if defined(Q_OS_WIN)
469static HMODULE getWindowsModuleHandle()
470{
471 HMODULE hModule = NULL;
472 GetModuleHandleEx(
473 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
474 (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule);
475 return hModule;
476}
477#endif // Q_OS_WIN
478
479static QString getRelocatablePrefix()
480{
481 QString prefixPath;
482
483 // For static builds, the prefix will be the app directory.
484 // For regular builds, the prefix will be relative to the location of the QtCore shared library.
485#if defined(QT_STATIC)
486 prefixPath = prefixFromAppDirHelper();
487#elif defined(Q_OS_DARWIN) && QT_CONFIG(framework)
488#ifndef QT_LIBINFIX
489 #define QT_LIBINFIX ""
490#endif
491 auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtCore" QT_LIBINFIX));
492 if (!qtCoreBundle) {
493 // When running Qt apps over Samba shares, CoreFoundation will fail to find
494 // the Resources directory inside the bundle, This directory is a symlink,
495 // and CF relies on readdir() and dtent.dt_type to detect symlinks, which
496 // does not work reliably for Samba shares. We work around it by manually
497 // looking for the QtCore bundle.
498 auto allBundles = CFBundleGetAllBundles();
499 auto bundleCount = CFArrayGetCount(allBundles);
500 for (int i = 0; i < bundleCount; ++i) {
501 auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i));
502 auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle));
503 auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle));
504 if (CFStringHasSuffix(path, CFSTR("/QtCore" QT_LIBINFIX ".framework"))) {
505 qtCoreBundle = bundle;
506 break;
507 }
508 }
509 }
510 Q_ASSERT(qtCoreBundle);
511
512 QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle);
513 Q_ASSERT(qtCorePath);
514
515 QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath);
516 Q_ASSERT(qtCorePathAbsolute);
517
518 QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute);
519
520 const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle);
521
522 const QString prefixDir = QString(libDirCFString) + QLatin1Char('/')
523 + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH);
524
525 prefixPath = QDir::cleanPath(prefixDir);
526#elif QT_CONFIG(dlopen)
527 Dl_info info;
528 int result = dladdr(reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), &info);
529 if (result > 0 && info.dli_fname)
530 prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(info.dli_fname));
531#elif defined(Q_OS_WIN)
532 HMODULE hModule = getWindowsModuleHandle();
533 const int kBufferSize = 4096;
534 wchar_t buffer[kBufferSize];
535 DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize);
536 const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize));
537 const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath();
538 pathSize = GetModuleFileName(NULL, buffer, kBufferSize);
539 const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath();
540 if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) {
541 // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an
542 // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking
543 // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib.
544 const QString libdir = QString::fromLocal8Bit(
545 qt_configure_strs + qt_configure_str_offsets[QLibraryInfo::LibrariesPath - 1]);
546 const QLatin1Char slash('/');
547#if defined(Q_CC_MINGW)
548 const QString implibPrefix = QStringLiteral("lib");
549 const QString implibSuffix = QStringLiteral(".a");
550#else
551 const QString implibPrefix;
552 const QString implibSuffix = QStringLiteral(".lib");
553#endif
554 const QString qtCoreImpLibFileName = implibPrefix
555 + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix;
556 const QString qtCoreImpLibPath = qtCoreDirPath
557 + slash + QLatin1String(QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH)
558 + slash + libdir
559 + slash + qtCoreImpLibFileName;
560 if (!QFileInfo::exists(qtCoreImpLibPath)) {
561 // We did not find a corresponding import library and conclude that this is a
562 // windeployqt'ed executable.
563 return exeDirPath;
564 }
565 }
566 if (!qtCoreFilePath.isEmpty())
567 prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath);
568#else
569#error "The chosen platform / config does not support querying for a dynamic prefix."
570#endif
571
572#if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__)
573 // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir.
574 // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0
575 // changelog regarding SSE2 support.
576 const QString libdir = QString::fromLocal8Bit(
577 qt_configure_strs + qt_configure_str_offsets[QLibraryInfo::LibrariesPath - 1]);
578 QDir prefixDir(prefixPath);
579 while (!prefixDir.exists(libdir)) {
580 prefixDir.cdUp();
581 prefixPath = prefixDir.absolutePath();
582 if (prefixDir.isRoot()) {
583 prefixPath.clear();
584 break;
585 }
586 }
587#endif
588
589 Q_ASSERT_X(!prefixPath.isEmpty(), "getRelocatablePrefix",
590 "Failed to find the Qt prefix path.");
591 return prefixPath;
592}
593#endif
594
595#if defined(QT_BUILD_QMAKE) && !defined(QT_BUILD_QMAKE_BOOTSTRAP)
596QString qmake_abslocation();
597
598static QString getPrefixFromHostBinDir(const char *hostBinDirToPrefixPath)
599{
600 const QFileInfo qmfi = QFileInfo(qmake_abslocation()).canonicalFilePath();
601 return QDir::cleanPath(qmfi.absolutePath() + QLatin1Char('/')
602 + QLatin1String(hostBinDirToPrefixPath));
603}
604
605static QString getExtPrefixFromHostBinDir()
606{
607 return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH);
608}
609
610static QString getHostPrefixFromHostBinDir()
611{
612 return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH);
613}
614#endif
615
616#ifndef QT_BUILD_QMAKE_BOOTSTRAP
617static QString getPrefix(
618#ifdef QT_BUILD_QMAKE
619 QLibraryInfo::PathGroup group
620#endif
621 )
622{
623#if defined(QT_BUILD_QMAKE)
624# if QT_CONFIGURE_CROSSBUILD
625 if (group == QLibraryInfo::DevicePaths)
626 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
627# else
628 Q_UNUSED(group);
629# endif
630 return getExtPrefixFromHostBinDir();
631#elif QT_CONFIG(relocatable)
632 return getRelocatablePrefix();
633#else
634 return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH);
635#endif
636}
637#endif // QT_BUILD_QMAKE_BOOTSTRAP
638
639/*! \fn QString QLibraryInfo::location(LibraryLocation loc)
640 \obsolete Use path() instead.
641
642 Returns the path specified by \a loc.
643 \sa path()
644*/
645
646/*!
647 \since 6.0
648 Returns the path specified by \a p.
649*/
650QString QLibraryInfo::path(LibraryPath p)
651{
652 const LibraryPath loc = p;
653#ifdef QT_BUILD_QMAKE // ends inside rawLocation !
654 QString ret = rawLocation(loc, FinalPaths);
655
656 // Automatically prepend the sysroot to target paths
657 if (loc < SysrootPath || loc > LastHostPath)
658 sysrootify(&ret);
659
660 return ret;
661}
662
663QString
664QLibraryInfo::rawLocation(LibraryPath loc, PathGroup group)
665{
666#endif // QT_BUILD_QMAKE, started inside path!
667 QString ret;
668 bool fromConf = false;
669#if QT_CONFIG(settings)
670#ifdef QT_BUILD_QMAKE
671 // Logic for choosing the right data source: if EffectivePaths are requested
672 // and qt.conf with that section is present, use it, otherwise fall back to
673 // FinalPaths. For FinalPaths, use qt.conf if present and contains not only
674 // [EffectivePaths], otherwise fall back to builtins.
675 // EffectiveSourcePaths falls back to EffectivePaths.
676 // DevicePaths falls back to FinalPaths.
677 PathGroup orig_group = group;
678 if (QLibraryInfoPrivate::haveGroup(group)
679 || (group == EffectiveSourcePaths
680 && (group = EffectivePaths, QLibraryInfoPrivate::haveGroup(group)))
681 || ((group == EffectivePaths || group == DevicePaths)
682 && (group = FinalPaths, QLibraryInfoPrivate::haveGroup(group)))
683 || (group = orig_group, false))
684#else
685 if (QLibraryInfoPrivate::configuration())
686#endif
687 {
688 fromConf = true;
689
690 QString key;
691 QString defaultValue;
692 if (unsigned(loc) < sizeof(qtConfEntries)/sizeof(qtConfEntries[0])) {
693 key = QLatin1String(qtConfEntries[loc].key);
694 defaultValue = QLatin1String(qtConfEntries[loc].value);
695 }
696#ifndef Q_OS_WIN // On Windows we use the registry
697 else if (loc == SettingsPath) {
698 key = QLatin1String("Settings");
699 defaultValue = QLatin1String(".");
700 }
701#endif
702
703 if(!key.isNull()) {
704 QSettings *config = QLibraryInfoPrivate::configuration();
705 config->beginGroup(QLatin1String(
706#ifdef QT_BUILD_QMAKE
707 group == DevicePaths ? "DevicePaths" :
708 group == EffectiveSourcePaths ? "EffectiveSourcePaths" :
709 group == EffectivePaths ? "EffectivePaths" :
710#endif
711 "Paths"));
712
713 ret = config->value(key, defaultValue).toString();
714
715#ifdef QT_BUILD_QMAKE
716 if (ret.isEmpty()) {
717 if (loc == HostPrefixPath)
718 ret = config->value(QLatin1String(qtConfEntries[PrefixPath].key),
719 QLatin1String(qtConfEntries[PrefixPath].value)).toString();
720 else if (loc == TargetSpecPath || loc == HostSpecPath || loc == SysrootifyPrefixPath)
721 fromConf = false;
722 // The last case here is SysrootPath, which can be legitimately empty.
723 // All other keys have non-empty fallbacks to start with.
724 }
725#endif
726
727 int startIndex = 0;
728 forever {
729 startIndex = ret.indexOf(QLatin1Char('$'), startIndex);
730 if (startIndex < 0)
731 break;
732 if (ret.length() < startIndex + 3)
733 break;
734 if (ret.at(startIndex + 1) != QLatin1Char('(')) {
735 startIndex++;
736 continue;
737 }
738 int endIndex = ret.indexOf(QLatin1Char(')'), startIndex + 2);
739 if (endIndex < 0)
740 break;
741 auto envVarName = QStringView{ret}.mid(startIndex + 2, endIndex - startIndex - 2);
742 QString value = QString::fromLocal8Bit(qgetenv(envVarName.toLocal8Bit().constData()));
743 ret.replace(startIndex, endIndex - startIndex + 1, value);
744 startIndex += value.length();
745 }
746
747 config->endGroup();
748
749 ret = QDir::fromNativeSeparators(ret);
750 }
751 }
752#endif // settings
753
754#ifndef QT_BUILD_QMAKE_BOOTSTRAP
755 if (!fromConf) {
756 // "volatile" here is a hack to prevent compilers from doing a
757 // compile-time strlen() on "path". The issue is that Qt installers
758 // will binary-patch the Qt installation paths -- in such scenarios, Qt
759 // will be built with a dummy path, thus the compile-time result of
760 // strlen is meaningless.
761 const char * volatile path = nullptr;
762 if (loc == PrefixPath) {
763 ret = getPrefix(
764#ifdef QT_BUILD_QMAKE
765 group
766#endif
767 );
768 } else if (unsigned(loc) <= sizeof(qt_configure_str_offsets)/sizeof(qt_configure_str_offsets[0])) {
769 path = qt_configure_strs + qt_configure_str_offsets[loc - 1];
770#ifndef Q_OS_WIN // On Windows we use the registry
771 } else if (loc == SettingsPath) {
772 path = QT_CONFIGURE_SETTINGS_PATH;
773#endif
774# ifdef QT_BUILD_QMAKE
775 } else if (loc == HostPrefixPath) {
776 static const QByteArray hostPrefixPath = getHostPrefixFromHostBinDir().toLatin1();
777 path = hostPrefixPath.constData();
778# endif
779 }
780
781 if (path)
782 ret = QString::fromLocal8Bit(path);
783 }
784#endif
785
786#ifdef QT_BUILD_QMAKE
787 // These values aren't actually paths and thus need to be returned verbatim.
788 if (loc == TargetSpecPath || loc == HostSpecPath || loc == SysrootifyPrefixPath)
789 return ret;
790#endif
791
792 if (!ret.isEmpty() && QDir::isRelativePath(ret)) {
793 QString baseDir;
794#ifdef QT_BUILD_QMAKE
795 if (loc == HostPrefixPath || loc == PrefixPath || loc == SysrootPath) {
796 // We make the prefix/sysroot path absolute to the executable's directory.
797 // loc == PrefixPath while a sysroot is set would make no sense here.
798 // loc == SysrootPath only makes sense if qmake lives inside the sysroot itself.
799 baseDir = QFileInfo(qmake_libraryInfoFile()).absolutePath();
800 } else if (loc > SysrootPath && loc <= LastHostPath) {
801 // We make any other host path absolute to the host prefix directory.
802 baseDir = rawLocation(HostPrefixPath, group);
803 } else {
804 // we make any other path absolute to the prefix directory
805 baseDir = rawLocation(PrefixPath, group);
806 if (group == EffectivePaths)
807 sysrootify(&baseDir);
808 }
809#else
810 if (loc == PrefixPath) {
811 baseDir = prefixFromAppDirHelper();
812 } else {
813 // we make any other path absolute to the prefix directory
814 baseDir = path(PrefixPath);
815 }
816#endif // QT_BUILD_QMAKE
817 ret = QDir::cleanPath(baseDir + QLatin1Char('/') + ret);
818 }
819 return ret;
820}
821
822/*!
823 Returns additional arguments to the platform plugin matching
824 \a platformName which can be specified as a string list using
825 the key \c Arguments in a group called \c Platforms of the
826 \c qt.conf file.
827
828 sa {Using qt.conf}
829
830 \internal
831
832 \since 5.3
833*/
834
835QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
836{
837#if !defined(QT_BUILD_QMAKE) && QT_CONFIG(settings)
838 QScopedPointer<const QSettings> settings(QLibraryInfoPrivate::findConfiguration());
839 if (!settings.isNull()) {
840 const QString key = QLatin1String(platformsSection)
841 + QLatin1Char('/')
842 + platformName
843 + QLatin1String("Arguments");
844 return settings->value(key).toStringList();
845 }
846#else
847 Q_UNUSED(platformName);
848#endif // !QT_BUILD_QMAKE && settings
849 return QStringList();
850}
851
852/*!
853 \enum QLibraryInfo::LibraryPath
854
855 \keyword library location
856
857 This enum type is used to query for a specific path:
858
859 \value PrefixPath The default prefix for all paths.
860 \value DocumentationPath The path to documentation upon install.
861 \value HeadersPath The path to all headers.
862 \value LibrariesPath The path to installed libraries.
863 \value LibraryExecutablesPath The path to installed executables required by libraries at runtime.
864 \value BinariesPath The path to installed Qt binaries (tools and applications).
865 \value PluginsPath The path to installed Qt plugins.
866 \value Qml2ImportsPath The path to installed QML extensions to import (QML 2.x).
867 \value ArchDataPath The path to general architecture-dependent Qt data.
868 \value DataPath The path to general architecture-independent Qt data.
869 \value TranslationsPath The path to translation information for Qt strings.
870 \value ExamplesPath The path to examples upon install.
871 \value TestsPath The path to installed Qt testcases.
872 \value SettingsPath The path to Qt settings. Not applicable on Windows.
873
874 \sa path()
875*/
876
877/*!
878 \typealias QLibraryInfo::LibraryLocation
879 \obsolete Use LibraryPath with QLibraryInfo::path() instead.
880*/
881
882QT_END_NAMESPACE
883
884#if defined(Q_CC_GNU) && defined(ELF_INTERPRETER)
885# include <stdio.h>
886# include <stdlib.h>
887
888#include "private/qcoreapplication_p.h"
889
890QT_WARNING_DISABLE_GCC("-Wattributes")
891QT_WARNING_DISABLE_CLANG("-Wattributes")
892QT_WARNING_DISABLE_INTEL(2621)
893
894extern const char qt_core_interpreter[] __attribute__((section(".interp")))
895 = ELF_INTERPRETER;
896
897extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
898void qt_core_boilerplate()
899{
900 printf("This is the QtCore library version " QT_BUILD_STR "\n"
901 "Copyright (C) 2016 The Qt Company Ltd.\n"
902 "Contact: http://www.qt.io/licensing/\n"
903 "\n"
904 "Installation prefix: %s\n"
905 "Library path: %s\n"
906 "Plugin path: %s\n",
907 qt_configure_prefix_path_str + 12,
908 qt_configure_strs + qt_configure_str_offsets[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
909 qt_configure_strs + qt_configure_str_offsets[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
910
911 QT_PREPEND_NAMESPACE(qDumpCPUFeatures)();
912
913 exit(0);
914}
915
916#endif
917