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