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