| 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 |
| 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 | |
| 137 | static const char platformsSection[] = "Platforms" ; |
| 138 | |
| 139 | QLibrarySettings::QLibrarySettings() |
| 140 | { |
| 141 | load(); |
| 142 | } |
| 143 | |
| 144 | void 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 | |
| 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(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 | |
| 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 |
| 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 |
| 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 |
| 284 | QLibraryInfo::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 | |
| 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 |
| 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 | */ |
| 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 | { .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 |
| 444 | void QLibraryInfo::reload() |
| 445 | { |
| 446 | QLibraryInfoPrivate::reload(); |
| 447 | } |
| 448 | |
| 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 |
| 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)) |
| 502 | static 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) |
| 514 | EXTERN_C IMAGE_DOS_HEADER __ImageBase; |
| 515 | static HMODULE getWindowsModuleHandle() |
| 516 | { |
| 517 | return reinterpret_cast<HMODULE>(&__ImageBase); |
| 518 | } |
| 519 | #else // Q_OS_WINRT |
| 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 | |
| 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(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) |
| 648 | QString qmake_abslocation(); |
| 649 | |
| 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 | |
| 657 | static QString getExtPrefixFromHostBinDir() |
| 658 | { |
| 659 | return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH); |
| 660 | } |
| 661 | |
| 662 | static QString getHostPrefixFromHostBinDir() |
| 663 | { |
| 664 | return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH); |
| 665 | } |
| 666 | #endif |
| 667 | |
| 668 | #ifndef QT_BUILD_QMAKE_BOOTSTRAP |
| 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 |
| 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 |
| 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(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 | |
| 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)); |
| 937 | void 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 | |