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 | |