1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the qmake application of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "option.h"
30 #include "cachekeys.h"
31 #include <ioutils.h>
32 #include <qdir.h>
33 #include <qregexp.h>
34 #include <qhash.h>
35 #include <qdebug.h>
36 #include <qlibraryinfo.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 
40 QT_BEGIN_NAMESPACE
41 
42 using namespace QMakeInternal;
43 
44 EvalHandler Option::evalHandler;
45 QMakeGlobals *Option::globals;
46 ProFileCache *Option::proFileCache;
47 QMakeVfs *Option::vfs;
48 QMakeParser *Option::parser;
49 
50 //convenience
51 QString Option::prf_ext;
52 QString Option::prl_ext;
53 QString Option::libtool_ext;
54 QString Option::pkgcfg_ext;
55 QString Option::ui_ext;
56 QStringList Option::h_ext;
57 QString Option::cpp_moc_ext;
58 QStringList Option::cpp_ext;
59 QStringList Option::c_ext;
60 QString Option::objc_ext;
61 QString Option::objcpp_ext;
62 QString Option::obj_ext;
63 QString Option::lex_ext;
64 QString Option::yacc_ext;
65 QString Option::pro_ext;
66 QString Option::dir_sep;
67 QString Option::h_moc_mod;
68 QString Option::yacc_mod;
69 QString Option::lex_mod;
70 QString Option::res_ext;
71 char Option::field_sep;
72 
73 //mode
74 Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
75 
76 //all modes
77 int Option::warn_level = WarnLogic | WarnDeprecated;
78 int Option::debug_level = 0;
79 QFile Option::output;
80 QString Option::output_dir;
81 bool Option::recursive = false;
82 
83 //QMAKE_*_PROPERTY stuff
84 QStringList Option::prop::properties;
85 
86 //QMAKE_GENERATE_PROJECT stuff
87 bool Option::projfile::do_pwd = true;
88 QStringList Option::projfile::project_dirs;
89 
90 //QMAKE_GENERATE_MAKEFILE stuff
91 int Option::mkfile::cachefile_depth = -1;
92 bool Option::mkfile::do_deps = true;
93 bool Option::mkfile::do_mocs = true;
94 bool Option::mkfile::do_dep_heuristics = true;
95 bool Option::mkfile::do_preprocess = false;
96 QStringList Option::mkfile::project_files;
97 
default_mode(QString progname)98 static Option::QMAKE_MODE default_mode(QString progname)
99 {
100     int s = progname.lastIndexOf(QDir::separator());
101     if(s != -1)
102         progname = progname.right(progname.length() - (s + 1));
103     if(progname == "qmakegen")
104         return Option::QMAKE_GENERATE_PROJECT;
105     else if(progname == "qt-config")
106         return Option::QMAKE_QUERY_PROPERTY;
107     return Option::QMAKE_GENERATE_MAKEFILE;
108 }
109 
detectProjectFile(const QString & path)110 static QString detectProjectFile(const QString &path)
111 {
112     QString ret;
113     QDir dir(path);
114     if(dir.exists(dir.dirName() + Option::pro_ext)) {
115         ret = dir.filePath(dir.dirName()) + Option::pro_ext;
116     } else { //last try..
117         QStringList profiles = dir.entryList(QStringList("*" + Option::pro_ext));
118         if(profiles.count() == 1)
119             ret = dir.filePath(profiles.at(0));
120     }
121     return ret;
122 }
123 
usage(const char * a0)124 bool usage(const char *a0)
125 {
126     fprintf(stdout, "Usage: %s [mode] [options] [files]\n"
127             "\n"
128             "QMake has two modes, one mode for generating project files based on\n"
129             "some heuristics, and the other for generating makefiles. Normally you\n"
130             "shouldn't need to specify a mode, as makefile generation is the default\n"
131             "mode for qmake, but you may use this to test qmake on an existing project\n"
132             "\n"
133             "Mode:\n"
134             "  -project       Put qmake into project file generation mode%s\n"
135             "                 In this mode qmake interprets [files] as files to\n"
136             "                 be added to the .pro file. By default, all files with\n"
137             "                 known source extensions are added.\n"
138             "                 Note: The created .pro file probably will \n"
139             "                 need to be edited. For example add the QT variable to \n"
140             "                 specify what modules are required.\n"
141             "  -makefile      Put qmake into makefile generation mode%s\n"
142             "                 In this mode qmake interprets files as project files to\n"
143             "                 be processed, if skipped qmake will try to find a project\n"
144             "                 file in your current working directory\n"
145             "\n"
146             "Warnings Options:\n"
147             "  -Wnone         Turn off all warnings; specific ones may be re-enabled by\n"
148             "                 later -W options\n"
149             "  -Wall          Turn on all warnings\n"
150             "  -Wparser       Turn on parser warnings\n"
151             "  -Wlogic        Turn on logic warnings (on by default)\n"
152             "  -Wdeprecated   Turn on deprecation warnings (on by default)\n"
153             "\n"
154             "Options:\n"
155             "   * You can place any variable assignment in options and it will be *\n"
156             "   * processed as if it was in [files]. These assignments will be    *\n"
157             "   * processed before [files] by default.                            *\n"
158             "  -o file        Write output to file\n"
159             "  -d             Increase debug level\n"
160             "  -t templ       Overrides TEMPLATE as templ\n"
161             "  -tp prefix     Overrides TEMPLATE so that prefix is prefixed into the value\n"
162             "  -help          This help\n"
163             "  -v             Version information\n"
164             "  -early         All subsequent variable assignments will be\n"
165             "                 parsed right before default_pre.prf\n"
166             "  -before        All subsequent variable assignments will be\n"
167             "                 parsed right before [files] (the default)\n"
168             "  -after         All subsequent variable assignments will be\n"
169             "                 parsed after [files]\n"
170             "  -late          All subsequent variable assignments will be\n"
171             "                 parsed right after default_post.prf\n"
172             "  -norecursive   Don't do a recursive search\n"
173             "  -recursive     Do a recursive search\n"
174             "  -set <prop> <value> Set persistent property\n"
175             "  -unset <prop>  Unset persistent property\n"
176             "  -query <prop>  Query persistent property. Show all if <prop> is empty.\n"
177             "  -qtconf file   Use file instead of looking for qt.conf\n"
178             "  -cache file    Use file as cache           [makefile mode only]\n"
179             "  -spec spec     Use spec as QMAKESPEC       [makefile mode only]\n"
180             "  -nocache       Don't use a cache file      [makefile mode only]\n"
181             "  -nodepend      Don't generate dependencies [makefile mode only]\n"
182             "  -nomoc         Don't generate moc targets  [makefile mode only]\n"
183             "  -nopwd         Don't look for files in pwd [project mode only]\n"
184             ,a0,
185             default_mode(a0) == Option::QMAKE_GENERATE_PROJECT  ? " (default)" : "",
186             default_mode(a0) == Option::QMAKE_GENERATE_MAKEFILE ? " (default)" : ""
187         );
188     return false;
189 }
190 
191 int
parseCommandLine(QStringList & args,QMakeCmdLineParserState & state)192 Option::parseCommandLine(QStringList &args, QMakeCmdLineParserState &state)
193 {
194     enum { ArgNone, ArgOutput } argState = ArgNone;
195     int x = 0;
196     while (x < args.count()) {
197         switch (argState) {
198         case ArgOutput:
199             Option::output.setFileName(args.at(x--));
200             args.erase(args.begin() + x, args.begin() + x + 2);
201             argState = ArgNone;
202             continue;
203         default:
204             QMakeGlobals::ArgumentReturn cmdRet = globals->addCommandLineArguments(state, args, &x);
205             if (cmdRet == QMakeGlobals::ArgumentsOk)
206                 break;
207             if (cmdRet == QMakeGlobals::ArgumentMalformed) {
208                 fprintf(stderr, "***Option %s requires a parameter\n", qPrintable(args.at(x - 1)));
209                 return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
210             }
211             Q_ASSERT(cmdRet == QMakeGlobals::ArgumentUnknown);
212             QString arg = args.at(x);
213             if (arg.startsWith(QLatin1Char('-'))) {
214                 if (arg == "-d") {
215                     Option::debug_level++;
216                 } else if (arg == "-v" || arg == "-version" || arg == "--version") {
217                     fprintf(stdout,
218                             "QMake version %s\n"
219                             "Using Qt version %s in %s\n",
220                             QMAKE_VERSION_STR, QT_VERSION_STR,
221                             QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
222 #ifdef QMAKE_OPENSOURCE_VERSION
223                     fprintf(stdout, "QMake is Open Source software from The Qt Company Ltd and/or its subsidiary(-ies).\n");
224 #endif
225                     return Option::QMAKE_CMDLINE_BAIL;
226                 } else if (arg == "-h" || arg == "-help" || arg == "--help") {
227                     return Option::QMAKE_CMDLINE_SHOW_USAGE;
228                 } else if (arg == "-Wall") {
229                     Option::warn_level |= WarnAll;
230                 } else if (arg == "-Wparser") {
231                     Option::warn_level |= WarnParser;
232                 } else if (arg == "-Wlogic") {
233                     Option::warn_level |= WarnLogic;
234                 } else if (arg == "-Wdeprecated") {
235                     Option::warn_level |= WarnDeprecated;
236                 } else if (arg == "-Wnone") {
237                     Option::warn_level = WarnNone;
238                 } else if (arg == "-r" || arg == "-recursive") {
239                     Option::recursive = true;
240                     args.removeAt(x);
241                     continue;
242                 } else if (arg == "-nr" || arg == "-norecursive") {
243                     Option::recursive = false;
244                     args.removeAt(x);
245                     continue;
246                 } else if (arg == "-o" || arg == "-output") {
247                     argState = ArgOutput;
248                 } else {
249                     if (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
250                         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
251                         if (arg == "-nodepend" || arg == "-nodepends") {
252                             Option::mkfile::do_deps = false;
253                         } else if (arg == "-nomoc") {
254                             Option::mkfile::do_mocs = false;
255                         } else if (arg == "-nodependheuristics") {
256                             Option::mkfile::do_dep_heuristics = false;
257                         } else if (arg == "-E") {
258                             Option::mkfile::do_preprocess = true;
259                         } else {
260                             fprintf(stderr, "***Unknown option %s\n", arg.toLatin1().constData());
261                             return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
262                         }
263                     } else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
264                         if (arg == "-nopwd") {
265                             Option::projfile::do_pwd = false;
266                         } else {
267                             fprintf(stderr, "***Unknown option %s\n", arg.toLatin1().constData());
268                             return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
269                         }
270                     }
271                 }
272             } else {
273                 bool handled = true;
274                 if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
275                     Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
276                     Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY) {
277                     Option::prop::properties.append(arg);
278                 } else {
279                     QFileInfo fi(arg);
280                     if(!fi.makeAbsolute()) //strange
281                         arg = fi.filePath();
282                     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
283                        Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
284                         if(fi.isDir()) {
285                             QString proj = detectProjectFile(arg);
286                             if (!proj.isNull())
287                                 arg = proj;
288                         }
289                         Option::mkfile::project_files.append(arg);
290                     } else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
291                         Option::projfile::project_dirs.append(arg);
292                     } else {
293                         handled = false;
294                     }
295                 }
296                 if(!handled) {
297                     return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
298                 }
299                 args.removeAt(x);
300                 continue;
301             }
302         }
303         x++;
304     }
305     if (argState != ArgNone) {
306         fprintf(stderr, "***Option %s requires a parameter\n", qPrintable(args.at(x - 1)));
307         return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
308     }
309     return Option::QMAKE_CMDLINE_SUCCESS;
310 }
311 
312 int
init(int argc,char ** argv)313 Option::init(int argc, char **argv)
314 {
315     Option::prf_ext = ".prf";
316     Option::pro_ext = ".pro";
317     Option::field_sep = ' ';
318 
319     if(argc && argv) {
320         QString argv0 = argv[0];
321 #ifdef Q_OS_WIN
322         if (!argv0.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive))
323             argv0 += QLatin1String(".exe");
324 #endif
325         if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
326             Option::qmake_mode = default_mode(argv0);
327         if (!argv0.isEmpty() && IoUtils::isAbsolutePath(argv0)) {
328             globals->qmake_abslocation = argv0;
329         } else if (argv0.contains(QLatin1Char('/'))
330 #ifdef Q_OS_WIN
331                    || argv0.contains(QLatin1Char('\\'))
332 #endif
333             ) { //relative PWD
334             globals->qmake_abslocation = QDir::current().absoluteFilePath(argv0);
335         } else { //in the PATH
336             QByteArray pEnv = qgetenv("PATH");
337             QDir currentDir = QDir::current();
338 #ifdef Q_OS_WIN
339             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
340             paths.prepend(QLatin1String("."));
341 #else
342             QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
343 #endif
344             for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
345                 if ((*p).isEmpty())
346                     continue;
347                 QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
348                 if (QFile::exists(candidate)) {
349                     globals->qmake_abslocation = candidate;
350                     break;
351                 }
352             }
353         }
354         if (Q_UNLIKELY(globals->qmake_abslocation.isNull())) {
355             // This is rather unlikely to ever happen on a modern system ...
356             globals->qmake_abslocation = QLibraryInfo::rawLocation(
357                                                 QLibraryInfo::HostBinariesPath,
358                                                 QLibraryInfo::EffectivePaths)
359 #ifdef Q_OS_WIN
360                                          + "/qmake.exe";
361 #else
362                                          + "/qmake";
363 #endif
364         } else {
365             globals->qmake_abslocation = QDir::cleanPath(globals->qmake_abslocation);
366         }
367     } else {
368         Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
369     }
370 
371     QMakeCmdLineParserState cmdstate(QDir::currentPath());
372     const QByteArray envflags = qgetenv("QMAKEFLAGS");
373     if (!envflags.isNull()) {
374         QStringList args;
375         QByteArray buf = "";
376         char quote = 0;
377         bool hasWord = false;
378         for (int i = 0; i < envflags.size(); ++i) {
379             char c = envflags.at(i);
380             if (!quote && (c == '\'' || c == '"')) {
381                 quote = c;
382             } else if (c == quote) {
383                 quote = 0;
384             } else if (!quote && c == ' ') {
385                 if (hasWord) {
386                     args << QString::fromLocal8Bit(buf);
387                     hasWord = false;
388                     buf = "";
389                 }
390             } else {
391                 buf += c;
392                 hasWord = true;
393             }
394         }
395         if (hasWord)
396             args << QString::fromLocal8Bit(buf);
397         parseCommandLine(args, cmdstate);
398         cmdstate.flush();
399     }
400     if(argc && argv) {
401         QStringList args;
402         args.reserve(argc - 1);
403         for (int i = 1; i < argc; i++)
404             args << QString::fromLocal8Bit(argv[i]);
405 
406         while (!args.isEmpty()) {
407             QString opt = args.at(0);
408             if (opt == "-project") {
409                 Option::recursive = true;
410                 Option::qmake_mode = Option::QMAKE_GENERATE_PROJECT;
411             } else if (opt == "-prl") {
412                 Option::mkfile::do_deps = false;
413                 Option::mkfile::do_mocs = false;
414                 Option::qmake_mode = Option::QMAKE_GENERATE_PRL;
415             } else if (opt == "-set") {
416                 Option::qmake_mode = Option::QMAKE_SET_PROPERTY;
417             } else if (opt == "-unset") {
418                 Option::qmake_mode = Option::QMAKE_UNSET_PROPERTY;
419             } else if (opt == "-query") {
420                 Option::qmake_mode = Option::QMAKE_QUERY_PROPERTY;
421             } else if (opt == "-makefile") {
422                 Option::qmake_mode = Option::QMAKE_GENERATE_MAKEFILE;
423             } else {
424                 break;
425             }
426             args.takeFirst();
427             break;
428         }
429 
430         int ret = parseCommandLine(args, cmdstate);
431         if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
432             if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
433                 usage(argv[0]);
434             return ret;
435             //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
436         }
437         globals->qmake_args = args;
438         globals->qmake_extra_args = cmdstate.extraargs;
439     }
440     globals->commitCommandLineArguments(cmdstate);
441     globals->debugLevel = Option::debug_level;
442 
443     //last chance for defaults
444     if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
445         Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
446         globals->useEnvironment();
447 
448         //try REALLY hard to do it for them, lazy..
449         if(Option::mkfile::project_files.isEmpty()) {
450             QString proj = detectProjectFile(qmake_getpwd());
451             if(!proj.isNull())
452                 Option::mkfile::project_files.append(proj);
453 #ifndef QT_BUILD_QMAKE_LIBRARY
454             if(Option::mkfile::project_files.isEmpty()) {
455                 usage(argv[0]);
456                 return Option::QMAKE_CMDLINE_ERROR;
457             }
458 #endif
459         }
460     }
461 
462     return QMAKE_CMDLINE_SUCCESS;
463 }
464 
prepareProject(const QString & pfile)465 void Option::prepareProject(const QString &pfile)
466 {
467     // Canonicalize only the directory, otherwise things will go haywire
468     // if the file itself is a symbolic link.
469     const QString srcpath = QFileInfo(QFileInfo(pfile).absolutePath()).canonicalFilePath();
470     globals->setDirectories(srcpath, output_dir);
471 }
472 
postProcessProject(QMakeProject * project)473 bool Option::postProcessProject(QMakeProject *project)
474 {
475     Option::cpp_ext = project->values("QMAKE_EXT_CPP").toQStringList();
476     Option::h_ext = project->values("QMAKE_EXT_H").toQStringList();
477     Option::c_ext = project->values("QMAKE_EXT_C").toQStringList();
478     Option::objc_ext = project->first("QMAKE_EXT_OBJC").toQString();
479     Option::objcpp_ext = project->first("QMAKE_EXT_OBJCXX").toQString();
480     Option::res_ext = project->first("QMAKE_EXT_RES").toQString();
481     Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG").toQString();
482     Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL").toQString();
483     Option::prl_ext = project->first("QMAKE_EXT_PRL").toQString();
484     Option::ui_ext = project->first("QMAKE_EXT_UI").toQString();
485     Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC").toQString();
486     Option::lex_ext = project->first("QMAKE_EXT_LEX").toQString();
487     Option::yacc_ext = project->first("QMAKE_EXT_YACC").toQString();
488     Option::obj_ext = project->first("QMAKE_EXT_OBJ").toQString();
489     Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC").toQString();
490     Option::lex_mod = project->first("QMAKE_MOD_LEX").toQString();
491     Option::yacc_mod = project->first("QMAKE_MOD_YACC").toQString();
492 
493     Option::dir_sep = project->dirSep().toQString();
494 
495     if (!project->buildRoot().isEmpty() && Option::output_dir.startsWith(project->buildRoot()))
496         Option::mkfile::cachefile_depth =
497                 Option::output_dir.mid(project->buildRoot().length()).count('/');
498 
499     return true;
500 }
501 
502 QString
fixString(QString string,uchar flags)503 Option::fixString(QString string, uchar flags)
504 {
505     //const QString orig_string = string;
506     static QHash<FixStringCacheKey, QString> *cache = nullptr;
507     if(!cache) {
508         cache = new QHash<FixStringCacheKey, QString>;
509         qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
510     }
511     FixStringCacheKey cacheKey(string, flags);
512 
513     QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
514 
515     if (it != cache->constEnd()) {
516         //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
517         return it.value();
518     }
519 
520     //fix the environment variables
521     if(flags & Option::FixEnvVars) {
522         int rep;
523         static QRegExp reg_var("\\$\\(.*\\)");
524         reg_var.setMinimal(true);
525         while((rep = reg_var.indexIn(string)) != -1)
526             string.replace(rep, reg_var.matchedLength(),
527                            QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_var.matchedLength() - 3).toLatin1().constData()).constData()));
528     }
529 
530     //canonicalize it (and treat as a path)
531     if(flags & Option::FixPathCanonicalize) {
532 #if 0
533         string = QFileInfo(string).canonicalFilePath();
534 #endif
535         string = QDir::cleanPath(string);
536     }
537 
538     // either none or only one active flag
539     Q_ASSERT(((flags & Option::FixPathToLocalSeparators) != 0) +
540              ((flags & Option::FixPathToTargetSeparators) != 0) +
541              ((flags & Option::FixPathToNormalSeparators) != 0) <= 1);
542 
543     //fix separators
544     if (flags & Option::FixPathToNormalSeparators) {
545         string.replace('\\', '/');
546     } else if (flags & Option::FixPathToLocalSeparators) {
547 #if defined(Q_OS_WIN32)
548         string.replace('/', '\\');
549 #else
550         string.replace('\\', '/');
551 #endif
552     } else if(flags & Option::FixPathToTargetSeparators) {
553         string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
554     }
555 
556     if ((string.startsWith("\"") && string.endsWith("\"")) ||
557         (string.startsWith("\'") && string.endsWith("\'")))
558         string = string.mid(1, string.length()-2);
559 
560     //cache
561     //qDebug() << "Fix" << orig_string << "->" << string;
562     cache->insert(cacheKey, string);
563     return string;
564 }
565 
debug_msg_internal(int level,const char * fmt,...)566 void debug_msg_internal(int level, const char *fmt, ...)
567 {
568     if(Option::debug_level < level)
569         return;
570     fprintf(stderr, "DEBUG %d: ", level);
571     {
572         va_list ap;
573         va_start(ap, fmt);
574         vfprintf(stderr, fmt, ap);
575         va_end(ap);
576     }
577     fprintf(stderr, "\n");
578 }
579 
warn_msg(QMakeWarn type,const char * fmt,...)580 void warn_msg(QMakeWarn type, const char *fmt, ...)
581 {
582     if(!(Option::warn_level & type))
583         return;
584     fprintf(stderr, "WARNING: ");
585     {
586         va_list ap;
587         va_start(ap, fmt);
588         vfprintf(stderr, fmt, ap);
589         va_end(ap);
590     }
591     fprintf(stderr, "\n");
592 }
593 
message(int type,const QString & msg,const QString & fileName,int lineNo)594 void EvalHandler::message(int type, const QString &msg, const QString &fileName, int lineNo)
595 {
596     QString pfx;
597     if ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage) {
598         int code = (type & QMakeHandler::CodeMask);
599         if ((code == QMakeHandler::WarnLanguage && !(Option::warn_level & WarnParser))
600             || (code == QMakeHandler::WarnDeprecated && !(Option::warn_level & WarnDeprecated)))
601             return;
602         pfx = QString::fromLatin1("WARNING: ");
603     }
604     if (lineNo > 0)
605         fprintf(stderr, "%s%s:%d: %s\n", qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg));
606     else if (lineNo)
607         fprintf(stderr, "%s%s: %s\n", qPrintable(pfx), qPrintable(fileName), qPrintable(msg));
608     else
609         fprintf(stderr, "%s%s\n", qPrintable(pfx), qPrintable(msg));
610 }
611 
fileMessage(int type,const QString & msg)612 void EvalHandler::fileMessage(int type, const QString &msg)
613 {
614     Q_UNUSED(type)
615     fprintf(stderr, "%s\n", qPrintable(msg));
616 }
617 
aboutToEval(ProFile *,ProFile *,EvalFileType)618 void EvalHandler::aboutToEval(ProFile *, ProFile *, EvalFileType)
619 {
620 }
621 
doneWithEval(ProFile *)622 void EvalHandler::doneWithEval(ProFile *)
623 {
624 }
625 
626 class QMakeCacheClearItem {
627 private:
628     qmakeCacheClearFunc func;
629     void **data;
630 public:
QMakeCacheClearItem(qmakeCacheClearFunc f,void ** d)631     QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
~QMakeCacheClearItem()632     ~QMakeCacheClearItem() {
633         (*func)(*data);
634         *data = nullptr;
635     }
636 };
637 static QList<QMakeCacheClearItem*> cache_items;
638 
639 void
qmakeClearCaches()640 qmakeClearCaches()
641 {
642     qDeleteAll(cache_items);
643     cache_items.clear();
644 }
645 
646 void
qmakeAddCacheClear(qmakeCacheClearFunc func,void ** data)647 qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
648 {
649     cache_items.append(new QMakeCacheClearItem(func, data));
650 }
651 
qmake_libraryInfoFile()652 QString qmake_libraryInfoFile()
653 {
654     if (!Option::globals->qtconf.isEmpty())
655         return Option::globals->qtconf;
656     if (!Option::globals->qmake_abslocation.isEmpty())
657         return QDir(QFileInfo(Option::globals->qmake_abslocation).absolutePath()).filePath("qt.conf");
658     return QString();
659 }
660 
qmake_abslocation()661 QString qmake_abslocation()
662 {
663     return Option::globals->qmake_abslocation;
664 }
665 
666 QT_END_NAMESPACE
667