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