make QMakeMetaInfo a little less inefficient with libtool .la files
[profile/ivi/qtbase.git] / qmake / option.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the qmake application of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "option.h"
43 #include "cachekeys.h"
44 #include <qdir.h>
45 #include <qregexp.h>
46 #include <qhash.h>
47 #include <qdebug.h>
48 #include <qsettings.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51
52 QT_BEGIN_NAMESPACE
53
54 //convenience
55 const char *Option::application_argv0 = 0;
56 QString Option::prf_ext;
57 QString Option::prl_ext;
58 QString Option::libtool_ext;
59 QString Option::pkgcfg_ext;
60 QString Option::ui_ext;
61 QStringList Option::h_ext;
62 QString Option::cpp_moc_ext;
63 QStringList Option::cpp_ext;
64 QStringList Option::c_ext;
65 QString Option::obj_ext;
66 QString Option::lex_ext;
67 QString Option::yacc_ext;
68 QString Option::pro_ext;
69 QString Option::dir_sep;
70 QString Option::dirlist_sep;
71 QString Option::h_moc_mod;
72 QString Option::yacc_mod;
73 QString Option::lex_mod;
74 QString Option::res_ext;
75 char Option::field_sep;
76
77 //mode
78 Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
79
80 //all modes
81 QString Option::qmake_abslocation;
82 QStringList Option::qmake_args;
83 int Option::warn_level = WarnLogic | WarnDeprecated;
84 int Option::debug_level = 0;
85 QFile Option::output;
86 QString Option::output_dir;
87 bool Option::recursive = false;
88 QStringList Option::before_user_vars;
89 QStringList Option::after_user_vars;
90 QString Option::user_template;
91 QString Option::user_template_prefix;
92
93 //QMAKE_*_PROPERTY stuff
94 QStringList Option::prop::properties;
95
96 //QMAKE_GENERATE_PROJECT stuff
97 bool Option::projfile::do_pwd = true;
98 QStringList Option::projfile::project_dirs;
99
100 //QMAKE_GENERATE_MAKEFILE stuff
101 QString Option::mkfile::qmakespec;
102 QString Option::mkfile::xqmakespec;
103 int Option::mkfile::cachefile_depth = -1;
104 bool Option::mkfile::do_deps = true;
105 bool Option::mkfile::do_mocs = true;
106 bool Option::mkfile::do_dep_heuristics = true;
107 bool Option::mkfile::do_preprocess = false;
108 bool Option::mkfile::do_stub_makefile = false;
109 bool Option::mkfile::do_cache = true;
110 QString Option::mkfile::source_root;
111 QString Option::mkfile::build_root;
112 QString Option::mkfile::cachefile;
113 QStringList Option::mkfile::project_files;
114
115 static Option::QMAKE_MODE default_mode(QString progname)
116 {
117     int s = progname.lastIndexOf(QDir::separator());
118     if(s != -1)
119         progname = progname.right(progname.length() - (s + 1));
120     if(progname == "qmakegen")
121         return Option::QMAKE_GENERATE_PROJECT;
122     else if(progname == "qt-config")
123         return Option::QMAKE_QUERY_PROPERTY;
124     return Option::QMAKE_GENERATE_MAKEFILE;
125 }
126
127 static QString detectProjectFile(const QString &path)
128 {
129     QString ret;
130     QDir dir(path);
131     if(dir.exists(dir.dirName() + Option::pro_ext)) {
132         ret = dir.filePath(dir.dirName()) + Option::pro_ext;
133     } else { //last try..
134         QStringList profiles = dir.entryList(QStringList("*" + Option::pro_ext));
135         if(profiles.count() == 1)
136             ret = dir.filePath(profiles.at(0));
137     }
138     return ret;
139 }
140
141 static QString cleanSpec(const QString &spec)
142 {
143     QString ret = QDir::cleanPath(spec);
144     if (ret.contains('/')) {
145         const QFileInfo specDirInfo(ret);
146         if (specDirInfo.exists() && specDirInfo.isDir())
147             ret = QDir::cleanPath(specDirInfo.absoluteFilePath());
148     }
149     return ret;
150 }
151
152 QString project_builtin_regx();
153 bool usage(const char *a0)
154 {
155     fprintf(stdout, "Usage: %s [mode] [options] [files]\n"
156             "\n"
157             "QMake has two modes, one mode for generating project files based on\n"
158             "some heuristics, and the other for generating makefiles. Normally you\n"
159             "shouldn't need to specify a mode, as makefile generation is the default\n"
160             "mode for qmake, but you may use this to test qmake on an existing project\n"
161             "\n"
162             "Mode:\n"
163             "  -project       Put qmake into project file generation mode%s\n"
164             "                 In this mode qmake interprets files as files to\n"
165             "                 be built,\n"
166             "                 defaults to %s\n"
167             "                 Note: The created .pro file probably will \n"
168             "                 need to be edited. For example add the QT variable to \n"
169             "                 specify what modules are required.\n"
170             "  -makefile      Put qmake into makefile generation mode%s\n"
171             "                 In this mode qmake interprets files as project files to\n"
172             "                 be processed, if skipped qmake will try to find a project\n"
173             "                 file in your current working directory\n"
174             "\n"
175             "Warnings Options:\n"
176             "  -Wnone         Turn off all warnings; specific ones may be re-enabled by\n"
177             "                 later -W options\n"
178             "  -Wall          Turn on all warnings\n"
179             "  -Wparser       Turn on parser warnings\n"
180             "  -Wlogic        Turn on logic warnings (on by default)\n"
181             "  -Wdeprecated   Turn on deprecation warnings (on by default)\n"
182             "\n"
183             "Options:\n"
184             "   * You can place any variable assignment in options and it will be     *\n"
185             "   * processed as if it was in [files]. These assignments will be parsed *\n"
186             "   * before [files].                                                     *\n"
187             "  -o file        Write output to file\n"
188             "  -d             Increase debug level\n"
189             "  -t templ       Overrides TEMPLATE as templ\n"
190             "  -tp prefix     Overrides TEMPLATE so that prefix is prefixed into the value\n"
191             "  -help          This help\n"
192             "  -v             Version information\n"
193             "  -after         All variable assignments after this will be\n"
194             "                 parsed after [files]\n"
195             "  -norecursive   Don't do a recursive search\n"
196             "  -recursive     Do a recursive search\n"
197             "  -set <prop> <value> Set persistent property\n"
198             "  -unset <prop>  Unset persistent property\n"
199             "  -query <prop>  Query persistent property. Show all if <prop> is empty.\n"
200             "  -cache file    Use file as cache           [makefile mode only]\n"
201             "  -spec spec     Use spec as QMAKESPEC       [makefile mode only]\n"
202             "  -nocache       Don't use a cache file      [makefile mode only]\n"
203             "  -nodepend      Don't generate dependencies [makefile mode only]\n"
204             "  -nomoc         Don't generate moc targets  [makefile mode only]\n"
205             "  -nopwd         Don't look for files in pwd [project mode only]\n"
206             ,a0,
207             default_mode(a0) == Option::QMAKE_GENERATE_PROJECT  ? " (default)" : "", project_builtin_regx().toLatin1().constData(),
208             default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : ""
209         );
210     return false;
211 }
212
213 int
214 Option::parseCommandLine(QStringList &args)
215 {
216     QStringList user_configs;
217
218     bool before = true;
219     args << QString(); // Avoid bounds checking for options which take an argument
220     for (int x = 0; x < args.size() - 1; ) {
221         QString arg = args.at(x);
222         if (arg.size() > 1 && arg.startsWith('-')) { /* options */
223             QString opt = arg.mid(1);
224             if(opt == "o" || opt == "output") {
225                 Option::output.setFileName(args.at(x + 1));
226                 args.erase(args.begin() + x, args.begin() + x + 2);
227                 continue;
228             } else if(opt == "after") {
229                 before = false;
230             } else if(opt == "t" || opt == "template") {
231                 Option::user_template = args.at(++x);
232             } else if(opt == "tp" || opt == "template_prefix") {
233                 Option::user_template_prefix = args.at(++x);
234             } else if(opt == "unix") {
235                 Option::dir_sep = "/";
236             } else if(opt == "win32") {
237                 Option::dir_sep = "\\";
238             } else if(opt == "d") {
239                 Option::debug_level++;
240             } else if(opt == "version" || opt == "v" || opt == "-version") {
241                 fprintf(stdout,
242                         "QMake version %s\n"
243                         "Using Qt version %s in %s\n",
244                         qmake_version(), QT_VERSION_STR,
245                         QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
246 #ifdef QMAKE_OPENSOURCE_VERSION
247                 fprintf(stdout, "QMake is Open Source software from Nokia Corporation and/or its subsidiary(-ies).\n");
248 #endif
249                 return Option::QMAKE_CMDLINE_BAIL;
250             } else if(opt == "h" || opt == "help") {
251                 return Option::QMAKE_CMDLINE_SHOW_USAGE;
252             } else if(opt == "Wall") {
253                 Option::warn_level |= WarnAll;
254             } else if(opt == "Wparser") {
255                 Option::warn_level |= WarnParser;
256             } else if(opt == "Wlogic") {
257                 Option::warn_level |= WarnLogic;
258             } else if(opt == "Wdeprecated") {
259                 Option::warn_level |= WarnDeprecated;
260             } else if(opt == "Wnone") {
261                 Option::warn_level = WarnNone;
262             } else if(opt == "r" || opt == "recursive") {
263                 Option::recursive = true;
264                 args.removeAt(x);
265                 continue;
266             } else if(opt == "nr" || opt == "norecursive") {
267                 Option::recursive = false;
268                 args.removeAt(x);
269                 continue;
270             } else if(opt == "config") {
271                 user_configs += args.at(++x);
272             } else {
273                 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
274                    Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
275                     if(opt == "nodepend" || opt == "nodepends") {
276                         Option::mkfile::do_deps = false;
277                     } else if(opt == "nomoc") {
278                         Option::mkfile::do_mocs = false;
279                     } else if(opt == "nocache") {
280                         Option::mkfile::do_cache = false;
281                     } else if(opt == "createstub") {
282                         Option::mkfile::do_stub_makefile = true;
283                     } else if(opt == "nodependheuristics") {
284                         Option::mkfile::do_dep_heuristics = false;
285                     } else if(opt == "E") {
286                         Option::mkfile::do_preprocess = true;
287                     } else if(opt == "cache") {
288                         Option::mkfile::cachefile = args.at(++x);
289                     } else if(opt == "platform" || opt == "spec") {
290                         Option::mkfile::qmakespec = args[x] = cleanSpec(args.at(++x));
291                     } else if (opt == "xplatform" || opt == "xspec") {
292                         Option::mkfile::xqmakespec = args[x] = cleanSpec(args.at(x));
293                     } else {
294                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
295                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
296                     }
297                 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
298                     if(opt == "nopwd") {
299                         Option::projfile::do_pwd = false;
300                     } else {
301                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
302                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
303                     }
304                 }
305             }
306         } else {
307             if(arg.indexOf('=') != -1) {
308                 if(before)
309                     Option::before_user_vars.append(arg);
310                 else
311                     Option::after_user_vars.append(arg);
312             } else {
313                 bool handled = true;
314                 if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
315                     Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
316                     Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
317                     Option::prop::properties.append(arg);
318                 } else {
319                     QFileInfo fi(arg);
320                     if(!fi.makeAbsolute()) //strange
321                         arg = fi.filePath();
322                     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
323                        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
324                         if(fi.isDir()) {
325                             QString proj = detectProjectFile(arg);
326                             if (!proj.isNull())
327                                 arg = proj;
328                         }
329                         Option::mkfile::project_files.append(arg);
330                     } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
331                         Option::projfile::project_dirs.append(arg);
332                     } else {
333                         handled = false;
334                     }
335                 }
336                 if(!handled) {
337                     return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
338                 }
339                 args.removeAt(x);
340                 continue;
341             }
342         }
343         x++;
344     }
345
346     if (!user_configs.isEmpty())
347         Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
348
349     if (Option::mkfile::xqmakespec.isEmpty())
350         Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
351
352     args.takeLast();
353     return Option::QMAKE_CMDLINE_SUCCESS;
354 }
355
356 int
357 Option::init(int argc, char **argv)
358 {
359     Option::application_argv0 = 0;
360     Option::prf_ext = ".prf";
361     Option::pro_ext = ".pro";
362 #ifdef Q_OS_WIN
363     Option::dir_sep = "\\";
364     Option::dirlist_sep = ";";
365 #else
366     Option::dir_sep = "/";
367     Option::dirlist_sep = ":";
368 #endif
369     Option::field_sep = ' ';
370
371     if(argc && argv) {
372         Option::application_argv0 = argv[0];
373         QString argv0 = argv[0];
374         if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
375             Option::qmake_mode = default_mode(argv0);
376         if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
377             Option::qmake_abslocation = argv0;
378         } else if (argv0.contains(QLatin1Char('/'))
379 #ifdef Q_OS_WIN
380                    || argv0.contains(QLatin1Char('\\'))
381 #endif
382             ) { //relative PWD
383             Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
384         } else { //in the PATH
385             QByteArray pEnv = qgetenv("PATH");
386             QDir currentDir = QDir::current();
387 #ifdef Q_OS_WIN
388             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
389 #else
390             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
391 #endif
392             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
393                 if ((*p).isEmpty())
394                     continue;
395                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
396 #ifdef Q_OS_WIN
397                 candidate += ".exe";
398 #endif
399                 if (QFile::exists(candidate)) {
400                     Option::qmake_abslocation = candidate;
401                     break;
402                 }
403             }
404         }
405         if(!Option::qmake_abslocation.isNull())
406             Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
407         else // This is rather unlikely to ever happen on a modern system ...
408             Option::qmake_abslocation = QLibraryInfo::rawLocation(QLibraryInfo::HostBinariesPath,
409                                                                   QLibraryInfo::EffectivePaths) +
410 #ifdef Q_OS_WIN
411                     "/qmake.exe";
412 #else
413                     "/qmake";
414 #endif
415     } else {
416         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
417     }
418
419     const QByteArray envflags = qgetenv("QMAKEFLAGS");
420     if (!envflags.isNull()) {
421         QStringList args;
422         QByteArray buf = "";
423         char quote = 0;
424         bool hasWord = false;
425         for (int i = 0; i < envflags.size(); ++i) {
426             char c = envflags.at(i);
427             if (!quote && (c == '\'' || c == '"')) {
428                 quote = c;
429             } else if (c == quote) {
430                 quote = 0;
431             } else if (!quote && c == ' ') {
432                 if (hasWord) {
433                     args << QString::fromLocal8Bit(buf);
434                     hasWord = false;
435                     buf = "";
436                 }
437             } else {
438                 buf += c;
439                 hasWord = true;
440             }
441         }
442         if (hasWord)
443             args << QString::fromLocal8Bit(buf);
444         parseCommandLine(args);
445     }
446     if(argc && argv) {
447         QStringList args;
448         for (int i = 1; i < argc; i++)
449             args << QString::fromLocal8Bit(argv[i]);
450
451         while (!args.isEmpty()) {
452             QString opt = args.at(0);
453             if (opt == "-project") {
454                 Option::recursive = true;
455                 Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT;
456             } else if (opt == "-prl") {
457                 Option::mkfile::do_deps = false;
458                 Option::mkfile::do_mocs = false;
459                 Option::qmake_mode = Option::QMAKE_GENERATE_PRL;
460             } else if (opt == "-set") {
461                 Option::qmake_mode = Option::QMAKE_SET_PROPERTY;
462             } else if (opt == "-unset") {
463                 Option::qmake_mode = Option::QMAKE_UNSET_PROPERTY;
464             } else if (opt == "-query") {
465                 Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY;
466             } else if (opt == "-makefile") {
467                 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
468             } else {
469                 break;
470             }
471             args.takeFirst();
472             break;
473         }
474
475         int ret = parseCommandLine(args);
476         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
477             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
478                 usage(argv[0]);
479             return ret;
480             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
481         }
482         Option::qmake_args = args;
483     }
484
485     //last chance for defaults
486     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
487         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
488         if (Option::mkfile::xqmakespec.isEmpty())
489             Option::mkfile::xqmakespec = QString::fromLocal8Bit(qgetenv("XQMAKESPEC").constData());
490         if (Option::mkfile::qmakespec.isEmpty()) {
491             Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
492             if (Option::mkfile::xqmakespec.isEmpty())
493                 Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
494         }
495
496         //try REALLY hard to do it for them, lazy..
497         if(Option::mkfile::project_files.isEmpty()) {
498             QString proj = detectProjectFile(qmake_getpwd());
499             if(!proj.isNull())
500                 Option::mkfile::project_files.append(proj);
501 #ifndef QT_BUILD_QMAKE_LIBRARY
502             if(Option::mkfile::project_files.isEmpty()) {
503                 usage(argv[0]);
504                 return Option::QMAKE_CMDLINE_ERROR;
505             }
506 #endif
507         }
508     }
509
510     return QMAKE_CMDLINE_SUCCESS;
511 }
512
513 void Option::prepareProject(const QString &pfile)
514 {
515     QString srcpath = (pfile != "-")
516             ? QDir::cleanPath(QFileInfo(pfile).absolutePath()) : qmake_getpwd();
517     if (srcpath != output_dir) {
518         if (!srcpath.endsWith(QLatin1Char('/')))
519             srcpath += QLatin1Char('/');
520         QString dstpath = output_dir;
521         if (!dstpath.endsWith(QLatin1Char('/')))
522             dstpath += QLatin1Char('/');
523         int srcLen = srcpath.length();
524         int dstLen = dstpath.length();
525         int lastSl = -1;
526         while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
527             if (srcpath.at(srcLen) == QLatin1Char('/'))
528                 lastSl = 0;
529         mkfile::source_root = srcpath.left(srcLen + lastSl);
530         mkfile::build_root = dstpath.left(dstLen + lastSl);
531     } else {
532         mkfile::source_root.clear();
533     }
534 }
535
536 bool Option::postProcessProject(QMakeProject *project)
537 {
538     Option::cpp_ext = project->values("QMAKE_EXT_CPP");
539     Option::h_ext = project->values("QMAKE_EXT_H");
540     Option::c_ext = project->values("QMAKE_EXT_C");
541     Option::res_ext = project->first("QMAKE_EXT_RES");
542     Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
543     Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
544     Option::prl_ext = project->first("QMAKE_EXT_PRL");
545     Option::ui_ext = project->first("QMAKE_EXT_UI");
546     Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
547     Option::lex_ext = project->first("QMAKE_EXT_LEX");
548     Option::yacc_ext = project->first("QMAKE_EXT_YACC");
549     Option::obj_ext = project->first("QMAKE_EXT_OBJ");
550     Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
551     Option::lex_mod = project->first("QMAKE_MOD_LEX");
552     Option::yacc_mod = project->first("QMAKE_MOD_YACC");
553
554     if (Option::output_dir.startsWith(project->buildRoot()))
555         Option::mkfile::cachefile_depth =
556                 Option::output_dir.mid(project->buildRoot().length()).count('/');
557
558     return true;
559 }
560
561 QString
562 Option::fixString(QString string, uchar flags)
563 {
564     //const QString orig_string = string;
565     static QHash<FixStringCacheKey, QString> *cache = 0;
566     if(!cache) {
567         cache = new QHash<FixStringCacheKey, QString>;
568         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
569     }
570     FixStringCacheKey cacheKey(string, flags);
571
572     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
573
574     if (it != cache->constEnd()) {
575         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
576         return it.value();
577     }
578
579     //fix the environment variables
580     if(flags & Option::FixEnvVars) {
581         int rep;
582         static QRegExp reg_var("\\$\\(.*\\)");
583         reg_var.setMinimal(true);
584         while((rep = reg_var.indexIn(string)) != -1)
585             string.replace(rep, reg_var.matchedLength(),
586                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
587     }
588
589     //canonicalize it (and treat as a path)
590     if(flags & Option::FixPathCanonicalize) {
591 #if 0
592         string = QFileInfo(string).canonicalFilePath();
593 #endif
594         string = QDir::cleanPath(string);
595     }
596
597     bool localSep = (flags & Option::FixPathToLocalSeparators) != 0;
598     bool targetSep = (flags & Option::FixPathToTargetSeparators) != 0;
599     bool normalSep = (flags & Option::FixPathToNormalSeparators) != 0;
600
601     // either none or only one active flag
602     Q_ASSERT(localSep + targetSep + normalSep <= 1);
603     //fix separators
604     if (flags & Option::FixPathToNormalSeparators) {
605         string = string.replace('\\', '/');
606     } else if (flags & Option::FixPathToLocalSeparators) {
607 #if defined(Q_OS_WIN32)
608         string = string.replace('/', '\\');
609 #else
610         string = string.replace('\\', '/');
611 #endif
612     } else if(flags & Option::FixPathToTargetSeparators) {
613         string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
614     }
615
616     if ((string.startsWith("\"") && string.endsWith("\"")) ||
617         (string.startsWith("\'") && string.endsWith("\'")))
618         string = string.mid(1, string.length()-2);
619
620     //cache
621     //qDebug() << "Fix" << orig_string << "->" << string;
622     cache->insert(cacheKey, string);
623     return string;
624 }
625
626 const char *qmake_version()
627 {
628     static char *ret = NULL;
629     if(ret)
630         return ret;
631     ret = (char *)malloc(15);
632     qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
633 #if defined(_MSC_VER) && _MSC_VER >= 1400
634     sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
635 #else
636     sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
637 #endif
638     return ret;
639 }
640
641 void debug_msg_internal(int level, const char *fmt, ...)
642 {
643     if(Option::debug_level < level)
644         return;
645     fprintf(stderr, "DEBUG %d: ", level);
646     {
647         va_list ap;
648         va_start(ap, fmt);
649         vfprintf(stderr, fmt, ap);
650         va_end(ap);
651     }
652     fprintf(stderr, "\n");
653 }
654
655 void warn_msg(QMakeWarn type, const char *fmt, ...)
656 {
657     if(!(Option::warn_level & type))
658         return;
659     fprintf(stderr, "WARNING: ");
660     {
661         va_list ap;
662         va_start(ap, fmt);
663         vfprintf(stderr, fmt, ap);
664         va_end(ap);
665     }
666     fprintf(stderr, "\n");
667 }
668
669 class QMakeCacheClearItem {
670 private:
671     qmakeCacheClearFunc func;
672     void **data;
673 public:
674     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
675     ~QMakeCacheClearItem() {
676         (*func)(*data);
677         *data = 0;
678     }
679 };
680 static QList<QMakeCacheClearItem*> cache_items;
681
682 void
683 qmakeClearCaches()
684 {
685     qDeleteAll(cache_items);
686     cache_items.clear();
687 }
688
689 void
690 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
691 {
692     cache_items.append(new QMakeCacheClearItem(func, data));
693 }
694
695 QString qmake_libraryInfoFile()
696 {
697     if(!Option::qmake_abslocation.isEmpty())
698         return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
699     return QString();
700 }
701
702 QT_END_NAMESPACE