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