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