1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the qmake application of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
default_mode(QString progname)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 
detectProjectFile(const QString & path)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();
usage(const char * a0)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
parseCommandLine(int argc,char ** argv,int skip)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
detectShellPath()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
init(int argc,char ** argv)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             paths.prepend(QLatin1String("."));
448 #else
449             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
450 #endif
451             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
452                 if ((*p).isEmpty())
453                     continue;
454                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
455 #ifdef Q_OS_WIN
456                 candidate += ".exe";
457 #endif
458                 if (QFile::exists(candidate)) {
459                     Option::qmake_abslocation = candidate;
460                     break;
461                 }
462             }
463         }
464         if(!Option::qmake_abslocation.isNull())
465             Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
466     } else {
467         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
468     }
469 
470     const QByteArray envflags = qgetenv("QMAKEFLAGS");
471     if (!envflags.isNull()) {
472         int env_argc = 0, env_size = 0, currlen=0;
473         char quote = 0, **env_argv = NULL;
474         for (int i = 0; i < envflags.size(); ++i) {
475             if (!quote && (envflags.at(i) == '\'' || envflags.at(i) == '"')) {
476                 quote = envflags.at(i);
477             } else if (envflags.at(i) == quote) {
478                 quote = 0;
479             } else if (!quote && envflags.at(i) == ' ') {
480                 if (currlen && env_argv && env_argv[env_argc]) {
481                     env_argv[env_argc][currlen] = '\0';
482                     currlen = 0;
483                     env_argc++;
484                 }
485             } else {
486                 if(!env_argv || env_argc > env_size) {
487                     env_argv = (char **)realloc(env_argv, sizeof(char *)*(env_size+=10));
488                     for(int i2 = env_argc; i2 < env_size; i2++)
489                         env_argv[i2] = NULL;
490                 }
491                 if(!env_argv[env_argc]) {
492                     currlen = 0;
493                     env_argv[env_argc] = (char*)malloc(255);
494                 }
495                 if(currlen < 255)
496                     env_argv[env_argc][currlen++] = envflags.at(i);
497             }
498         }
499         if(env_argv) {
500             if(env_argv[env_argc]) {
501                 env_argv[env_argc][currlen] = '\0';
502                 currlen = 0;
503                 env_argc++;
504             }
505             parseCommandLine(env_argc, env_argv);
506             for(int i2 = 0; i2 < env_size; i2++) {
507                 if(env_argv[i2])
508                     free(env_argv[i2]);
509             }
510             free(env_argv);
511         }
512     }
513     if(argc && argv) {
514         int ret = parseCommandLine(argc, argv, 1);
515         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
516             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
517                 usage(argv[0]);
518             return ret;
519             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
520         }
521     }
522 
523     //last chance for defaults
524     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
525         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
526         if(Option::mkfile::qmakespec.isNull() || Option::mkfile::qmakespec.isEmpty())
527             Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
528 
529         //try REALLY hard to do it for them, lazy..
530         if(Option::mkfile::project_files.isEmpty()) {
531             QString proj = detectProjectFile(qmake_getpwd());
532             if(!proj.isNull())
533                 Option::mkfile::project_files.append(proj);
534 #ifndef QT_BUILD_QMAKE_LIBRARY
535             if(Option::mkfile::project_files.isEmpty()) {
536                 usage(argv[0]);
537                 return Option::QMAKE_CMDLINE_ERROR;
538             }
539 #endif
540         }
541     } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
542 #if defined(Q_OS_MAC)
543         Option::host_mode = Option::HOST_MACX_MODE;
544         Option::target_mode = Option::TARG_MACX_MODE;
545 #elif defined(Q_OS_UNIX)
546         Option::host_mode = Option::HOST_UNIX_MODE;
547         Option::target_mode = Option::TARG_UNIX_MODE;
548 #else
549         Option::host_mode = Option::HOST_WIN_MODE;
550         Option::target_mode = Option::TARG_WIN_MODE;
551 #endif
552     }
553 
554     //defaults for globals
555     if (Option::host_mode != Option::HOST_UNKNOWN_MODE)
556         applyHostMode();
557     return QMAKE_CMDLINE_SUCCESS;
558 }
559 
applyHostMode()560 void Option::applyHostMode()
561 {
562    if (Option::host_mode == Option::HOST_WIN_MODE) {
563        Option::dir_sep = "\\";
564        Option::obj_ext = ".obj";
565    } else {
566        Option::dir_sep = "/";
567        Option::obj_ext = ".o";
568    }
569 }
570 
postProcessProject(QMakeProject * project)571 bool Option::postProcessProject(QMakeProject *project)
572 {
573     Option::cpp_ext = project->variables()["QMAKE_EXT_CPP"];
574     if(cpp_ext.isEmpty())
575         cpp_ext << ".cpp"; //something must be there
576     Option::h_ext = project->variables()["QMAKE_EXT_H"];
577     if(h_ext.isEmpty())
578         h_ext << ".h";
579     Option::c_ext = project->variables()["QMAKE_EXT_C"];
580     if(c_ext.isEmpty())
581         c_ext << ".c"; //something must be there
582 
583     if(!project->isEmpty("QMAKE_EXT_RES"))
584         Option::res_ext = project->first("QMAKE_EXT_RES");
585     if(!project->isEmpty("QMAKE_EXT_PKGCONFIG"))
586         Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG");
587     if(!project->isEmpty("QMAKE_EXT_LIBTOOL"))
588         Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL");
589     if(!project->isEmpty("QMAKE_EXT_PRL"))
590         Option::prl_ext = project->first("QMAKE_EXT_PRL");
591     if(!project->isEmpty("QMAKE_EXT_PRF"))
592         Option::prf_ext = project->first("QMAKE_EXT_PRF");
593     if(!project->isEmpty("QMAKE_EXT_JS"))
594         Option::prf_ext = project->first("QMAKE_EXT_JS");
595     if(!project->isEmpty("QMAKE_EXT_UI"))
596         Option::ui_ext = project->first("QMAKE_EXT_UI");
597     if(!project->isEmpty("QMAKE_EXT_CPP_MOC"))
598         Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC");
599     if(!project->isEmpty("QMAKE_EXT_H_MOC"))
600         Option::h_moc_ext = project->first("QMAKE_EXT_H_MOC");
601     if(!project->isEmpty("QMAKE_EXT_LEX"))
602         Option::lex_ext = project->first("QMAKE_EXT_LEX");
603     if(!project->isEmpty("QMAKE_EXT_YACC"))
604         Option::yacc_ext = project->first("QMAKE_EXT_YACC");
605     if(!project->isEmpty("QMAKE_EXT_OBJ"))
606         Option::obj_ext = project->first("QMAKE_EXT_OBJ");
607     if(!project->isEmpty("QMAKE_H_MOD_MOC"))
608         Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC");
609     if(!project->isEmpty("QMAKE_CPP_MOD_MOC"))
610         Option::cpp_moc_mod = project->first("QMAKE_CPP_MOD_MOC");
611     if(!project->isEmpty("QMAKE_MOD_LEX"))
612         Option::lex_mod = project->first("QMAKE_MOD_LEX");
613     if(!project->isEmpty("QMAKE_MOD_YACC"))
614         Option::yacc_mod = project->first("QMAKE_MOD_YACC");
615     if(!project->isEmpty("QMAKE_DIR_SEP"))
616         Option::dir_sep = project->first("QMAKE_DIR_SEP");
617     if(!project->isEmpty("QMAKE_DIRLIST_SEP"))
618         Option::dirlist_sep = project->first("QMAKE_DIRLIST_SEP");
619     if(!project->isEmpty("QMAKE_MOD_SYSTEM_ENV"))
620         Option::sysenv_mod = project->first("QMAKE_MOD_SYSTEM_ENV");
621     return true;
622 }
623 
624 QString
fixString(QString string,uchar flags)625 Option::fixString(QString string, uchar flags)
626 {
627     //const QString orig_string = string;
628     static QHash<FixStringCacheKey, QString> *cache = 0;
629     if(!cache) {
630         cache = new QHash<FixStringCacheKey, QString>;
631         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
632     }
633     FixStringCacheKey cacheKey(string, flags);
634 
635     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
636 
637     if (it != cache->constEnd()) {
638         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
639         return it.value();
640     }
641 
642     //fix the environment variables
643     if(flags & Option::FixEnvVars) {
644         int rep;
645         static QRegExp reg_var("\\$\\(.*\\)");
646         reg_var.setMinimal(true);
647         while((rep = reg_var.indexIn(string)) != -1)
648             string.replace(rep, reg_var.matchedLength(),
649                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
650     }
651 
652     //canonicalize it (and treat as a path)
653     if(flags & Option::FixPathCanonicalize) {
654 #if 0
655         string = QFileInfo(string).canonicalFilePath();
656 #endif
657         string = QDir::cleanPath(string);
658     }
659 
660     if(string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
661         string[0] = string[0].toLower();
662 
663     //fix separators
664     Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
665     if(flags & Option::FixPathToLocalSeparators) {
666 #if defined(Q_OS_WIN32)
667         string = string.replace('/', '\\');
668 #else
669         string = string.replace('\\', '/');
670 #endif
671     } else if(flags & Option::FixPathToTargetSeparators) {
672         string = string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
673     }
674 
675     if ((string.startsWith("\"") && string.endsWith("\"")) ||
676         (string.startsWith("\'") && string.endsWith("\'")))
677         string = string.mid(1, string.length()-2);
678 
679     //cache
680     //qDebug() << "Fix" << orig_string << "->" << string;
681     cache->insert(cacheKey, string);
682     return string;
683 }
684 
qmake_version()685 const char *qmake_version()
686 {
687     static char *ret = NULL;
688     if(ret)
689         return ret;
690     ret = (char *)malloc(15);
691     qmakeAddCacheClear(qmakeFreeCacheClear, (void**)&ret);
692 #if defined(_MSC_VER) && _MSC_VER >= 1400
693     sprintf_s(ret, 15, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
694 #else
695     sprintf(ret, "%d.%02d%c", QMAKE_VERSION_MAJOR, QMAKE_VERSION_MINOR, 'a' + QMAKE_VERSION_PATCH);
696 #endif
697     return ret;
698 }
699 
debug_msg_internal(int level,const char * fmt,...)700 void debug_msg_internal(int level, const char *fmt, ...)
701 {
702     if(Option::debug_level < level)
703         return;
704     fprintf(stderr, "DEBUG %d: ", level);
705     {
706         va_list ap;
707         va_start(ap, fmt);
708         vfprintf(stderr, fmt, ap);
709         va_end(ap);
710     }
711     fprintf(stderr, "\n");
712 }
713 
warn_msg(QMakeWarn type,const char * fmt,...)714 void warn_msg(QMakeWarn type, const char *fmt, ...)
715 {
716     if(!(Option::warn_level & type))
717         return;
718     fprintf(stderr, "WARNING: ");
719     {
720         va_list ap;
721         va_start(ap, fmt);
722         vfprintf(stderr, fmt, ap);
723         va_end(ap);
724     }
725     fprintf(stderr, "\n");
726 }
727 
728 class QMakeCacheClearItem {
729 private:
730     qmakeCacheClearFunc func;
731     void **data;
732 public:
QMakeCacheClearItem(qmakeCacheClearFunc f,void ** d)733     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
~QMakeCacheClearItem()734     ~QMakeCacheClearItem() {
735         (*func)(*data);
736         *data = 0;
737     }
738 };
739 static QList<QMakeCacheClearItem*> cache_items;
740 
741 void
qmakeClearCaches()742 qmakeClearCaches()
743 {
744     qDeleteAll(cache_items);
745     cache_items.clear();
746 }
747 
748 void
qmakeAddCacheClear(qmakeCacheClearFunc func,void ** data)749 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
750 {
751     cache_items.append(new QMakeCacheClearItem(func, data));
752 }
753 
qmake_libraryInfoFile()754 QString qmake_libraryInfoFile()
755 {
756     if(!Option::qmake_abslocation.isEmpty())
757         return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
758     return QString();
759 }
760 
761 QT_END_NAMESPACE
762