Merge "Merge branch 'buildsystem'" into refs/staging/master
[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 QString Option::h_moc_ext;
64 QStringList Option::cpp_ext;
65 QStringList Option::c_ext;
66 QString Option::obj_ext;
67 QString Option::lex_ext;
68 QString Option::yacc_ext;
69 QString Option::pro_ext;
70 QString Option::dir_sep;
71 QString Option::dirlist_sep;
72 QString Option::h_moc_mod;
73 QString Option::cpp_moc_mod;
74 QString Option::yacc_mod;
75 QString Option::lex_mod;
76 QString Option::sysenv_mod;
77 QString Option::res_ext;
78 char Option::field_sep;
79
80 //mode
81 Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
82
83 //all modes
84 QString Option::qmake_abslocation;
85 int Option::warn_level = WarnLogic | WarnDeprecated;
86 int Option::debug_level = 0;
87 QFile Option::output;
88 QString Option::output_dir;
89 Option::QMAKE_RECURSIVE Option::recursive = Option::QMAKE_RECURSIVE_DEFAULT;
90 QStringList Option::before_user_vars;
91 QStringList Option::after_user_vars;
92 QString Option::user_template;
93 QString Option::user_template_prefix;
94 QStringList Option::shellPath;
95 Option::HOST_MODE Option::host_mode = Option::HOST_UNKNOWN_MODE;
96 Option::TARG_MODE Option::target_mode = Option::TARG_UNKNOWN_MODE;
97 bool Option::target_mode_overridden = false;
98
99 //QMAKE_*_PROPERTY stuff
100 QStringList Option::prop::properties;
101
102 //QMAKE_GENERATE_PROJECT stuff
103 bool Option::projfile::do_pwd = true;
104 QStringList Option::projfile::project_dirs;
105
106 //QMAKE_GENERATE_MAKEFILE stuff
107 QString Option::mkfile::qmakespec;
108 QString Option::mkfile::xqmakespec;
109 int Option::mkfile::cachefile_depth = -1;
110 bool Option::mkfile::do_deps = true;
111 bool Option::mkfile::do_mocs = true;
112 bool Option::mkfile::do_dep_heuristics = true;
113 bool Option::mkfile::do_preprocess = false;
114 bool Option::mkfile::do_stub_makefile = false;
115 bool Option::mkfile::do_cache = true;
116 QString Option::mkfile::source_root;
117 QString Option::mkfile::build_root;
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::ui_ext = ".ui";
424     Option::h_ext << ".h" << ".hpp" << ".hh" << ".hxx";
425     Option::c_ext << ".c";
426 #ifndef Q_OS_WIN
427     Option::h_ext << ".H";
428 #endif
429     Option::cpp_moc_ext = ".moc";
430     Option::h_moc_ext = ".cpp";
431     Option::cpp_ext << ".cpp" << ".cc" << ".cxx";
432 #ifndef Q_OS_WIN
433     Option::cpp_ext << ".C";
434 #endif
435     Option::lex_ext = ".l";
436     Option::yacc_ext = ".y";
437     Option::pro_ext = ".pro";
438 #ifdef Q_OS_WIN
439     Option::dirlist_sep = ";";
440     Option::shellPath = detectShellPath();
441     Option::res_ext = ".res";
442 #else
443     Option::dirlist_sep = ":";
444     Option::shellPath = QStringList("sh");
445 #endif
446     Option::sysenv_mod = "QMAKE_ENV_";
447     Option::field_sep = ' ';
448
449     if(argc && argv) {
450         Option::application_argv0 = argv[0];
451         QString argv0 = argv[0];
452         if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
453             Option::qmake_mode = default_mode(argv0);
454         if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
455             Option::qmake_abslocation = argv0;
456         } else if (argv0.contains(QLatin1Char('/'))
457 #ifdef Q_OS_WIN
458                    || argv0.contains(QLatin1Char('\\'))
459 #endif
460             ) { //relative PWD
461             Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
462         } else { //in the PATH
463             QByteArray pEnv = qgetenv("PATH");
464             QDir currentDir = QDir::current();
465 #ifdef Q_OS_WIN
466             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
467 #else
468             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
469 #endif
470             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
471                 if ((*p).isEmpty())
472                     continue;
473                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
474 #ifdef Q_OS_WIN
475                 candidate += ".exe";
476 #endif
477                 if (QFile::exists(candidate)) {
478                     Option::qmake_abslocation = candidate;
479                     break;
480                 }
481             }
482         }
483         if(!Option::qmake_abslocation.isNull())
484             Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
485     } else {
486         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
487     }
488
489     const QByteArray envflags = qgetenv("QMAKEFLAGS");
490     if (!envflags.isNull()) {
491         int env_argc = 0, env_size = 0, currlen=0;
492         char quote = 0, **env_argv = NULL;
493         for (int i = 0; i < envflags.size(); ++i) {
494             if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
495                 quote = envflags.at(i);
496             } else if (envflags.at(i) == quote) {
497                 quote = 0;
498             } else if (!quote && envflags.at(i) == ' ') {
499                 if (currlen && env_argv && env_argv[env_argc]) {
500                     env_argv[env_argc][currlen] = '\0';
501                     currlen = 0;
502                     env_argc++;
503                 }
504             } else {
505                 if(!env_argv || env_argc > env_size) {
506                     env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
507                     for(int i2 = env_argc; i2 < env_size; i2++)
508                         env_argv[i2] = NULL;
509                 }
510                 if(!env_argv[env_argc]) {
511                     currlen = 0;
512                     env_argv[env_argc] = (char*)malloc(255);
513                 }
514                 if(currlen < 255)
515                     env_argv[env_argc][currlen++] = envflags.at(i);
516             }
517         }
518         if(env_argv) {
519             if(env_argv[env_argc]) {
520                 env_argv[env_argc][currlen] = '\0';
521                 currlen = 0;
522                 env_argc++;
523             }
524             parseCommandLine(env_argc, env_argv);
525             for(int i2 = 0; i2 < env_size; i2++) {
526                 if(env_argv[i2])
527                     free(env_argv[i2]);
528             }
529             free(env_argv);
530         }
531     }
532     if(argc && argv) {
533         int ret = parseCommandLine(argc, argv, 1);
534         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
535             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
536                 usage(argv[0]);
537             return ret;
538             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
539         }
540     }
541
542     //last chance for defaults
543     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
544         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
545         if (Option::mkfile::xqmakespec.isEmpty())
546             Option::mkfile::xqmakespec = QString::fromLocal8Bit(qgetenv("XQMAKESPEC").constData());
547         if (Option::mkfile::qmakespec.isEmpty()) {
548             Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
549             if (Option::mkfile::xqmakespec.isEmpty())
550                 Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
551         }
552
553         //try REALLY hard to do it for them, lazy..
554         if(Option::mkfile::project_files.isEmpty()) {
555             QString proj = detectProjectFile(qmake_getpwd());
556             if(!proj.isNull())
557                 Option::mkfile::project_files.append(proj);
558 #ifndef QT_BUILD_QMAKE_LIBRARY
559             if(Option::mkfile::project_files.isEmpty()) {
560                 usage(argv[0]);
561                 return Option::QMAKE_CMDLINE_ERROR;
562             }
563 #endif
564         }
565     } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
566 #if defined(Q_OS_MAC)
567         Option::host_mode = Option::HOST_MACX_MODE;
568         Option::target_mode = Option::TARG_MACX_MODE;
569 #elif defined(Q_OS_UNIX)
570         Option::host_mode = Option::HOST_UNIX_MODE;
571         Option::target_mode = Option::TARG_UNIX_MODE;
572 #else
573         Option::host_mode = Option::HOST_WIN_MODE;
574         Option::target_mode = Option::TARG_WIN_MODE;
575 #endif
576     }
577
578     //defaults for globals
579     if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
580         applyHostMode();
581     return QMAKE_CMDLINE_SUCCESS;
582 }
583
584 void Option::applyHostMode()
585 {
586    if (Option::host_mode == Option::HOST_WIN_MODE) {
587        Option::dir_sep = "\\";
588        Option::obj_ext = ".obj";
589    } else {
590        Option::dir_sep = "/";
591        Option::obj_ext = ".o";
592    }
593 }
594
595 void Option::prepareProject(const QString &pfile)
596 {
597     QString srcpath = (pfile != "-")
598             ? QDir::cleanPath(QFileInfo(pfile).absolutePath()) : qmake_getpwd();
599     if (srcpath != output_dir) {
600         if (!srcpath.endsWith(QLatin1Char('/')))
601             srcpath += QLatin1Char('/');
602         QString dstpath = output_dir;
603         if (!dstpath.endsWith(QLatin1Char('/')))
604             dstpath += QLatin1Char('/');
605         int srcLen = srcpath.length();
606         int dstLen = dstpath.length();
607         int lastSl = 0;
608         while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
609             if (srcpath.at(srcLen) == QLatin1Char('/'))
610                 lastSl = 1;
611         mkfile::source_root = srcpath.left(srcLen + lastSl);
612         mkfile::build_root = dstpath.left(dstLen + lastSl);
613     } else {
614         mkfile::source_root.clear();
615     }
616 }
617
618 bool Option::postProcessProject(QMakeProject *project)
619 {
620     Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
621     if(cpp_ext.isEmpty())
622         cpp_ext << ".cpp"; //something must be there
623     Option::h_ext = project->variables()["QMAKE_EXT_H"];
624     if(h_ext.isEmpty())
625         h_ext << ".h";
626     Option::c_ext = project->variables()["QMAKE_EXT_C"];
627     if(c_ext.isEmpty())
628         c_ext << ".c"; //something must be there
629
630     if(!project->isEmpty("QMAKE_EXT_RES"))
631         Option::res_ext = project->first("QMAKE_EXT_RES");
632     if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
633         Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
634     if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
635         Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
636     if(!project->isEmpty("QMAKE_EXT_PRL"))
637         Option::prl_ext = project->first("QMAKE_EXT_PRL");
638     if(!project->isEmpty("QMAKE_EXT_PRF"))
639         Option::prf_ext = project->first("QMAKE_EXT_PRF");
640     if(!project->isEmpty("QMAKE_EXT_JS"))
641         Option::prf_ext = project->first("QMAKE_EXT_JS");
642     if(!project->isEmpty("QMAKE_EXT_UI"))
643         Option::ui_ext = project->first("QMAKE_EXT_UI");
644     if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
645         Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
646     if(!project->isEmpty("QMAKE_EXT_H_MOC"))
647         Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
648     if(!project->isEmpty("QMAKE_EXT_LEX"))
649         Option::lex_ext = project->first("QMAKE_EXT_LEX");
650     if(!project->isEmpty("QMAKE_EXT_YACC"))
651         Option::yacc_ext = project->first("QMAKE_EXT_YACC");
652     if(!project->isEmpty("QMAKE_EXT_OBJ"))
653         Option::obj_ext = project->first("QMAKE_EXT_OBJ");
654     if(!project->isEmpty("QMAKE_H_MOD_MOC"))
655         Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
656     if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
657         Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
658     if(!project->isEmpty("QMAKE_MOD_LEX"))
659         Option::lex_mod = project->first("QMAKE_MOD_LEX");
660     if(!project->isEmpty("QMAKE_MOD_YACC"))
661         Option::yacc_mod = project->first("QMAKE_MOD_YACC");
662     if(!project->isEmpty("QMAKE_DIR_SEP"))
663         Option::dir_sep = project->first("QMAKE_DIR_SEP");
664     if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
665         Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
666     if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
667         Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
668     return true;
669 }
670
671 QString
672 Option::fixString(QString string, uchar flags)
673 {
674     //const QString orig_string = string;
675     static QHash<FixStringCacheKey, QString> *cache = 0;
676     if(!cache) {
677         cache = new QHash<FixStringCacheKey, QString>;
678         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
679     }
680     FixStringCacheKey cacheKey(string, flags);
681
682     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
683
684     if (it != cache->constEnd()) {
685         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
686         return it.value();
687     }
688
689     //fix the environment variables
690     if(flags & Option::FixEnvVars) {
691         int rep;
692         static QRegExp reg_var("\\$\\(.*\\)");
693         reg_var.setMinimal(true);
694         while((rep = reg_var.indexIn(string)) != -1)
695             string.replace(rep, reg_var.matchedLength(),
696                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
697     }
698
699     //canonicalize it (and treat as a path)
700     if(flags & Option::FixPathCanonicalize) {
701 #if 0
702         string = QFileInfo(string).canonicalFilePath();
703 #endif
704         string = QDir::cleanPath(string);
705     }
706
707     if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
708         string[0] = string[0].toLower();
709
710     bool localSep = (flags & Option::FixPathToLocalSeparators) != 0;
711     bool targetSep = (flags & Option::FixPathToTargetSeparators) != 0;
712     bool normalSep = (flags & Option::FixPathToNormalSeparators) != 0;
713
714     // either none or only one active flag
715     Q_ASSERT(localSep + targetSep + normalSep <= 1);
716     //fix separators
717     if (flags & Option::FixPathToNormalSeparators) {
718         string = string.replace('\\', '/');
719     } else if (flags & Option::FixPathToLocalSeparators) {
720 #if defined(Q_OS_WIN32)
721         string = string.replace('/', '\\');
722 #else
723         string = string.replace('\\', '/');
724 #endif
725     } else if(flags & Option::FixPathToTargetSeparators) {
726         string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
727     }
728
729     if ((string.startsWith("\"") && string.endsWith("\"")) ||
730         (string.startsWith("\'") && string.endsWith("\'")))
731         string = string.mid(1, string.length()-2);
732
733     //cache
734     //qDebug() << "Fix" << orig_string << "->" << string;
735     cache->insert(cacheKey, string);
736     return string;
737 }
738
739 const char *qmake_version()
740 {
741     static char *ret = NULL;
742     if(ret)
743         return ret;
744     ret = (char *)malloc(15);
745     qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
746 #if defined(_MSC_VER) && _MSC_VER >= 1400
747     sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
748 #else
749     sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
750 #endif
751     return ret;
752 }
753
754 void debug_msg_internal(int level, const char *fmt, ...)
755 {
756     if(Option::debug_level < level)
757         return;
758     fprintf(stderr, "DEBUG %d: ", level);
759     {
760         va_list ap;
761         va_start(ap, fmt);
762         vfprintf(stderr, fmt, ap);
763         va_end(ap);
764     }
765     fprintf(stderr, "\n");
766 }
767
768 void warn_msg(QMakeWarn type, const char *fmt, ...)
769 {
770     if(!(Option::warn_level & type))
771         return;
772     fprintf(stderr, "WARNING: ");
773     {
774         va_list ap;
775         va_start(ap, fmt);
776         vfprintf(stderr, fmt, ap);
777         va_end(ap);
778     }
779     fprintf(stderr, "\n");
780 }
781
782 class QMakeCacheClearItem {
783 private:
784     qmakeCacheClearFunc func;
785     void **data;
786 public:
787     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
788     ~QMakeCacheClearItem() {
789         (*func)(*data);
790         *data = 0;
791     }
792 };
793 static QList<QMakeCacheClearItem*> cache_items;
794
795 void
796 qmakeClearCaches()
797 {
798     qDeleteAll(cache_items);
799     cache_items.clear();
800 }
801
802 void
803 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
804 {
805     cache_items.append(new QMakeCacheClearItem(func, data));
806 }
807
808 QString qmake_libraryInfoFile()
809 {
810     if(!Option::qmake_abslocation.isEmpty())
811         return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
812     return QString();
813 }
814
815 QT_END_NAMESPACE