repurpose deprecated -E switch
[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                         Option::mkfile::do_preprocess = true;
310                     } else if(opt == "cache") {
311                         Option::mkfile::cachefile = argv[++x];
312                     } else if(opt == "platform" || opt == "spec") {
313                         Option::mkfile::qmakespec = cleanSpec(argv[++x]);
314                         Option::mkfile::qmakespec_commandline = argv[x];
315                     } else if (opt == "xplatform" || opt == "xspec") {
316                         Option::mkfile::xqmakespec = cleanSpec(argv[++x]);
317                         Option::mkfile::xqmakespec_commandline = argv[x];
318                     } else {
319                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
320                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
321                     }
322                 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
323                     if(opt == "nopwd") {
324                         Option::projfile::do_pwd = false;
325                     } else {
326                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
327                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
328                     }
329                 }
330             }
331         } else {
332             QString arg = argv[x];
333             if(arg.indexOf('=') != -1) {
334                 if(before)
335                     Option::before_user_vars.append(arg);
336                 else
337                     Option::after_user_vars.append(arg);
338             } else {
339                 bool handled = true;
340                 if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
341                     Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
342                     Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
343                     Option::prop::properties.append(arg);
344                 } else {
345                     QFileInfo fi(arg);
346                     if(!fi.makeAbsolute()) //strange
347                         arg = fi.filePath();
348                     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
349                        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
350                         if(fi.isDir()) {
351                             QString proj = detectProjectFile(arg);
352                             if (!proj.isNull())
353                                 arg = proj;
354                         }
355                         Option::mkfile::project_files.append(arg);
356                     } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
357                         Option::projfile::project_dirs.append(arg);
358                     } else {
359                         handled = false;
360                     }
361                 }
362                 if(!handled) {
363                     return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
364                 }
365             }
366         }
367     }
368
369     if (!user_configs.isEmpty())
370         Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
371
372     if (Option::mkfile::xqmakespec.isEmpty())
373         Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
374
375     return Option::QMAKE_CMDLINE_SUCCESS;
376 }
377
378 int
379 Option::init(int argc, char **argv)
380 {
381 #if defined(Q_OS_MAC)
382     Option::host_mode = Option::HOST_MACX_MODE;
383 #elif defined(Q_OS_UNIX)
384     Option::host_mode = Option::HOST_UNIX_MODE;
385 #else
386     Option::host_mode = Option::HOST_WIN_MODE;
387 #endif
388     Option::application_argv0 = 0;
389     Option::prf_ext = ".prf";
390     Option::pro_ext = ".pro";
391 #ifdef Q_OS_WIN
392     Option::dirlist_sep = ";";
393 #else
394     Option::dirlist_sep = ":";
395 #endif
396     Option::field_sep = ' ';
397
398     if(argc && argv) {
399         Option::application_argv0 = argv[0];
400         QString argv0 = argv[0];
401         if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
402             Option::qmake_mode = default_mode(argv0);
403         if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
404             Option::qmake_abslocation = argv0;
405         } else if (argv0.contains(QLatin1Char('/'))
406 #ifdef Q_OS_WIN
407                    || argv0.contains(QLatin1Char('\\'))
408 #endif
409             ) { //relative PWD
410             Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
411         } else { //in the PATH
412             QByteArray pEnv = qgetenv("PATH");
413             QDir currentDir = QDir::current();
414 #ifdef Q_OS_WIN
415             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
416 #else
417             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
418 #endif
419             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
420                 if ((*p).isEmpty())
421                     continue;
422                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
423 #ifdef Q_OS_WIN
424                 candidate += ".exe";
425 #endif
426                 if (QFile::exists(candidate)) {
427                     Option::qmake_abslocation = candidate;
428                     break;
429                 }
430             }
431         }
432         if(!Option::qmake_abslocation.isNull())
433             Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
434         else // This is rather unlikely to ever happen on a modern system ...
435             Option::qmake_abslocation = QLibraryInfo::rawLocation(QLibraryInfo::HostBinariesPath,
436                                                                   QLibraryInfo::EffectivePaths) +
437 #ifdef Q_OS_WIN
438                     "/qmake.exe";
439 #else
440                     "/qmake";
441 #endif
442     } else {
443         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
444     }
445
446     const QByteArray envflags = qgetenv("QMAKEFLAGS");
447     if (!envflags.isNull()) {
448         int env_argc = 0, env_size = 0, currlen=0;
449         char quote = 0, **env_argv = NULL;
450         for (int i = 0; i < envflags.size(); ++i) {
451             if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
452                 quote = envflags.at(i);
453             } else if (envflags.at(i) == quote) {
454                 quote = 0;
455             } else if (!quote && envflags.at(i) == ' ') {
456                 if (currlen && env_argv && env_argv[env_argc]) {
457                     env_argv[env_argc][currlen] = '\0';
458                     currlen = 0;
459                     env_argc++;
460                 }
461             } else {
462                 if(!env_argv || env_argc > env_size) {
463                     env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
464                     for(int i2 = env_argc; i2 < env_size; i2++)
465                         env_argv[i2] = NULL;
466                 }
467                 if(!env_argv[env_argc]) {
468                     currlen = 0;
469                     env_argv[env_argc] = (char*)malloc(255);
470                 }
471                 if(currlen < 255)
472                     env_argv[env_argc][currlen++] = envflags.at(i);
473             }
474         }
475         if(env_argv) {
476             if(env_argv[env_argc]) {
477                 env_argv[env_argc][currlen] = '\0';
478                 currlen = 0;
479                 env_argc++;
480             }
481             parseCommandLine(env_argc, env_argv);
482             for(int i2 = 0; i2 < env_size; i2++) {
483                 if(env_argv[i2])
484                     free(env_argv[i2]);
485             }
486             free(env_argv);
487         }
488     }
489     if(argc && argv) {
490         int ret = parseCommandLine(argc, argv, 1);
491         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
492             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
493                 usage(argv[0]);
494             return ret;
495             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
496         }
497     }
498
499     //last chance for defaults
500     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
501         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
502         if (Option::mkfile::xqmakespec.isEmpty())
503             Option::mkfile::xqmakespec = QString::fromLocal8Bit(qgetenv("XQMAKESPEC").constData());
504         if (Option::mkfile::qmakespec.isEmpty()) {
505             Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
506             if (Option::mkfile::xqmakespec.isEmpty())
507                 Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
508         }
509
510         //try REALLY hard to do it for them, lazy..
511         if(Option::mkfile::project_files.isEmpty()) {
512             QString proj = detectProjectFile(qmake_getpwd());
513             if(!proj.isNull())
514                 Option::mkfile::project_files.append(proj);
515 #ifndef QT_BUILD_QMAKE_LIBRARY
516             if(Option::mkfile::project_files.isEmpty()) {
517                 usage(argv[0]);
518                 return Option::QMAKE_CMDLINE_ERROR;
519             }
520 #endif
521         }
522     }
523
524     //defaults for globals
525     if (Option::host_mode == Option::HOST_WIN_MODE) {
526         Option::dir_sep = "\\";
527     } else {
528         Option::dir_sep = "/";
529     }
530
531     return QMAKE_CMDLINE_SUCCESS;
532 }
533
534 void Option::prepareProject(const QString &pfile)
535 {
536     QString srcpath = (pfile != "-")
537             ? QDir::cleanPath(QFileInfo(pfile).absolutePath()) : qmake_getpwd();
538     if (srcpath != output_dir) {
539         if (!srcpath.endsWith(QLatin1Char('/')))
540             srcpath += QLatin1Char('/');
541         QString dstpath = output_dir;
542         if (!dstpath.endsWith(QLatin1Char('/')))
543             dstpath += QLatin1Char('/');
544         int srcLen = srcpath.length();
545         int dstLen = dstpath.length();
546         int lastSl = -1;
547         while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
548             if (srcpath.at(srcLen) == QLatin1Char('/'))
549                 lastSl = 0;
550         mkfile::source_root = srcpath.left(srcLen + lastSl);
551         mkfile::build_root = dstpath.left(dstLen + lastSl);
552     } else {
553         mkfile::source_root.clear();
554     }
555 }
556
557 bool Option::postProcessProject(QMakeProject *project)
558 {
559     Option::cpp_ext = project->values("QMAKE_EXT_CPP");
560     Option::h_ext = project->values("QMAKE_EXT_H");
561     Option::c_ext = project->values("QMAKE_EXT_C");
562     Option::res_ext = project->first("QMAKE_EXT_RES");
563     Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
564     Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
565     Option::prl_ext = project->first("QMAKE_EXT_PRL");
566     Option::ui_ext = project->first("QMAKE_EXT_UI");
567     Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
568     Option::lex_ext = project->first("QMAKE_EXT_LEX");
569     Option::yacc_ext = project->first("QMAKE_EXT_YACC");
570     Option::obj_ext = project->first("QMAKE_EXT_OBJ");
571     Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
572     Option::lex_mod = project->first("QMAKE_MOD_LEX");
573     Option::yacc_mod = project->first("QMAKE_MOD_YACC");
574     Option::dir_sep = project->first("QMAKE_DIR_SEP");
575     Option::shellPath = project->values("QMAKE_SH");
576     return true;
577 }
578
579 QString
580 Option::fixString(QString string, uchar flags)
581 {
582     //const QString orig_string = string;
583     static QHash<FixStringCacheKey, QString> *cache = 0;
584     if(!cache) {
585         cache = new QHash<FixStringCacheKey, QString>;
586         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
587     }
588     FixStringCacheKey cacheKey(string, flags);
589
590     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
591
592     if (it != cache->constEnd()) {
593         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
594         return it.value();
595     }
596
597     //fix the environment variables
598     if(flags & Option::FixEnvVars) {
599         int rep;
600         static QRegExp reg_var("\\$\\(.*\\)");
601         reg_var.setMinimal(true);
602         while((rep = reg_var.indexIn(string)) != -1)
603             string.replace(rep, reg_var.matchedLength(),
604                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
605     }
606
607     //canonicalize it (and treat as a path)
608     if(flags & Option::FixPathCanonicalize) {
609 #if 0
610         string = QFileInfo(string).canonicalFilePath();
611 #endif
612         string = QDir::cleanPath(string);
613     }
614
615     if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
616         string[0] = string[0].toLower();
617
618     bool localSep = (flags & Option::FixPathToLocalSeparators) != 0;
619     bool targetSep = (flags & Option::FixPathToTargetSeparators) != 0;
620     bool normalSep = (flags & Option::FixPathToNormalSeparators) != 0;
621
622     // either none or only one active flag
623     Q_ASSERT(localSep + targetSep + normalSep <= 1);
624     //fix separators
625     if (flags & Option::FixPathToNormalSeparators) {
626         string = string.replace('\\', '/');
627     } else if (flags & Option::FixPathToLocalSeparators) {
628 #if defined(Q_OS_WIN32)
629         string = string.replace('/', '\\');
630 #else
631         string = string.replace('\\', '/');
632 #endif
633     } else if(flags & Option::FixPathToTargetSeparators) {
634         string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
635     }
636
637     if ((string.startsWith("\"") && string.endsWith("\"")) ||
638         (string.startsWith("\'") && string.endsWith("\'")))
639         string = string.mid(1, string.length()-2);
640
641     //cache
642     //qDebug() << "Fix" << orig_string << "->" << string;
643     cache->insert(cacheKey, string);
644     return string;
645 }
646
647 const char *qmake_version()
648 {
649     static char *ret = NULL;
650     if(ret)
651         return ret;
652     ret = (char *)malloc(15);
653     qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
654 #if defined(_MSC_VER) && _MSC_VER >= 1400
655     sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
656 #else
657     sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
658 #endif
659     return ret;
660 }
661
662 void debug_msg_internal(int level, const char *fmt, ...)
663 {
664     if(Option::debug_level < level)
665         return;
666     fprintf(stderr, "DEBUG %d: ", level);
667     {
668         va_list ap;
669         va_start(ap, fmt);
670         vfprintf(stderr, fmt, ap);
671         va_end(ap);
672     }
673     fprintf(stderr, "\n");
674 }
675
676 void warn_msg(QMakeWarn type, const char *fmt, ...)
677 {
678     if(!(Option::warn_level & type))
679         return;
680     fprintf(stderr, "WARNING: ");
681     {
682         va_list ap;
683         va_start(ap, fmt);
684         vfprintf(stderr, fmt, ap);
685         va_end(ap);
686     }
687     fprintf(stderr, "\n");
688 }
689
690 class QMakeCacheClearItem {
691 private:
692     qmakeCacheClearFunc func;
693     void **data;
694 public:
695     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
696     ~QMakeCacheClearItem() {
697         (*func)(*data);
698         *data = 0;
699     }
700 };
701 static QList<QMakeCacheClearItem*> cache_items;
702
703 void
704 qmakeClearCaches()
705 {
706     qDeleteAll(cache_items);
707     cache_items.clear();
708 }
709
710 void
711 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
712 {
713     cache_items.append(new QMakeCacheClearItem(func, data));
714 }
715
716 QString qmake_libraryInfoFile()
717 {
718     if(!Option::qmake_abslocation.isEmpty())
719         return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
720     return QString();
721 }
722
723 QT_END_NAMESPACE