Revert "move finding the makespec to Option"
[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 int Option::mkfile::cachefile_depth = -1;
111 bool Option::mkfile::do_deps = true;
112 bool Option::mkfile::do_mocs = true;
113 bool Option::mkfile::do_dep_heuristics = true;
114 bool Option::mkfile::do_preprocess = false;
115 bool Option::mkfile::do_stub_makefile = false;
116 bool Option::mkfile::do_cache = true;
117 QString Option::mkfile::project_root;
118 QString Option::mkfile::project_build_root;
119 QString Option::mkfile::cachefile;
120 QStringList Option::mkfile::project_files;
121 QString Option::mkfile::qmakespec_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 {
333                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
334                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
335                     }
336                 } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
337                     if(opt == "nopwd") {
338                         Option::projfile::do_pwd = false;
339                     } else {
340                         fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
341                         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
342                     }
343                 }
344             }
345         } else {
346             QString arg = argv[x];
347             if(arg.indexOf('=') != -1) {
348                 if(before)
349                     Option::before_user_vars.append(arg);
350                 else
351                     Option::after_user_vars.append(arg);
352             } else {
353                 bool handled = true;
354                 if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
355                     Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
356                     Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
357                     Option::prop::properties.append(arg);
358                 } else {
359                     QFileInfo fi(arg);
360                     if(!fi.makeAbsolute()) //strange
361                         arg = fi.filePath();
362                     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
363                        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
364                         if(fi.isDir()) {
365                             QString proj = detectProjectFile(arg);
366                             if (!proj.isNull())
367                                 arg = proj;
368                         }
369                         Option::mkfile::project_files.append(arg);
370                     } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
371                         Option::projfile::project_dirs.append(arg);
372                     } else {
373                         handled = false;
374                     }
375                 }
376                 if(!handled) {
377                     return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
378                 }
379             }
380         }
381     }
382
383     if (!user_configs.isEmpty())
384         Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
385
386     return Option::QMAKE_CMDLINE_SUCCESS;
387 }
388
389 #ifdef Q_OS_WIN
390 static QStringList detectShellPath()
391 {
392     QStringList paths;
393     QString path = qgetenv("PATH");
394     QStringList pathlist = path.toLower().split(";");
395     for (int i = 0; i < pathlist.count(); i++) {
396         QString maybeSh = pathlist.at(i) + "/sh.exe";
397         if (QFile::exists(maybeSh)) {
398             paths.append(maybeSh);
399         }
400     }
401     return paths;
402 }
403 #endif
404
405 int
406 Option::init(int argc, char **argv)
407 {
408     Option::application_argv0 = 0;
409     Option::cpp_moc_mod = "";
410     Option::h_moc_mod = "moc_";
411     Option::lex_mod = "_lex";
412     Option::yacc_mod = "_yacc";
413     Option::prl_ext = ".prl";
414     Option::libtool_ext = ".la";
415     Option::pkgcfg_ext = ".pc";
416     Option::prf_ext = ".prf";
417     Option::js_ext = ".js";
418     Option::ui_ext = ".ui";
419     Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
420     Option::c_ext << ".c";
421 #ifndef Q_OS_WIN
422     Option::h_ext << ".H";
423 #endif
424     Option::cpp_moc_ext = ".moc";
425     Option::h_moc_ext = ".cpp";
426     Option::cpp_ext << ".cpp" << ".cc" << ".cxx";
427 #ifndef Q_OS_WIN
428     Option::cpp_ext << ".C";
429 #endif
430     Option::lex_ext = ".l";
431     Option::yacc_ext = ".y";
432     Option::pro_ext = ".pro";
433     Option::mmp_ext = ".mmp";
434 #ifdef Q_OS_WIN
435     Option::dirlist_sep = ";";
436     Option::shellPath = detectShellPath();
437     Option::res_ext = ".res";
438 #else
439     Option::dirlist_sep = ":";
440     Option::shellPath = QStringList("sh");
441 #endif
442     Option::sysenv_mod = "QMAKE_ENV_";
443     Option::field_sep = ' ';
444
445     if(argc && argv) {
446         Option::application_argv0 = argv[0];
447         QString argv0 = argv[0];
448         if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
449             Option::qmake_mode = default_mode(argv0);
450         if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
451             Option::qmake_abslocation = argv0;
452         } else if (argv0.contains(QLatin1Char('/'))
453 #ifdef Q_OS_WIN
454                    || argv0.contains(QLatin1Char('\\'))
455 #endif
456             ) { //relative PWD
457             Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
458         } else { //in the PATH
459             QByteArray pEnv = qgetenv("PATH");
460             QDir currentDir = QDir::current();
461 #ifdef Q_OS_WIN
462             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
463 #else
464             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
465 #endif
466             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
467                 if ((*p).isEmpty())
468                     continue;
469                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
470 #ifdef Q_OS_WIN
471                 candidate += ".exe";
472 #endif
473                 if (QFile::exists(candidate)) {
474                     Option::qmake_abslocation = candidate;
475                     break;
476                 }
477             }
478         }
479         if(!Option::qmake_abslocation.isNull())
480             Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
481     } else {
482         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
483     }
484
485     const QByteArray envflags = qgetenv("QMAKEFLAGS");
486     if (!envflags.isNull()) {
487         int env_argc = 0, env_size = 0, currlen=0;
488         char quote = 0, **env_argv = NULL;
489         for (int i = 0; i < envflags.size(); ++i) {
490             if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
491                 quote = envflags.at(i);
492             } else if (envflags.at(i) == quote) {
493                 quote = 0;
494             } else if (!quote && envflags.at(i) == ' ') {
495                 if (currlen && env_argv && env_argv[env_argc]) {
496                     env_argv[env_argc][currlen] = '\0';
497                     currlen = 0;
498                     env_argc++;
499                 }
500             } else {
501                 if(!env_argv || env_argc > env_size) {
502                     env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
503                     for(int i2 = env_argc; i2 < env_size; i2++)
504                         env_argv[i2] = NULL;
505                 }
506                 if(!env_argv[env_argc]) {
507                     currlen = 0;
508                     env_argv[env_argc] = (char*)malloc(255);
509                 }
510                 if(currlen < 255)
511                     env_argv[env_argc][currlen++] = envflags.at(i);
512             }
513         }
514         if(env_argv) {
515             if(env_argv[env_argc]) {
516                 env_argv[env_argc][currlen] = '\0';
517                 currlen = 0;
518                 env_argc++;
519             }
520             parseCommandLine(env_argc, env_argv);
521             for(int i2 = 0; i2 < env_size; i2++) {
522                 if(env_argv[i2])
523                     free(env_argv[i2]);
524             }
525             free(env_argv);
526         }
527     }
528     if(argc && argv) {
529         int ret = parseCommandLine(argc, argv, 1);
530         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
531             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
532                 usage(argv[0]);
533             return ret;
534             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
535         }
536     }
537
538     //last chance for defaults
539     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
540         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
541         if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty())
542             Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
543
544         //try REALLY hard to do it for them, lazy..
545         if(Option::mkfile::project_files.isEmpty()) {
546             QString proj = detectProjectFile(qmake_getpwd());
547             if(!proj.isNull())
548                 Option::mkfile::project_files.append(proj);
549 #ifndef QT_BUILD_QMAKE_LIBRARY
550             if(Option::mkfile::project_files.isEmpty()) {
551                 usage(argv[0]);
552                 return Option::QMAKE_CMDLINE_ERROR;
553             }
554 #endif
555         }
556     } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
557 #if defined(Q_OS_MAC)
558         Option::host_mode = Option::HOST_MACX_MODE;
559         Option::target_mode = Option::TARG_MACX_MODE;
560 #elif defined(Q_OS_UNIX)
561         Option::host_mode = Option::HOST_UNIX_MODE;
562         Option::target_mode = Option::TARG_UNIX_MODE;
563 #else
564         Option::host_mode = Option::HOST_WIN_MODE;
565         Option::target_mode = Option::TARG_WIN_MODE;
566 #endif
567     }
568
569     //defaults for globals
570     if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
571         applyHostMode();
572     return QMAKE_CMDLINE_SUCCESS;
573 }
574
575 void Option::applyHostMode()
576 {
577    if (Option::host_mode == Option::HOST_WIN_MODE) {
578        Option::dir_sep = "\\";
579        Option::obj_ext = ".obj";
580    } else {
581        Option::dir_sep = "/";
582        Option::obj_ext = ".o";
583    }
584 }
585
586 bool Option::prepareProject(const QString &pfile)
587 {
588     mkfile::project_build_root.clear();
589     if (mkfile::do_cache) {
590         if (mkfile::cachefile.isEmpty())  { //find it as it has not been specified
591             QDir dir(output_dir);
592             while (!dir.exists(QLatin1String(".qmake.cache")))
593                 if (dir.isRoot() || !dir.cdUp())
594                     goto no_cache;
595             mkfile::cachefile = dir.filePath(QLatin1String(".qmake.cache"));
596             mkfile::project_build_root = dir.path();
597         } else {
598             QFileInfo fi(mkfile::cachefile);
599             mkfile::cachefile = QDir::cleanPath(fi.absoluteFilePath());
600             mkfile::project_build_root = QDir::cleanPath(fi.absolutePath());
601         }
602
603         if (mkfile::qmakespec.isEmpty()) {
604             QMakeProject cproj;
605             if (!cproj.read(mkfile::cachefile, QMakeProject::ReadProFile))
606                 return false;
607             mkfile::qmakespec = cproj.first(QLatin1String("QMAKESPEC"));
608         }
609     }
610   no_cache:
611
612     QString srcpath = (pfile != "-")
613             ? QDir::cleanPath(QFileInfo(pfile).absolutePath()) : qmake_getpwd();
614     if (srcpath != output_dir || mkfile::project_build_root.isEmpty()) {
615         QDir srcdir(srcpath);
616         QDir dstdir(output_dir);
617         do {
618             if (!mkfile::project_build_root.isEmpty()) {
619                 // If we already know the build root, just match up the source root with it.
620                 if (dstdir.path() == mkfile::project_build_root) {
621                     mkfile::project_root = srcdir.path();
622                     break;
623                 }
624             } else {
625                 // Look for mkspecs/ in source and build. First to win determines the root.
626                 if (dstdir.exists("mkspecs") || srcdir.exists("mkspecs")) {
627                     mkfile::project_build_root = dstdir.path();
628                     mkfile::project_root = srcdir.path();
629                     if (mkfile::project_root == mkfile::project_build_root)
630                         mkfile::project_root.clear();
631                     break;
632                 }
633             }
634         } while (!srcdir.isRoot() && srcdir.cdUp() && !dstdir.isRoot() && dstdir.cdUp());
635     } else {
636         mkfile::project_root.clear();
637     }
638
639     return true;
640 }
641
642 bool Option::postProcessProject(QMakeProject *project)
643 {
644     Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
645     if(cpp_ext.isEmpty())
646         cpp_ext << ".cpp"; //something must be there
647     Option::h_ext = project->variables()["QMAKE_EXT_H"];
648     if(h_ext.isEmpty())
649         h_ext << ".h";
650     Option::c_ext = project->variables()["QMAKE_EXT_C"];
651     if(c_ext.isEmpty())
652         c_ext << ".c"; //something must be there
653
654     if(!project->isEmpty("QMAKE_EXT_RES"))
655         Option::res_ext = project->first("QMAKE_EXT_RES");
656     if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
657         Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
658     if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
659         Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
660     if(!project->isEmpty("QMAKE_EXT_PRL"))
661         Option::prl_ext = project->first("QMAKE_EXT_PRL");
662     if(!project->isEmpty("QMAKE_EXT_PRF"))
663         Option::prf_ext = project->first("QMAKE_EXT_PRF");
664     if(!project->isEmpty("QMAKE_EXT_JS"))
665         Option::prf_ext = project->first("QMAKE_EXT_JS");
666     if(!project->isEmpty("QMAKE_EXT_UI"))
667         Option::ui_ext = project->first("QMAKE_EXT_UI");
668     if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
669         Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
670     if(!project->isEmpty("QMAKE_EXT_H_MOC"))
671         Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
672     if(!project->isEmpty("QMAKE_EXT_LEX"))
673         Option::lex_ext = project->first("QMAKE_EXT_LEX");
674     if(!project->isEmpty("QMAKE_EXT_YACC"))
675         Option::yacc_ext = project->first("QMAKE_EXT_YACC");
676     if(!project->isEmpty("QMAKE_EXT_OBJ"))
677         Option::obj_ext = project->first("QMAKE_EXT_OBJ");
678     if(!project->isEmpty("QMAKE_H_MOD_MOC"))
679         Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
680     if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
681         Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
682     if(!project->isEmpty("QMAKE_MOD_LEX"))
683         Option::lex_mod = project->first("QMAKE_MOD_LEX");
684     if(!project->isEmpty("QMAKE_MOD_YACC"))
685         Option::yacc_mod = project->first("QMAKE_MOD_YACC");
686     if(!project->isEmpty("QMAKE_DIR_SEP"))
687         Option::dir_sep = project->first("QMAKE_DIR_SEP");
688     if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
689         Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
690     if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
691         Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
692     return true;
693 }
694
695 QString
696 Option::fixString(QString string, uchar flags)
697 {
698     //const QString orig_string = string;
699     static QHash<FixStringCacheKey, QString> *cache = 0;
700     if(!cache) {
701         cache = new QHash<FixStringCacheKey, QString>;
702         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
703     }
704     FixStringCacheKey cacheKey(string, flags);
705
706     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
707
708     if (it != cache->constEnd()) {
709         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
710         return it.value();
711     }
712
713     //fix the environment variables
714     if(flags & Option::FixEnvVars) {
715         int rep;
716         static QRegExp reg_var("\\$\\(.*\\)");
717         reg_var.setMinimal(true);
718         while((rep = reg_var.indexIn(string)) != -1)
719             string.replace(rep, reg_var.matchedLength(),
720                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
721     }
722
723     //canonicalize it (and treat as a path)
724     if(flags & Option::FixPathCanonicalize) {
725 #if 0
726         string = QFileInfo(string).canonicalFilePath();
727 #endif
728         string = QDir::cleanPath(string);
729     }
730
731     if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
732         string[0] = string[0].toLower();
733
734     bool localSep = (flags & Option::FixPathToLocalSeparators) != 0;
735     bool targetSep = (flags & Option::FixPathToTargetSeparators) != 0;
736     bool normalSep = (flags & Option::FixPathToNormalSeparators) != 0;
737
738     // either none or only one active flag
739     Q_ASSERT(localSep + targetSep + normalSep <= 1);
740     //fix separators
741     if (flags & Option::FixPathToNormalSeparators) {
742         string = string.replace('\\', '/');
743     } else if (flags & Option::FixPathToLocalSeparators) {
744 #if defined(Q_OS_WIN32)
745         string = string.replace('/', '\\');
746 #else
747         string = string.replace('\\', '/');
748 #endif
749     } else if(flags & Option::FixPathToTargetSeparators) {
750         string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
751     }
752
753     if ((string.startsWith("\"") && string.endsWith("\"")) ||
754         (string.startsWith("\'") && string.endsWith("\'")))
755         string = string.mid(1, string.length()-2);
756
757     //cache
758     //qDebug() << "Fix" << orig_string << "->" << string;
759     cache->insert(cacheKey, string);
760     return string;
761 }
762
763 const char *qmake_version()
764 {
765     static char *ret = NULL;
766     if(ret)
767         return ret;
768     ret = (char *)malloc(15);
769     qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
770 #if defined(_MSC_VER) && _MSC_VER >= 1400
771     sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
772 #else
773     sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
774 #endif
775     return ret;
776 }
777
778 void debug_msg_internal(int level, const char *fmt, ...)
779 {
780     if(Option::debug_level < level)
781         return;
782     fprintf(stderr, "DEBUG %d: ", level);
783     {
784         va_list ap;
785         va_start(ap, fmt);
786         vfprintf(stderr, fmt, ap);
787         va_end(ap);
788     }
789     fprintf(stderr, "\n");
790 }
791
792 void warn_msg(QMakeWarn type, const char *fmt, ...)
793 {
794     if(!(Option::warn_level & type))
795         return;
796     fprintf(stderr, "WARNING: ");
797     {
798         va_list ap;
799         va_start(ap, fmt);
800         vfprintf(stderr, fmt, ap);
801         va_end(ap);
802     }
803     fprintf(stderr, "\n");
804 }
805
806 class QMakeCacheClearItem {
807 private:
808     qmakeCacheClearFunc func;
809     void **data;
810 public:
811     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
812     ~QMakeCacheClearItem() {
813         (*func)(*data);
814         *data = 0;
815     }
816 };
817 static QList<QMakeCacheClearItem*> cache_items;
818
819 void
820 qmakeClearCaches()
821 {
822     qDeleteAll(cache_items);
823     cache_items.clear();
824 }
825
826 void
827 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
828 {
829     cache_items.append(new QMakeCacheClearItem(func, data));
830 }
831
832 QString qmake_libraryInfoFile()
833 {
834     if(!Option::qmake_abslocation.isEmpty())
835         return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
836     return QString();
837 }
838
839 QT_END_NAMESPACE