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
51 QT_BEGIN_NAMESPACE
52 extern QString qmake_libraryInfoFile();
53 QT_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 
77 QT_BEGIN_NAMESPACE
78 
79 extern void qDumpCPUFeatures(); // in qsimd.cpp
80 
81 #if QT_CONFIG(settings)
82 
83 struct 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 };
98 Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
99 
100 class QLibraryInfoPrivate
101 {
102 public:
103     static QSettings *findConfiguration();
104 #ifdef QT_BUILD_QMAKE
reload()105     static void reload()
106     {
107         if (qt_library_settings.exists())
108             qt_library_settings->load();
109     }
haveGroup(QLibraryInfo::PathGroup group)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
configuration()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 
137 static const char platformsSection[] = "Platforms";
138 
QLibrarySettings()139 QLibrarySettings::QLibrarySettings()
140 {
141     load();
142 }
143 
load()144 void 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 
findConfiguration()183 QSettings *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 
QLibraryInfo()247 QLibraryInfo::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)
256 QString
licensee()257 QLibraryInfo::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)
269 QString
licensedProducts()270 QLibraryInfo::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)
283 QDate
buildDate()284 QLibraryInfo::buildDate()
285 {
286     return QDate::fromString(QString::fromLatin1("2012-12-20"), 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 
build()366 const 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 */
376 bool
isDebugBuild()377 QLibraryInfo::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 */
version()393 QVersionNumber 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 
410 static const struct {
411     char key[19], value[13];
412 } qtConfEntries[] = {
413     { "Prefix", "." },
414     { "Documentation", "doc" }, // should be ${Data}/doc
415     { "Headers", "include" },
416     { "Libraries", "lib" },
417 #ifdef Q_OS_WIN
418     { "LibraryExecutables", "bin" },
419 #else
420     { "LibraryExecutables", "libexec" }, // should be ${ArchData}/libexec
421 #endif
422     { "Binaries", "bin" },
423     { "Plugins", "plugins" }, // should be ${ArchData}/plugins
424     { "Imports", "imports" }, // should be ${ArchData}/imports
425     { "Qml2Imports", "qml" }, // should be ${ArchData}/qml
426     { "ArchData", "." },
427     { "Data", "." },
428     { "Translations", "translations" }, // should be ${Data}/translations
429     { "Examples", "examples" },
430     { "Tests", "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
reload()444 void QLibraryInfo::reload()
445 {
446     QLibraryInfoPrivate::reload();
447 }
448 
sysrootify(QString * path)449 void 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
prefixFromAppDirHelper()468 static 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))
prefixFromQtCoreLibraryHelper(const QString & qtCoreLibraryPath)502 static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath)
503 {
504     const QString qtCoreLibrary = QDir::fromNativeSeparators(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(prefixDir);
509 }
510 #endif
511 
512 #if defined(Q_OS_WIN)
513 #if defined(Q_OS_WINRT)
514 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
getWindowsModuleHandle()515 static HMODULE getWindowsModuleHandle()
516 {
517     return reinterpret_cast<HMODULE>(&__ImageBase);
518 }
519 #else  // Q_OS_WINRT
getWindowsModuleHandle()520 static 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 
getRelocatablePrefix()531 static 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(reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), &info);
581     if (result > 0 && info.dli_fname)
582         prefixPath = prefixFromQtCoreLibraryHelper(QString::fromLocal8Bit(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         qt_configure_strs + qt_configure_str_offsets[QLibraryInfo::LibrariesPath - 1]);
630     QDir prefixDir(prefixPath);
631     while (!prefixDir.exists(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)
648 QString qmake_abslocation();
649 
getPrefixFromHostBinDir(const char * hostBinDirToPrefixPath)650 static 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 
getExtPrefixFromHostBinDir()657 static QString getExtPrefixFromHostBinDir()
658 {
659     return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH);
660 }
661 
getHostPrefixFromHostBinDir()662 static QString getHostPrefixFromHostBinDir()
663 {
664     return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH);
665 }
666 #endif
667 
668 #ifndef QT_BUILD_QMAKE_BOOTSTRAP
getPrefix(QLibraryInfo::PathGroup group)669 static 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 */
692 QString
location(LibraryLocation loc)693 QLibraryInfo::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 
705 QString
rawLocation(LibraryLocation loc,PathGroup group)706 QLibraryInfo::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(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(QLatin1Char('$'), startIndex);
772                 if (startIndex < 0)
773                     break;
774                 if (ret.length() < startIndex + 3)
775                     break;
776                 if (ret.at(startIndex + 1) != QLatin1Char('(')) {
777                     startIndex++;
778                     continue;
779                 }
780                 int endIndex = ret.indexOf(QLatin1Char(')'), startIndex + 2);
781                 if (endIndex < 0)
782                     break;
783                 QStringRef envVarName = ret.midRef(startIndex + 2, endIndex - startIndex - 2);
784                 QString value = QString::fromLocal8Bit(qgetenv(envVarName.toLocal8Bit().constData()));
785                 ret.replace(startIndex, endIndex - startIndex + 1, value);
786                 startIndex += value.length();
787             }
788 
789             config->endGroup();
790 
791             ret = QDir::fromNativeSeparators(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(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(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(PrefixPath);
857         }
858 #endif // QT_BUILD_QMAKE
859         ret = QDir::cleanPath(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 
platformPluginArguments(const QString & platformName)877 QStringList 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 
921 QT_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 
929 QT_WARNING_DISABLE_GCC("-Wattributes")
930 QT_WARNING_DISABLE_CLANG("-Wattributes")
931 QT_WARNING_DISABLE_INTEL(2621)
932 
933 extern const char qt_core_interpreter[] __attribute__((section(".interp")))
934     = ELF_INTERPRETER;
935 
936 extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
qt_core_boilerplate()937 void qt_core_boilerplate()
938 {
939     printf("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(0);
953 }
954 
955 #endif
956