source: trunk/src/corelib/global/qlibraryinfo.cpp@ 494

Last change on this file since 494 was 424, checked in by Dmitry A. Kuminov, 15 years ago

corelib: QLibraryInfo: Changed default "Settings" path to %ETC%/xdg. Also use %ETC%/qtsys.conf as the system-wide qt.conf instead of %ETC%/qt/qtsys.conf.

File size: 22.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdir.h"
43#include "qfile.h"
44#include "qconfig.h"
45#include "qsettings.h"
46#include "qlibraryinfo.h"
47#include "qpointer.h"
48
49#ifdef QT_BUILD_QMAKE
50QT_BEGIN_NAMESPACE
51extern QString qmake_libraryInfoFile();
52QT_END_NAMESPACE
53#else
54# include "qcoreapplication.h"
55#endif
56
57#ifdef Q_OS_MAC
58# include "private/qcore_mac_p.h"
59#endif
60
61#ifdef Q_OS_OS2
62
63#include "qt_os2.h"
64
65static const char *qt_module_path()
66{
67 static char path[CCHMAXPATH] = {'\0'};
68 if (!path[0]) {
69 HMODULE hmod;
70 ULONG objNum, offset;
71 DosQueryModFromEIP(&hmod, &objNum, sizeof(path), path, &offset,
72 (ULONG)qt_module_path);
73 DosQueryModuleName(hmod, sizeof(path), path);
74 char *slash = strrchr(path, '\\');
75 if (slash)
76 *slash = '\0';
77 }
78 return path;
79}
80
81#endif // Q_OS_OS2
82
83#include "qconfig.cpp"
84
85QT_BEGIN_NAMESPACE
86
87#ifndef QT_NO_SETTINGS
88
89struct QLibrarySettings
90{
91 QLibrarySettings();
92 ~QLibrarySettings() { delete static_cast<QSettings *>(settings); }
93 QSettings *settings;
94};
95Q_GLOBAL_STATIC(QLibrarySettings, qt_library_settings)
96
97class QLibraryInfoPrivate
98{
99public:
100 static QSettings *findConfiguration();
101 static void cleanup()
102 {
103 QLibrarySettings *ls = qt_library_settings();
104 if (ls) {
105 delete static_cast<QSettings *>(ls->settings);
106 ls->settings = 0;
107 }
108 }
109 static QSettings *configuration()
110 {
111#ifdef QT_NO_THREAD
112 // This recursion guard should be a temporary solution; the recursive
113 // dependency should be found and removed.
114 static bool initializing = false;
115 if (initializing)
116 return 0;
117 initializing = true;
118#endif
119 QLibrarySettings *ls = qt_library_settings();
120#ifdef QT_NO_THREAD
121 initializing = false;
122#endif
123 return ls ? static_cast<QSettings *>(qt_library_settings()->settings) : (QSettings*)0;
124 }
125};
126
127QLibrarySettings::QLibrarySettings()
128{
129 settings = QLibraryInfoPrivate::findConfiguration();
130#ifndef QT_BUILD_QMAKE
131 qAddPostRoutine(QLibraryInfoPrivate::cleanup);
132#endif
133}
134
135QSettings *QLibraryInfoPrivate::findConfiguration()
136{
137 QString qtconfig = QLatin1String(":/qt/etc/qt.conf");
138#ifdef QT_BUILD_QMAKE
139 if(!QFile::exists(qtconfig))
140 qtconfig = qmake_libraryInfoFile();
141#else
142 if (!QFile::exists(qtconfig) && QCoreApplication::instance()) {
143#ifdef Q_OS_MAC
144 CFBundleRef bundleRef = CFBundleGetMainBundle();
145 if (bundleRef) {
146 QCFType<CFURLRef> urlRef = CFBundleCopyResourceURL(bundleRef,
147 QCFString(QLatin1String("qt.conf")),
148 0,
149 0);
150 if (urlRef) {
151 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
152 qtconfig = QDir::cleanPath(path);
153 }
154 }
155 if (qtconfig.isEmpty())
156#endif
157 {
158 QDir pwd(QCoreApplication::applicationDirPath());
159 qtconfig = pwd.filePath(QLatin1String("qt.conf"));
160 }
161 }
162#ifdef Q_OS_OS2
163 if (!QFile::exists(qtconfig)) {
164 // search in the directory that contains the DLL or EXE where this
165 // code is located (e.g. QtCore.dll or app.exe if Qt is a static lib)
166 qtconfig = QString::fromLocal8Bit(qt_module_path());
167 qtconfig = QDir::fromNativeSeparators(qtconfig) +
168 QLatin1String("/qt.conf");
169 qtconfig = QDir::cleanPath(qtconfig);
170
171 if (!QFile::exists(qtconfig)) {
172 // search in the system-wide location
173 qtconfig = QString::fromLocal8Bit(qgetenv("ETC"));
174 if (qtconfig.isEmpty())
175 qtconfig = QDir::rootPath();
176 qtconfig = QDir::fromNativeSeparators(qtconfig) +
177 QLatin1String("/qtsys.conf");
178 qtconfig = QDir::cleanPath(qtconfig);
179 }
180 }
181#endif
182#endif
183 if (QFile::exists(qtconfig))
184 return new QSettings(qtconfig, QSettings::IniFormat);
185 return 0; //no luck
186}
187
188/*!
189 \class QLibraryInfo
190 \brief The QLibraryInfo class provides information about the Qt library.
191
192 \ingroup misc
193 \mainclass
194
195 Many pieces of information are established when Qt is configured.
196 Installation paths, license information, and even a unique build
197 key. This class provides an abstraction for accessing this
198 information.
199
200 \table
201 \header \o Function \o Return value
202 \row \o buildKey() \o A string that identifies the Qt version and
203 the configuration. This key is used to ensure
204 that \l{plugins} link against the same version
205 of Qt as the application.
206 \row \o location() \o The path to a certain Qt
207 component (e.g., documentation, header files).
208 \row \o licensee(),
209 licensedProducts() \o Licensing information.
210 \endtable
211
212 You can also use a \c qt.conf file to override the hard-coded paths
213 that are compiled into the Qt library. For more information, see
214 the \l {Using qt.conf} documentation.
215
216 \sa QSysInfo, {Using qt.conf}
217*/
218
219/*! \internal
220
221 You cannot create a QLibraryInfo, instead only the static functions are available to query
222 information.
223*/
224
225QLibraryInfo::QLibraryInfo()
226{ }
227
228/*!
229 Returns the person to whom this build of Qt is licensed.
230
231 \sa licensedProducts()
232*/
233
234QString
235QLibraryInfo::licensee()
236{
237 const char *str = QT_CONFIGURE_LICENSEE;
238 return QString::fromLocal8Bit(str);
239}
240
241/*!
242 Returns the products that the license for this build of Qt has access to.
243
244 \sa licensee()
245*/
246
247QString
248QLibraryInfo::licensedProducts()
249{
250 const char *str = QT_CONFIGURE_LICENSED_PRODUCTS;
251 return QString::fromLatin1(str);
252}
253
254/*!
255 Returns a unique key identifying this build of Qt and its
256 configurations. This key is not globally unique, rather only useful
257 for establishing of two configurations are compatible. This can be
258 used to compare with the \c QT_BUILD_KEY preprocessor symbol.
259
260 \sa location()
261*/
262
263QString
264QLibraryInfo::buildKey()
265{
266 return QString::fromLatin1(QT_BUILD_KEY);
267}
268
269/*!
270 Returns the location specified by \a loc.
271
272*/
273
274QString
275QLibraryInfo::location(LibraryLocation loc)
276{
277 QString ret;
278 if(!QLibraryInfoPrivate::configuration()) {
279 const char *path = 0;
280 switch (loc) {
281#ifdef QT_CONFIGURE_PREFIX_PATH
282 case PrefixPath:
283 path = QT_CONFIGURE_PREFIX_PATH;
284 break;
285#endif
286#ifdef QT_CONFIGURE_DOCUMENTATION_PATH
287 case DocumentationPath:
288 path = QT_CONFIGURE_DOCUMENTATION_PATH;
289 break;
290#endif
291#ifdef QT_CONFIGURE_HEADERS_PATH
292 case HeadersPath:
293 path = QT_CONFIGURE_HEADERS_PATH;
294 break;
295#endif
296#ifdef QT_CONFIGURE_LIBRARIES_PATH
297 case LibrariesPath:
298 path = QT_CONFIGURE_LIBRARIES_PATH;
299 break;
300#endif
301#ifdef QT_CONFIGURE_BINARIES_PATH
302 case BinariesPath:
303 path = QT_CONFIGURE_BINARIES_PATH;
304 break;
305#endif
306#ifdef QT_CONFIGURE_PLUGINS_PATH
307 case PluginsPath:
308 path = QT_CONFIGURE_PLUGINS_PATH;
309 break;
310#endif
311#ifdef QT_CONFIGURE_DATA_PATH
312 case DataPath:
313 path = QT_CONFIGURE_DATA_PATH;
314 break;
315#endif
316#ifdef QT_CONFIGURE_TRANSLATIONS_PATH
317 case TranslationsPath:
318 path = QT_CONFIGURE_TRANSLATIONS_PATH;
319 break;
320#endif
321#ifdef QT_CONFIGURE_SETTINGS_PATH
322 case SettingsPath:
323 path = QT_CONFIGURE_SETTINGS_PATH;
324 break;
325#endif
326#ifdef QT_CONFIGURE_EXAMPLES_PATH
327 case ExamplesPath:
328 path = QT_CONFIGURE_EXAMPLES_PATH;
329 break;
330#endif
331#ifdef QT_CONFIGURE_DEMOS_PATH
332 case DemosPath:
333 path = QT_CONFIGURE_DEMOS_PATH;
334 break;
335#endif
336 default:
337 break;
338 }
339
340 if (path) {
341 ret = QString::fromLocal8Bit(path);
342#ifdef Q_OS_OS2
343 // expand environment variables in the form $(ENVVAR)
344 int rep;
345 QRegExp reg_var(QLatin1String("\\$\\(.*\\)"));
346 reg_var.setMinimal(true);
347 while((rep = reg_var.indexIn(ret)) != -1) {
348 ret.replace(rep, reg_var.matchedLength(),
349 QFile::decodeName(qgetenv(ret.mid(rep + 2,
350 reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
351 }
352#endif
353 }
354 } else {
355 QString key;
356 QString defaultValue;
357 switch(loc) {
358 case PrefixPath:
359 key = QLatin1String("Prefix");
360 break;
361 case DocumentationPath:
362 key = QLatin1String("Documentation");
363 defaultValue = QLatin1String("doc");
364 break;
365 case HeadersPath:
366 key = QLatin1String("Headers");
367 defaultValue = QLatin1String("include");
368 break;
369 case LibrariesPath:
370 key = QLatin1String("Libraries");
371 defaultValue = QLatin1String("lib");
372 break;
373 case BinariesPath:
374 key = QLatin1String("Binaries");
375 defaultValue = QLatin1String("bin");
376 break;
377 case PluginsPath:
378 key = QLatin1String("Plugins");
379 defaultValue = QLatin1String("plugins");
380 break;
381 case DataPath:
382 key = QLatin1String("Data");
383 break;
384 case TranslationsPath:
385 key = QLatin1String("Translations");
386 defaultValue = QLatin1String("translations");
387 break;
388 case SettingsPath:
389 key = QLatin1String("Settings");
390 break;
391 case ExamplesPath:
392 key = QLatin1String("Examples");
393 break;
394 case DemosPath:
395 key = QLatin1String("Demos");
396 break;
397 default:
398 break;
399 }
400
401 if(!key.isNull()) {
402 QSettings *config = QLibraryInfoPrivate::configuration();
403 config->beginGroup(QLatin1String("Paths"));
404
405 QString subKey;
406 {
407 /*
408 find the child group whose version number is closest
409 to the library version. for example and we have the
410 following groups:
411
412 Paths
413 Paths/4.0
414 Paths/4.1.2
415 Paths/4.2.5
416 Paths/5
417
418 if QT_VERSION is 4.0.1, then we use 'Paths/4.0'
419 if QT_VERSION is 4.1.5, then we use 'Paths/4.1.2'
420 if QT_VERSION is 4.6.3, then we use 'Paths/4.2.5'
421 if QT_VERSION is 6.0.2, then we use 'Paths/5'
422
423 note: any of the trailing version numbers may be
424 omitted (in which case, they default to zero),
425 i.e. 4 == 4.0.0, 4.1 == 4.1.0, and so on
426 */
427 enum {
428 QT_MAJOR = ((QT_VERSION >> 16) & 0xFF),
429 QT_MINOR = ((QT_VERSION >> 8) & 0xFF),
430 QT_PATCH = (QT_VERSION & 0xFF)
431 };
432 int maj = 0, min = 0, pat = 0;
433 QStringList children = config->childGroups();
434 for(int child = 0; child < children.size(); ++child) {
435 QString cver = children.at(child);
436 QStringList cver_list = cver.split(QLatin1Char('.'));
437 if(cver_list.size() > 0 && cver_list.size() < 4) {
438 bool ok;
439 int cmaj = -1, cmin = -1, cpat = -1;
440 cmaj = cver_list[0].toInt(&ok);
441 if(!ok || cmaj < 0)
442 continue;
443 if(cver_list.size() >= 2) {
444 cmin = cver_list[1].toInt(&ok);
445 if(!ok)
446 continue;
447 if(cmin < 0)
448 cmin = -1;
449 }
450 if(cver_list.size() >= 3) {
451 cpat = cver_list[2].toInt(&ok);
452 if(!ok)
453 continue;
454 if(cpat < 0)
455 cpat = -1;
456 }
457 if((cmaj >= maj && cmaj <= QT_MAJOR) &&
458 (cmin == -1 || (cmin >= min && cmin <= QT_MINOR)) &&
459 (cpat == -1 || (cpat >= pat && cpat <= QT_PATCH)) &&
460 config->contains(cver + QLatin1Char('/') + key)) {
461 subKey = cver + QLatin1Char('/');
462 maj = cmaj;
463 min = cmin;
464 pat = cpat;
465 }
466 }
467 }
468 }
469 ret = config->value(subKey + key, defaultValue).toString();
470 // expand environment variables in the form $(ENVVAR)
471 int rep;
472 QRegExp reg_var(QLatin1String("\\$\\(.*\\)"));
473 reg_var.setMinimal(true);
474 while((rep = reg_var.indexIn(ret)) != -1) {
475 ret.replace(rep, reg_var.matchedLength(),
476 QFile::decodeName(qgetenv(ret.mid(rep + 2,
477 reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
478 }
479 config->endGroup();
480 }
481 }
482
483#ifdef Q_OS_OS2
484
485 // QDir::isRelativePath() isn't precise on OS/2 (see
486 // QDir::absoluteFilePath()) therefore we don't rely on it
487 if (loc == PrefixPath) {
488#ifdef QT_BUILD_QMAKE
489 QFileInfo fi(qmake_libraryInfoFile());
490 return QDir::cleanPath(QDir(fi.absolutePath()).absoluteFilePath(ret));
491#else
492 QSettings *config = QLibraryInfoPrivate::configuration();
493 if (config) {
494 // if we read paths from qt[sys].conf, the Prefix is relative to
495 // the directory we load qt[sys].conf from
496 QFileInfo fi(config->fileName());
497 return QDir::cleanPath(QDir(fi.absolutePath()).absoluteFilePath(ret));
498 } else {
499 // we make the prefix path absolute to the executable's directory
500 if (QCoreApplication::instance()) {
501 return QDir::cleanPath(QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(ret));
502 }
503 return QDir::current().absoluteFilePath(ret);
504 }
505#endif
506 }
507
508 // we make any other path absolute to the prefix directory
509 return QDir::cleanPath(QDir(location(PrefixPath)).absoluteFilePath(ret));
510
511#else // #ifdef Q_OS_OS2
512
513 if (QDir::isRelativePath(ret)) {
514 if (loc == PrefixPath) {
515 // we make the prefix path absolute to the executable's directory
516#ifdef QT_BUILD_QMAKE
517 QFileInfo fi(qmake_libraryInfoFile());
518 return QDir::cleanPath(QDir(fi.absolutePath()).absoluteFilePath(ret));
519#else
520 if (QCoreApplication::instance()) {
521#ifdef Q_OS_MAC
522 CFBundleRef bundleRef = CFBundleGetMainBundle();
523 if (bundleRef) {
524 QCFType<CFURLRef> urlRef = CFBundleCopyBundleURL(bundleRef);
525 if (urlRef) {
526 QCFString path = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle);
527 return QDir::cleanPath(path + QLatin1String("/Contents"));
528 }
529 }
530#endif
531 return QDir::cleanPath(QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(ret));
532 } else {
533 return QDir::current().absoluteFilePath(ret);
534 }
535#endif
536 } else {
537 // we make any other path absolute to the prefix directory
538 return QDir::cleanPath(QDir(location(PrefixPath)).absoluteFilePath(ret));
539 }
540 }
541 return QDir::cleanPath(ret);
542
543#endif // #ifdef Q_OS_OS2
544}
545
546/*!
547 \enum QLibraryInfo::LibraryLocation
548
549 \keyword library location
550
551 This enum type is used to specify a specific location
552 specifier:
553
554 \value PrefixPath The default prefix for all paths.
555 \value DocumentationPath The location for documentation upon install.
556 \value HeadersPath The location for all headers.
557 \value LibrariesPath The location of installed librarires.
558 \value BinariesPath The location of installed Qt binaries (tools and applications).
559 \value PluginsPath The location of installed Qt plugins.
560 \value DataPath The location of general Qt data.
561 \value TranslationsPath The location of translation information for Qt strings.
562 \value SettingsPath The location for Qt settings.
563 \value ExamplesPath The location for examples upon install.
564 \value DemosPath The location for demos upon install.
565
566 \sa location()
567*/
568
569#endif // QT_NO_SETTINGS
570
571QT_END_NAMESPACE
572
573#if defined(Q_CC_GNU) && defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) && !defined(QT_BOOTSTRAPPED)
574
575# include <sys/syscall.h>
576# include <unistd.h>
577
578static const char boilerplate[] =
579 "This is the QtCore library version " QT_VERSION_STR "\n"
580 "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).\n"
581 "Contact: Qt Software Information ([email protected])\n"
582 "\n"
583 "Build key: " QT_BUILD_KEY;
584
585extern "C" {
586void qt_core_init_boilerplate() __attribute__((noreturn));
587}
588
589# if defined(QT_ARCH_I386)
590#define sysinit() (void)0
591#define syswrite(msg, len) \
592 ({ int res; \
593 asm volatile ("movl %%ebx, %%edi\n" \
594 "movl $1, %%ebx\n" \
595 "int $0x80\n" \
596 "movl %%edi, %%ebx\n" \
597 : "=a" (res) : "0" (SYS_write), "c" (msg), "d" (len) : "edi"); res; })
598#define sysexit(c) \
599 asm ("xor %%ebx, %%ebx\n" \
600 "int $0x80\n" \
601 : : "a" (SYS_exit)); _exit(c)
602
603# elif defined(QT_ARCH_X86_64)
604#define sysinit() (void)0
605#define syswrite(msg, len) \
606 ({ int res; \
607 asm volatile ("syscall\n" \
608 : "=a" (res) : "0" (SYS_write), "D" (1), "S" (msg), "d" (len) : "rcx"); res; })
609#define sysexit(c) \
610 asm ("syscall\n" \
611 : : "a" (SYS_exit), "D" (0)); _exit(c)
612
613# elif defined(QT_ARCH_IA64)
614#define sysinit() \
615 asm volatile ("{.mlx\n" \
616 " nop.m 0\n" \
617 " movl r2 = @pcrel(boilerplate);;" \
618 "}\n" \
619 "{.mii\n" \
620 " mov r10 = @ltoffx(boilerplate)\n" \
621 " mov r1 = ip\n" \
622 " adds r2 = -16, r2\n;;\n" \
623 "}\n" \
624 " add r1 = r2, r1;;\n" \
625 " sub r1 = r1, r10;;\n" \
626 : : : "r2", "r10")
627#define syswrite(msg, len) \
628 ({ const char *_msg = msg; \
629 asm ("mov out0=%1\n" \
630 "mov out1=%2\n" \
631 "mov out2=%3\n" \
632 ";;\n" \
633 "mov r15=%0\n" \
634 "break 0x100000;;\n" \
635 : : "I" (SYS_write), "I" (1), "r" (_msg), "r" (len)); })
636#define sysexit(c) \
637 asm ("mov out0=%1\n" \
638 ";;\n" \
639 "mov r15=%0\n" \
640 "break 0x100000;;\n" \
641 : : "I" (SYS_exit), "O" (0)); write(1, 0, 0); _exit(c)
642# else
643#define sysinit() (void)0
644#define syswrite(msg, len) (msg); (len)
645#define sysexit(c) __builtin_exit(c)
646# endif
647
648#define sysputs(msg) syswrite(msg, -1 + sizeof(msg))
649#define sysendl() syswrite("\n", 1)
650#define print_qt_configure(_which) \
651 ({const char *which = _which; \
652 which += 12; \
653 int len = 0; \
654 while (which[len]) ++len; \
655 syswrite(which, len); })
656
657void qt_core_init_boilerplate()
658{
659 sysinit();
660 sysputs(boilerplate);
661 sysputs("\nInstallation prefix: ");
662 print_qt_configure(qt_configure_prefix_path_str);
663 sysputs("\nLibrary path: ");
664 print_qt_configure(qt_configure_libraries_path_str);
665 sysputs("\nInclude path: ");
666 print_qt_configure(qt_configure_headers_path_str);
667 sysendl();
668 sysexit(0);
669}
670
671#endif
Note: See TracBrowser for help on using the repository browser.