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