1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // Copyright (C) 2021 Intel Corporation. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
4 | |
5 | #include "qdir.h" |
6 | #include "qstringlist.h" |
7 | #include "qfile.h" |
8 | #if QT_CONFIG(settings) |
9 | #include "qsettings.h" |
10 | #endif |
11 | #include "qlibraryinfo.h" |
12 | #include "qlibraryinfo_p.h" |
13 | #include "qscopedpointer.h" |
14 | |
15 | #include "qcoreapplication.h" |
16 | |
17 | #include "private/qglobal_p.h" |
18 | #include "archdetect.cpp" |
19 | #include "qconfig.cpp" |
20 | |
21 | #ifdef Q_OS_DARWIN |
22 | # include "private/qcore_mac_p.h" |
23 | #endif // Q_OS_DARWIN |
24 | |
25 | #if QT_CONFIG(relocatable) && QT_CONFIG(dlopen) && !QT_CONFIG(framework) |
26 | # include <dlfcn.h> |
27 | #endif |
28 | |
29 | #if QT_CONFIG(relocatable) && defined(Q_OS_WIN) |
30 | # include <qt_windows.h> |
31 | #endif |
32 | |
33 | QT_BEGIN_NAMESPACE |
34 | |
35 | using namespace Qt::StringLiterals; |
36 | |
37 | extern void qDumpCPUFeatures(); // in qsimd.cpp |
38 | |
39 | #if QT_CONFIG(settings) |
40 | |
41 | static QSettings *findConfiguration(); |
42 | |
43 | struct QLibrarySettings |
44 | { |
45 | QLibrarySettings(); |
46 | void load(); |
47 | bool havePaths(); |
48 | QSettings *configuration(); |
49 | |
50 | QScopedPointer<QSettings> settings; |
51 | bool paths; |
52 | bool reloadOnQAppAvailable; |
53 | }; |
54 | Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings) |
55 | |
56 | QLibrarySettings::QLibrarySettings() : paths(false), reloadOnQAppAvailable(false) |
57 | { |
58 | load(); |
59 | } |
60 | |
61 | QSettings *QLibrarySettings::configuration() |
62 | { |
63 | if (reloadOnQAppAvailable && QCoreApplication::instance() != nullptr) |
64 | load(); |
65 | return settings.data(); |
66 | } |
67 | |
68 | bool QLibrarySettings::havePaths() |
69 | { |
70 | if (reloadOnQAppAvailable && QCoreApplication::instance() != nullptr) |
71 | load(); |
72 | return paths; |
73 | } |
74 | |
75 | void QLibrarySettings::load() |
76 | { |
77 | // If we get any settings here, those won't change when the application shows up. |
78 | settings.reset(other: findConfiguration()); |
79 | reloadOnQAppAvailable = (settings.data() == nullptr && QCoreApplication::instance() == nullptr); |
80 | |
81 | if (settings) { |
82 | // This code needs to be in the regular library, as otherwise a qt.conf that |
83 | // works for qmake would break things for dynamically built Qt tools. |
84 | QStringList children = settings->childGroups(); |
85 | paths = !children.contains(str: "Platforms"_L1 ) |
86 | || children.contains(str: "Paths"_L1 ); |
87 | } |
88 | } |
89 | |
90 | static QSettings *findConfiguration() |
91 | { |
92 | if (QLibraryInfoPrivate::qtconfManualPath) |
93 | return new QSettings(*QLibraryInfoPrivate::qtconfManualPath, QSettings::IniFormat); |
94 | |
95 | QString qtconfig = QStringLiteral(":/qt/etc/qt.conf" ); |
96 | if (QFile::exists(fileName: qtconfig)) |
97 | return new QSettings(qtconfig, QSettings::IniFormat); |
98 | #ifdef Q_OS_DARWIN |
99 | CFBundleRef bundleRef = CFBundleGetMainBundle(); |
100 | if (bundleRef) { |
101 | QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef, |
102 | QCFString("qt.conf"_L1 ), |
103 | 0, |
104 | 0); |
105 | if (urlRef) { |
106 | QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle); |
107 | qtconfig = QDir::cleanPath(path); |
108 | if (QFile::exists(qtconfig)) |
109 | return new QSettings(qtconfig, QSettings::IniFormat); |
110 | } |
111 | } |
112 | #endif |
113 | if (QCoreApplication::instance()) { |
114 | QDir pwd(QCoreApplication::applicationDirPath()); |
115 | qtconfig = pwd.filePath(fileName: u"qt" QT_STRINGIFY(QT_VERSION_MAJOR) ".conf"_s ); |
116 | if (QFile::exists(fileName: qtconfig)) |
117 | return new QSettings(qtconfig, QSettings::IniFormat); |
118 | qtconfig = pwd.filePath(fileName: "qt.conf"_L1 ); |
119 | if (QFile::exists(fileName: qtconfig)) |
120 | return new QSettings(qtconfig, QSettings::IniFormat); |
121 | } |
122 | return nullptr; //no luck |
123 | } |
124 | |
125 | const QString *QLibraryInfoPrivate::qtconfManualPath = nullptr; |
126 | |
127 | QSettings *QLibraryInfoPrivate::configuration() |
128 | { |
129 | QLibrarySettings *ls = qt_library_settings(); |
130 | return ls ? ls->configuration() : nullptr; |
131 | } |
132 | |
133 | void QLibraryInfoPrivate::reload() |
134 | { |
135 | if (qt_library_settings.exists()) |
136 | qt_library_settings->load(); |
137 | } |
138 | |
139 | static bool havePaths() { |
140 | QLibrarySettings *ls = qt_library_settings(); |
141 | return ls && ls->havePaths(); |
142 | } |
143 | |
144 | #endif // settings |
145 | |
146 | /*! |
147 | \class QLibraryInfo |
148 | \inmodule QtCore |
149 | \brief The QLibraryInfo class provides information about the Qt library. |
150 | |
151 | Many pieces of information are established when Qt is configured and built. |
152 | This class provides an abstraction for accessing that information. |
153 | By using the static functions of this class, an application can obtain |
154 | information about the instance of the Qt library which the application |
155 | is using at run-time. |
156 | |
157 | You can also use a \c qt.conf file to override the hard-coded paths |
158 | that are compiled into the Qt library. For more information, see |
159 | the \l {Using qt.conf} documentation. |
160 | |
161 | \sa QSysInfo, {Using qt.conf} |
162 | */ |
163 | |
164 | /*! |
165 | \internal |
166 | |
167 | You cannot create a QLibraryInfo, instead only the static functions are available to query |
168 | information. |
169 | */ |
170 | |
171 | QLibraryInfo::QLibraryInfo() |
172 | { } |
173 | |
174 | #if defined(Q_CC_CLANG) // must be before GNU, because clang claims to be GNU too |
175 | # define COMPILER_STRING __VERSION__ /* already includes the compiler's name */ |
176 | #elif defined(Q_CC_GHS) |
177 | # define COMPILER_STRING "GHS " QT_STRINGIFY(__GHS_VERSION_NUMBER) |
178 | #elif defined(Q_CC_GNU) |
179 | # define COMPILER_STRING "GCC " __VERSION__ |
180 | #elif defined(Q_CC_MSVC) |
181 | # if _MSC_VER < 1910 |
182 | # define COMPILER_STRING "MSVC 2015" |
183 | # elif _MSC_VER < 1917 |
184 | # define COMPILER_STRING "MSVC 2017" |
185 | # elif _MSC_VER < 1930 |
186 | # define COMPILER_STRING "MSVC 2019" |
187 | # elif _MSC_VER < 2000 |
188 | # define COMPILER_STRING "MSVC 2022" |
189 | # else |
190 | # define COMPILER_STRING "MSVC _MSC_VER " QT_STRINGIFY(_MSC_VER) |
191 | # endif |
192 | #else |
193 | # define COMPILER_STRING "<unknown compiler>" |
194 | #endif |
195 | #ifdef QT_NO_DEBUG |
196 | # define DEBUG_STRING " release" |
197 | #else |
198 | # define DEBUG_STRING " debug" |
199 | #endif |
200 | #ifdef QT_SHARED |
201 | # define SHARED_STRING " shared (dynamic)" |
202 | #else |
203 | # define SHARED_STRING " static" |
204 | #endif |
205 | static const char *qt_build_string() noexcept |
206 | { |
207 | return "Qt " QT_VERSION_STR " (" ARCH_FULL SHARED_STRING DEBUG_STRING " build; by " COMPILER_STRING ")" ; |
208 | } |
209 | |
210 | /*! |
211 | Returns a string describing how this version of Qt was built. |
212 | |
213 | \internal |
214 | |
215 | \since 5.3 |
216 | */ |
217 | |
218 | const char *QLibraryInfo::build() noexcept |
219 | { |
220 | return qt_build_string(); |
221 | } |
222 | |
223 | /*! |
224 | \since 5.0 |
225 | Returns \c true if this build of Qt was built with debugging enabled, or |
226 | false if it was built in release mode. |
227 | */ |
228 | bool |
229 | QLibraryInfo::isDebugBuild() noexcept |
230 | { |
231 | #ifdef QT_DEBUG |
232 | return true; |
233 | #else |
234 | return false; |
235 | #endif |
236 | } |
237 | |
238 | /*! |
239 | \since 6.5 |
240 | Returns \c true if this is a shared (dynamic) build of Qt. |
241 | */ |
242 | bool QLibraryInfo::isSharedBuild() noexcept |
243 | { |
244 | #ifdef QT_SHARED |
245 | return true; |
246 | #else |
247 | return false; |
248 | #endif |
249 | } |
250 | |
251 | /*! |
252 | \since 5.8 |
253 | Returns the version of the Qt library. |
254 | |
255 | \sa qVersion() |
256 | */ |
257 | QVersionNumber QLibraryInfo::version() noexcept |
258 | { |
259 | return QVersionNumber(QT_VERSION_MAJOR, QT_VERSION_MINOR, QT_VERSION_PATCH); |
260 | } |
261 | |
262 | static QString prefixFromAppDirHelper() |
263 | { |
264 | QString appDir; |
265 | |
266 | if (QCoreApplication::instance()) { |
267 | #ifdef Q_OS_DARWIN |
268 | CFBundleRef bundleRef = CFBundleGetMainBundle(); |
269 | if (bundleRef) { |
270 | QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef); |
271 | if (urlRef) { |
272 | QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle); |
273 | #ifdef Q_OS_MACOS |
274 | QString bundleContentsDir = QString(path) + "/Contents/"_L1 ; |
275 | if (QDir(bundleContentsDir).exists()) |
276 | return QDir::cleanPath(bundleContentsDir); |
277 | #else |
278 | return QDir::cleanPath(QString(path)); // iOS |
279 | #endif // Q_OS_MACOS |
280 | } |
281 | } |
282 | #endif // Q_OS_DARWIN |
283 | // We make the prefix path absolute to the executable's directory. |
284 | appDir = QCoreApplication::applicationDirPath(); |
285 | } else { |
286 | appDir = QDir::currentPath(); |
287 | } |
288 | |
289 | return appDir; |
290 | } |
291 | |
292 | #if QT_CONFIG(relocatable) |
293 | #if !defined(QT_STATIC) && !(defined(Q_OS_DARWIN) && QT_CONFIG(framework)) \ |
294 | && (QT_CONFIG(dlopen) || defined(Q_OS_WIN)) |
295 | static QString prefixFromQtCoreLibraryHelper(const QString &qtCoreLibraryPath) |
296 | { |
297 | const QString qtCoreLibrary = QDir::fromNativeSeparators(pathName: qtCoreLibraryPath); |
298 | const QString libDir = QFileInfo(qtCoreLibrary).absolutePath(); |
299 | const QString prefixDir = libDir + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH; |
300 | return QDir::cleanPath(path: prefixDir); |
301 | } |
302 | #endif |
303 | |
304 | #if defined(Q_OS_WIN) |
305 | static HMODULE getWindowsModuleHandle() |
306 | { |
307 | HMODULE hModule = NULL; |
308 | GetModuleHandleEx( |
309 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, |
310 | (LPCTSTR)&QLibraryInfo::isDebugBuild, &hModule); |
311 | return hModule; |
312 | } |
313 | #endif // Q_OS_WIN |
314 | |
315 | static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode) |
316 | { |
317 | QString prefixPath; |
318 | |
319 | // For static builds, the prefix will be the app directory. |
320 | // For regular builds, the prefix will be relative to the location of the QtCore shared library. |
321 | #if defined(QT_STATIC) |
322 | prefixPath = prefixFromAppDirHelper(); |
323 | if (usageMode == QLibraryInfoPrivate::UsedFromQtBinDir) { |
324 | // For Qt tools in a static build, we must chop off the bin directory. |
325 | constexpr QByteArrayView binDir = qt_configure_strs.viewAt(QLibraryInfo::BinariesPath - 1); |
326 | constexpr size_t binDirLength = binDir.size() + 1; |
327 | prefixPath.chop(binDirLength); |
328 | } |
329 | #elif defined(Q_OS_DARWIN) && QT_CONFIG(framework) |
330 | Q_UNUSED(usageMode); |
331 | #ifndef QT_LIBINFIX |
332 | #define QT_LIBINFIX "" |
333 | #endif |
334 | auto qtCoreBundle = CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.QtCore" QT_LIBINFIX)); |
335 | if (!qtCoreBundle) { |
336 | // When running Qt apps over Samba shares, CoreFoundation will fail to find |
337 | // the Resources directory inside the bundle, This directory is a symlink, |
338 | // and CF relies on readdir() and dtent.dt_type to detect symlinks, which |
339 | // does not work reliably for Samba shares. We work around it by manually |
340 | // looking for the QtCore bundle. |
341 | auto allBundles = CFBundleGetAllBundles(); |
342 | auto bundleCount = CFArrayGetCount(allBundles); |
343 | for (int i = 0; i < bundleCount; ++i) { |
344 | auto bundle = CFBundleRef(CFArrayGetValueAtIndex(allBundles, i)); |
345 | auto url = QCFType<CFURLRef>(CFBundleCopyBundleURL(bundle)); |
346 | auto path = QCFType<CFStringRef>(CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle)); |
347 | if (CFStringHasSuffix(path, CFSTR("/QtCore" QT_LIBINFIX ".framework" ))) { |
348 | qtCoreBundle = bundle; |
349 | break; |
350 | } |
351 | } |
352 | } |
353 | Q_ASSERT(qtCoreBundle); |
354 | |
355 | QCFType<CFURLRef> qtCorePath = CFBundleCopyBundleURL(qtCoreBundle); |
356 | Q_ASSERT(qtCorePath); |
357 | |
358 | QCFType<CFURLRef> qtCorePathAbsolute = CFURLCopyAbsoluteURL(qtCorePath); |
359 | Q_ASSERT(qtCorePathAbsolute); |
360 | |
361 | QCFType<CFURLRef> libDirCFPath = CFURLCreateCopyDeletingLastPathComponent(NULL, qtCorePathAbsolute); |
362 | |
363 | const QCFString libDirCFString = CFURLCopyFileSystemPath(libDirCFPath, kCFURLPOSIXPathStyle); |
364 | |
365 | const QString prefixDir = QString(libDirCFString) + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH; |
366 | |
367 | prefixPath = QDir::cleanPath(prefixDir); |
368 | #elif QT_CONFIG(dlopen) |
369 | Q_UNUSED(usageMode); |
370 | Dl_info info; |
371 | int result = dladdr(address: reinterpret_cast<void *>(&QLibraryInfo::isDebugBuild), info: &info); |
372 | if (result > 0 && info.dli_fname) |
373 | prefixPath = prefixFromQtCoreLibraryHelper(qtCoreLibraryPath: QString::fromLocal8Bit(ba: info.dli_fname)); |
374 | #elif defined(Q_OS_WIN) |
375 | Q_UNUSED(usageMode); |
376 | HMODULE hModule = getWindowsModuleHandle(); |
377 | const int kBufferSize = 4096; |
378 | wchar_t buffer[kBufferSize]; |
379 | DWORD pathSize = GetModuleFileName(hModule, buffer, kBufferSize); |
380 | const QString qtCoreFilePath = QString::fromWCharArray(buffer, int(pathSize)); |
381 | const QString qtCoreDirPath = QFileInfo(qtCoreFilePath).absolutePath(); |
382 | pathSize = GetModuleFileName(NULL, buffer, kBufferSize); |
383 | const QString exeDirPath = QFileInfo(QString::fromWCharArray(buffer, int(pathSize))).absolutePath(); |
384 | if (QFileInfo(exeDirPath) == QFileInfo(qtCoreDirPath)) { |
385 | // QtCore DLL is next to the executable. This is either a windeployqt'ed executable or an |
386 | // executable within the QT_HOST_BIN directory. We're detecting the latter case by checking |
387 | // whether there's an import library corresponding to our QtCore DLL in PREFIX/lib. |
388 | const QString libdir = QString::fromLocal8Bit( |
389 | qt_configure_strs.viewAt(QLibraryInfo::LibrariesPath - 1)); |
390 | const QLatin1Char slash('/'); |
391 | #if defined(Q_CC_MINGW) |
392 | const QString implibPrefix = QStringLiteral("lib" ); |
393 | const QString implibSuffix = QStringLiteral(".a" ); |
394 | #else |
395 | const QString implibPrefix; |
396 | const QString implibSuffix = QStringLiteral(".lib" ); |
397 | #endif |
398 | const QString qtCoreImpLibFileName = implibPrefix |
399 | + QFileInfo(qtCoreFilePath).completeBaseName() + implibSuffix; |
400 | const QString qtCoreImpLibPath = qtCoreDirPath |
401 | + slash + QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH |
402 | + slash + libdir |
403 | + slash + qtCoreImpLibFileName; |
404 | if (!QFileInfo::exists(qtCoreImpLibPath)) { |
405 | // We did not find a corresponding import library and conclude that this is a |
406 | // windeployqt'ed executable. |
407 | return exeDirPath; |
408 | } |
409 | } |
410 | if (!qtCoreFilePath.isEmpty()) |
411 | prefixPath = prefixFromQtCoreLibraryHelper(qtCoreFilePath); |
412 | #else |
413 | #error "The chosen platform / config does not support querying for a dynamic prefix." |
414 | #endif |
415 | |
416 | #if defined(Q_OS_LINUX) && !defined(QT_STATIC) && defined(__GLIBC__) |
417 | // QTBUG-78948: libQt5Core.so may be located in subdirectories below libdir. |
418 | // See "Hardware capabilities" in the ld.so documentation and the Qt 5.3.0 |
419 | // changelog regarding SSE2 support. |
420 | const QString libdir = QString::fromLocal8Bit( |
421 | ba: qt_configure_strs.viewAt(index: QLibraryInfo::LibrariesPath - 1)); |
422 | QDir prefixDir(prefixPath); |
423 | while (!prefixDir.exists(name: libdir)) { |
424 | prefixDir.cdUp(); |
425 | prefixPath = prefixDir.absolutePath(); |
426 | if (prefixDir.isRoot()) { |
427 | prefixPath.clear(); |
428 | break; |
429 | } |
430 | } |
431 | #endif |
432 | |
433 | Q_ASSERT_X(!prefixPath.isEmpty(), "getRelocatablePrefix" , |
434 | "Failed to find the Qt prefix path." ); |
435 | return prefixPath; |
436 | } |
437 | #endif |
438 | |
439 | static QString getPrefix(QLibraryInfoPrivate::UsageMode usageMode) |
440 | { |
441 | #if QT_CONFIG(relocatable) |
442 | return getRelocatablePrefix(usageMode); |
443 | #else |
444 | Q_UNUSED(usageMode); |
445 | return QString::fromLocal8Bit(QT_CONFIGURE_PREFIX_PATH); |
446 | #endif |
447 | } |
448 | |
449 | QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo::LibraryPath loc) |
450 | { |
451 | /* |
452 | * To add a new entry in QLibraryInfo::LibraryPath, add it to the enum |
453 | * in qtbase/src/corelib/global/qlibraryinfo.h and: |
454 | * - add its relative path in the qtConfEntries[] array below |
455 | * (the key is what appears in a qt.conf file) |
456 | */ |
457 | static constexpr auto qtConfEntries = qOffsetStringArray( |
458 | strings: "Prefix" , strings: "." , |
459 | strings: "Documentation" , strings: "doc" , // should be ${Data}/doc |
460 | strings: "Headers" , strings: "include" , |
461 | strings: "Libraries" , strings: "lib" , |
462 | #ifdef Q_OS_WIN |
463 | "LibraryExecutables" , "bin" , |
464 | #else |
465 | strings: "LibraryExecutables" , strings: "libexec" , // should be ${ArchData}/libexec |
466 | #endif |
467 | strings: "Binaries" , strings: "bin" , |
468 | strings: "Plugins" , strings: "plugins" , // should be ${ArchData}/plugins |
469 | |
470 | strings: "QmlImports" , strings: "qml" , // should be ${ArchData}/qml |
471 | |
472 | strings: "ArchData" , strings: "." , |
473 | strings: "Data" , strings: "." , |
474 | strings: "Translations" , strings: "translations" , // should be ${Data}/translations |
475 | strings: "Examples" , strings: "examples" , |
476 | strings: "Tests" , strings: "tests" |
477 | ); |
478 | constexpr QByteArrayView dot{"." }; |
479 | |
480 | LocationInfo result; |
481 | |
482 | if (int(loc) < qtConfEntries.count()) { |
483 | result.key = QLatin1StringView(qtConfEntries.viewAt(index: loc * 2)); |
484 | result.defaultValue = QLatin1StringView(qtConfEntries.viewAt(index: loc * 2 + 1)); |
485 | if (result.key == u"QmlImports" ) |
486 | result.fallbackKey = u"Qml2Imports"_s ; |
487 | #ifndef Q_OS_WIN // On Windows we use the registry |
488 | } else if (loc == QLibraryInfo::SettingsPath) { |
489 | result.key = "Settings"_L1 ; |
490 | result.defaultValue = QLatin1StringView(dot); |
491 | #endif |
492 | } |
493 | |
494 | return result; |
495 | } |
496 | |
497 | /*! \fn QString QLibraryInfo::location(LibraryLocation loc) |
498 | \deprecated [6.0] Use path() instead. |
499 | |
500 | Returns the path specified by \a loc. |
501 | */ |
502 | |
503 | /*! |
504 | \since 6.0 |
505 | Returns the path specified by \a p. |
506 | */ |
507 | QString QLibraryInfo::path(LibraryPath p) |
508 | { |
509 | return QLibraryInfoPrivate::path(p); |
510 | } |
511 | |
512 | |
513 | /* |
514 | Returns the path specified by \a p. |
515 | |
516 | The usage mode can be set to UsedFromQtBinDir to enable special handling for executables that |
517 | live in <install-prefix>/bin. |
518 | */ |
519 | QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMode) |
520 | { |
521 | const QLibraryInfo::LibraryPath loc = p; |
522 | QString ret; |
523 | bool fromConf = false; |
524 | #if QT_CONFIG(settings) |
525 | if (havePaths()) { |
526 | fromConf = true; |
527 | |
528 | auto li = QLibraryInfoPrivate::locationInfo(loc); |
529 | if (!li.key.isNull()) { |
530 | QSettings *config = QLibraryInfoPrivate::configuration(); |
531 | Q_ASSERT(config != nullptr); |
532 | config->beginGroup(prefix: "Paths"_L1 ); |
533 | |
534 | if (li.fallbackKey.isNull()) { |
535 | ret = config->value(key: li.key, defaultValue: li.defaultValue).toString(); |
536 | } else { |
537 | QVariant v = config->value(key: li.key); |
538 | if (!v.isValid()) |
539 | v = config->value(key: li.fallbackKey, defaultValue: li.defaultValue); |
540 | ret = v.toString(); |
541 | } |
542 | |
543 | qsizetype startIndex = 0; |
544 | while (true) { |
545 | startIndex = ret.indexOf(c: u'$', from: startIndex); |
546 | if (startIndex < 0) |
547 | break; |
548 | if (ret.size() < startIndex + 3) |
549 | break; |
550 | if (ret.at(i: startIndex + 1) != u'(') { |
551 | startIndex++; |
552 | continue; |
553 | } |
554 | qsizetype endIndex = ret.indexOf(c: u')', from: startIndex + 2); |
555 | if (endIndex < 0) |
556 | break; |
557 | auto envVarName = QStringView{ret}.mid(pos: startIndex + 2, n: endIndex - startIndex - 2); |
558 | QString value = QString::fromLocal8Bit(ba: qgetenv(varName: envVarName.toLocal8Bit().constData())); |
559 | ret.replace(i: startIndex, len: endIndex - startIndex + 1, after: value); |
560 | startIndex += value.size(); |
561 | } |
562 | |
563 | config->endGroup(); |
564 | |
565 | ret = QDir::fromNativeSeparators(pathName: ret); |
566 | } |
567 | } |
568 | #endif // settings |
569 | |
570 | if (!fromConf) { |
571 | if (loc == QLibraryInfo::PrefixPath) { |
572 | ret = getPrefix(usageMode); |
573 | } else if (int(loc) <= qt_configure_strs.count()) { |
574 | ret = QString::fromLocal8Bit(ba: qt_configure_strs.viewAt(index: loc - 1)); |
575 | #ifndef Q_OS_WIN // On Windows we use the registry |
576 | } else if (loc == QLibraryInfo::SettingsPath) { |
577 | // Use of volatile is a hack to discourage compilers from calling |
578 | // strlen(), in the inlined fromLocal8Bit(const char *)'s body, at |
579 | // compile-time, as Qt installers binary-patch the path, replacing |
580 | // the dummy path seen at compile-time, typically changing length. |
581 | const char *volatile path = QT_CONFIGURE_SETTINGS_PATH; |
582 | ret = QString::fromLocal8Bit(ba: path); |
583 | #endif |
584 | } |
585 | } |
586 | |
587 | if (!ret.isEmpty() && QDir::isRelativePath(path: ret)) { |
588 | QString baseDir; |
589 | if (loc == QLibraryInfo::PrefixPath) { |
590 | baseDir = prefixFromAppDirHelper(); |
591 | } else { |
592 | // we make any other path absolute to the prefix directory |
593 | baseDir = path(p: QLibraryInfo::PrefixPath, usageMode); |
594 | } |
595 | ret = QDir::cleanPath(path: baseDir + u'/' + ret); |
596 | } |
597 | return ret; |
598 | } |
599 | |
600 | /*! |
601 | Returns additional arguments to the platform plugin matching |
602 | \a platformName which can be specified as a string list using |
603 | the key \c Arguments in a group called \c Platforms of the |
604 | \c qt.conf file. |
605 | |
606 | sa {Using qt.conf} |
607 | |
608 | \internal |
609 | |
610 | \since 5.3 |
611 | */ |
612 | |
613 | QStringList QLibraryInfo::platformPluginArguments(const QString &platformName) |
614 | { |
615 | #if QT_CONFIG(settings) |
616 | QScopedPointer<const QSettings> settings(findConfiguration()); |
617 | if (!settings.isNull()) { |
618 | const QString key = "Platforms/"_L1 |
619 | + platformName |
620 | + "Arguments"_L1 ; |
621 | return settings->value(key).toStringList(); |
622 | } |
623 | #else |
624 | Q_UNUSED(platformName); |
625 | #endif // settings |
626 | return QStringList(); |
627 | } |
628 | |
629 | /*! |
630 | \enum QLibraryInfo::LibraryPath |
631 | |
632 | \keyword library location |
633 | |
634 | This enum type is used to query for a specific path: |
635 | |
636 | \value PrefixPath The default prefix for all paths. |
637 | \value DocumentationPath The path to documentation upon install. |
638 | \value HeadersPath The path to all headers. |
639 | \value LibrariesPath The path to installed libraries. |
640 | \value LibraryExecutablesPath The path to installed executables required by libraries at runtime. |
641 | \value BinariesPath The path to installed Qt binaries (tools and applications). |
642 | \value PluginsPath The path to installed Qt plugins. |
643 | \value QmlImportsPath The path to installed QML extensions to import. |
644 | \value Qml2ImportsPath This value is deprecated. Use QmlImportsPath instead. |
645 | \value ArchDataPath The path to general architecture-dependent Qt data. |
646 | \value DataPath The path to general architecture-independent Qt data. |
647 | \value TranslationsPath The path to translation information for Qt strings. |
648 | \value ExamplesPath The path to examples upon install. |
649 | \value TestsPath The path to installed Qt testcases. |
650 | \value SettingsPath The path to Qt settings. Not applicable on Windows. |
651 | |
652 | \sa path() |
653 | */ |
654 | |
655 | /*! |
656 | \typealias QLibraryInfo::LibraryLocation |
657 | \deprecated Use LibraryPath with QLibraryInfo::path() instead. |
658 | */ |
659 | |
660 | /*! |
661 | \macro QT_VERSION_STR |
662 | \relates <QtVersion> |
663 | |
664 | This macro expands to a string that specifies Qt's version number (for |
665 | example, "6.1.2"). This is the version with which the application is |
666 | compiled. This may be a different version than the version the application |
667 | will find itself using at \e runtime. |
668 | |
669 | \sa qVersion(), QT_VERSION |
670 | */ |
671 | |
672 | /*! |
673 | \relates <QtVersion> |
674 | |
675 | Returns the version number of Qt at runtime as a string (for example, |
676 | "6.1.2"). This is the version of the Qt library in use at \e runtime, |
677 | which need not be the version the application was \e compiled with. |
678 | |
679 | \sa QT_VERSION_STR, QLibraryInfo::version() |
680 | */ |
681 | |
682 | const char *qVersion() noexcept |
683 | { |
684 | return QT_VERSION_STR; |
685 | } |
686 | |
687 | #if QT_DEPRECATED_SINCE(6, 9) |
688 | |
689 | bool qSharedBuild() noexcept |
690 | { |
691 | return QLibraryInfo::isSharedBuild(); |
692 | } |
693 | |
694 | #endif // QT_DEPRECATED_SINCE(6, 9) |
695 | |
696 | QT_END_NAMESPACE |
697 | |
698 | #if defined(Q_CC_GNU) && defined(ELF_INTERPRETER) |
699 | # include <elf.h> |
700 | # include <stdio.h> |
701 | # include <stdlib.h> |
702 | |
703 | #include "private/qcoreapplication_p.h" |
704 | |
705 | QT_WARNING_DISABLE_GCC("-Wformat-overflow" ) |
706 | QT_WARNING_DISABLE_GCC("-Wattributes" ) |
707 | QT_WARNING_DISABLE_CLANG("-Wattributes" ) |
708 | QT_WARNING_DISABLE_INTEL(2621) |
709 | |
710 | # if defined(Q_OS_LINUX) |
711 | # include "minimum-linux_p.h" |
712 | # endif |
713 | # ifdef QT_ELF_NOTE_OS_TYPE |
714 | struct ElfNoteAbiTag |
715 | { |
716 | static_assert(sizeof(Elf32_Nhdr) == sizeof(Elf64_Nhdr), |
717 | "The size of an ELF note is wrong (should be 12 bytes)" ); |
718 | struct Payload { |
719 | Elf32_Word ostype = QT_ELF_NOTE_OS_TYPE; |
720 | Elf32_Word major = QT_ELF_NOTE_OS_MAJOR; |
721 | Elf32_Word minor = QT_ELF_NOTE_OS_MINOR; |
722 | # ifdef QT_ELF_NOTE_OS_PATCH |
723 | Elf32_Word patch = QT_ELF_NOTE_OS_PATCH; |
724 | # endif |
725 | }; |
726 | |
727 | Elf32_Nhdr = { |
728 | .n_namesz = sizeof(name), |
729 | .n_descsz = sizeof(Payload), |
730 | .n_type = NT_GNU_ABI_TAG |
731 | }; |
732 | char name[sizeof ELF_NOTE_GNU] = ELF_NOTE_GNU; // yes, include the null terminator |
733 | Payload payload = {}; |
734 | }; |
735 | __attribute__((section(".note.ABI-tag" ), aligned(4), used)) |
736 | extern constexpr ElfNoteAbiTag QT_MANGLE_NAMESPACE(qt_abi_tag) = {}; |
737 | # endif |
738 | |
739 | extern const char qt_core_interpreter[] __attribute__((section(".interp" ))) |
740 | = ELF_INTERPRETER; |
741 | |
742 | extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer)); |
743 | void qt_core_boilerplate() |
744 | { |
745 | printf(format: "This is the QtCore library version %s\n" |
746 | "Copyright (C) 2016 The Qt Company Ltd.\n" |
747 | "Contact: http://www.qt.io/licensing/\n" |
748 | "\n" |
749 | "Installation prefix: %s\n" |
750 | "Library path: %s\n" |
751 | "Plugin path: %s\n" , |
752 | QT_PREPEND_NAMESPACE(qt_build_string)(), |
753 | QT_CONFIGURE_PREFIX_PATH, |
754 | qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1], |
755 | qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]); |
756 | |
757 | QT_PREPEND_NAMESPACE(qDumpCPUFeatures)(); |
758 | |
759 | exit(status: 0); |
760 | } |
761 | |
762 | #endif |
763 | |