| 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 |
| 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(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 | |
| 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 | |
| 247 | QLibraryInfo::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 | |
| 323 | const 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 | */ |
| 333 | bool |
| 334 | QLibraryInfo::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 | */ |
| 350 | QVersionNumber 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 | |
| 367 | static 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 |
| 400 | void QLibraryInfo::reload() |
| 401 | { |
| 402 | QLibraryInfoPrivate::reload(); |
| 403 | } |
| 404 | |
| 405 | void 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 |
| 424 | static 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)) |
| 458 | static 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) |
| 469 | static 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 | |
| 479 | static 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) |
| 596 | QString qmake_abslocation(); |
| 597 | |
| 598 | static 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 | |
| 605 | static QString getExtPrefixFromHostBinDir() |
| 606 | { |
| 607 | return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_EXTPREFIX_PATH); |
| 608 | } |
| 609 | |
| 610 | static QString getHostPrefixFromHostBinDir() |
| 611 | { |
| 612 | return getPrefixFromHostBinDir(QT_CONFIGURE_HOSTBINDIR_TO_HOSTPREFIX_PATH); |
| 613 | } |
| 614 | #endif |
| 615 | |
| 616 | #ifndef QT_BUILD_QMAKE_BOOTSTRAP |
| 617 | static 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 | */ |
| 650 | QString 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 | |
| 663 | QString |
| 664 | QLibraryInfo::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 | |
| 835 | QStringList 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 | |
| 882 | QT_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 | |
| 890 | QT_WARNING_DISABLE_GCC("-Wattributes" ) |
| 891 | QT_WARNING_DISABLE_CLANG("-Wattributes" ) |
| 892 | QT_WARNING_DISABLE_INTEL(2621) |
| 893 | |
| 894 | extern const char qt_core_interpreter[] __attribute__((section(".interp" ))) |
| 895 | = ELF_INTERPRETER; |
| 896 | |
| 897 | extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer)); |
| 898 | void 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 | |