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 <qregularexpression.h>
34#include <qhash.h>
35#include <qdebug.h>
36#include <qlibraryinfo.h>
37#include <stdlib.h>
38#include <stdarg.h>
39
40QT_BEGIN_NAMESPACE
41
42using namespace QMakeInternal;
43
44EvalHandler Option::evalHandler;
45QMakeGlobals *Option::globals;
46ProFileCache *Option::proFileCache;
47QMakeVfs *Option::vfs;
48QMakeParser *Option::parser;
49
50//convenience
51QString Option::prf_ext;
52QString Option::prl_ext;
53QString Option::libtool_ext;
54QString Option::pkgcfg_ext;
55QString Option::ui_ext;
56QStringList Option::h_ext;
57QString Option::cpp_moc_ext;
58QStringList Option::cpp_ext;
59QStringList Option::c_ext;
60QString Option::objc_ext;
61QString Option::objcpp_ext;
62QString Option::obj_ext;
63QString Option::lex_ext;
64QString Option::yacc_ext;
65QString Option::pro_ext;
66QString Option::dir_sep;
67QString Option::h_moc_mod;
68QString Option::yacc_mod;
69QString Option::lex_mod;
70QString Option::res_ext;
71char Option::field_sep;
72
73//mode
74Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
75
76//all modes
77int Option::warn_level = WarnLogic | WarnDeprecated;
78int Option::debug_level = 0;
79QFile Option::output;
80QString Option::output_dir;
81bool Option::recursive = false;
82
83//QMAKE_*_PROPERTY stuff
84QStringList Option::prop::properties;
85
86//QMAKE_GENERATE_PROJECT stuff
87bool Option::projfile::do_pwd = true;
88QStringList Option::projfile::project_dirs;
89
90//QMAKE_GENERATE_MAKEFILE stuff
91int Option::mkfile::cachefile_depth = -1;
92bool Option::mkfile::do_deps = true;
93bool Option::mkfile::do_mocs = true;
94bool Option::mkfile::do_dep_heuristics = true;
95bool Option::mkfile::do_preprocess = false;
96QStringList Option::mkfile::project_files;
97
98static 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
110static 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
124bool 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
191int
192Option::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::path(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
312int
313Option::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 if (opt == "-qtconf") {
424 // Move the argument following "-qtconf <file>" in front and check again.
425 if (args.length() >= 3)
426 args.prepend(args.takeAt(2));
427 continue;
428 } else {
429 break;
430 }
431 args.takeFirst();
432 break;
433 }
434
435 int ret = parseCommandLine(args, cmdstate);
436 if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
437 if ((ret & Option::QMAKE_CMDLINE_SHOW_USAGE) != 0)
438 usage(argv[0]);
439 return ret;
440 //return ret == QMAKE_CMDLINE_SHOW_USAGE ? usage(argv[0]) : false;
441 }
442 globals->qmake_args = args;
443 globals->qmake_extra_args = cmdstate.extraargs;
444 }
445 globals->commitCommandLineArguments(cmdstate);
446 globals->debugLevel = Option::debug_level;
447
448 //last chance for defaults
449 if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
450 Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
451 globals->useEnvironment();
452
453 //try REALLY hard to do it for them, lazy..
454 if(Option::mkfile::project_files.isEmpty()) {
455 QString proj = detectProjectFile(qmake_getpwd());
456 if(!proj.isNull())
457 Option::mkfile::project_files.append(proj);
458#ifndef QT_BUILD_QMAKE_LIBRARY
459 if(Option::mkfile::project_files.isEmpty()) {
460 usage(argv[0]);
461 return Option::QMAKE_CMDLINE_ERROR;
462 }
463#endif
464 }
465 }
466
467 return QMAKE_CMDLINE_SUCCESS;
468}
469
470void Option::prepareProject(const QString &pfile)
471{
472 // Canonicalize only the directory, otherwise things will go haywire
473 // if the file itself is a symbolic link.
474 const QString srcpath = QFileInfo(QFileInfo(pfile).absolutePath()).canonicalFilePath();
475 globals->setDirectories(srcpath, output_dir);
476}
477
478bool Option::postProcessProject(QMakeProject *project)
479{
480 Option::cpp_ext = project->values("QMAKE_EXT_CPP").toQStringList();
481 Option::h_ext = project->values("QMAKE_EXT_H").toQStringList();
482 Option::c_ext = project->values("QMAKE_EXT_C").toQStringList();
483 Option::objc_ext = project->first("QMAKE_EXT_OBJC").toQString();
484 Option::objcpp_ext = project->first("QMAKE_EXT_OBJCXX").toQString();
485 Option::res_ext = project->first("QMAKE_EXT_RES").toQString();
486 Option::pkgcfg_ext = project->first("QMAKE_EXT_PKGCONFIG").toQString();
487 Option::libtool_ext = project->first("QMAKE_EXT_LIBTOOL").toQString();
488 Option::prl_ext = project->first("QMAKE_EXT_PRL").toQString();
489 Option::ui_ext = project->first("QMAKE_EXT_UI").toQString();
490 Option::cpp_moc_ext = project->first("QMAKE_EXT_CPP_MOC").toQString();
491 Option::lex_ext = project->first("QMAKE_EXT_LEX").toQString();
492 Option::yacc_ext = project->first("QMAKE_EXT_YACC").toQString();
493 Option::obj_ext = project->first("QMAKE_EXT_OBJ").toQString();
494 Option::h_moc_mod = project->first("QMAKE_H_MOD_MOC").toQString();
495 Option::lex_mod = project->first("QMAKE_MOD_LEX").toQString();
496 Option::yacc_mod = project->first("QMAKE_MOD_YACC").toQString();
497
498 Option::dir_sep = project->dirSep().toQString();
499
500 if (!project->buildRoot().isEmpty() && Option::output_dir.startsWith(project->buildRoot()))
501 Option::mkfile::cachefile_depth =
502 Option::output_dir.mid(project->buildRoot().length()).count('/');
503
504 return true;
505}
506
507QString
508Option::fixString(QString string, uchar flags)
509{
510 //const QString orig_string = string;
511 static QHash<FixStringCacheKey, QString> *cache = nullptr;
512 if(!cache) {
513 cache = new QHash<FixStringCacheKey, QString>;
514 qmakeAddCacheClear(qmakeDeleteCacheClear<QHash<FixStringCacheKey, QString> >, (void**)&cache);
515 }
516 FixStringCacheKey cacheKey(string, flags);
517
518 QHash<FixStringCacheKey, QString>::const_iterator it = cache->constFind(cacheKey);
519
520 if (it != cache->constEnd()) {
521 //qDebug() << "Fix (cached) " << orig_string << "->" << it.value();
522 return it.value();
523 }
524
525 //fix the environment variables
526 if(flags & Option::FixEnvVars) {
527 static QRegularExpression reg_var("\\$\\(.*\\)", QRegularExpression::InvertedGreedinessOption);
528 QRegularExpressionMatch match;
529 while ((match = reg_var.match(string)).hasMatch()) {
530 int start = match.capturedStart();
531 int len = match.capturedLength();
532 string.replace(start, len,
533 QString::fromLocal8Bit(qgetenv(string.mid(start + 2, len - 3).toLatin1().constData()).constData()));
534 }
535 }
536
537 //canonicalize it (and treat as a path)
538 if(flags & Option::FixPathCanonicalize) {
539#if 0
540 string = QFileInfo(string).canonicalFilePath();
541#endif
542 string = QDir::cleanPath(string);
543 }
544
545 // either none or only one active flag
546 Q_ASSERT(((flags & Option::FixPathToLocalSeparators) != 0) +
547 ((flags & Option::FixPathToTargetSeparators) != 0) +
548 ((flags & Option::FixPathToNormalSeparators) != 0) <= 1);
549
550 //fix separators
551 if (flags & Option::FixPathToNormalSeparators) {
552 string.replace('\\', '/');
553 } else if (flags & Option::FixPathToLocalSeparators) {
554#if defined(Q_OS_WIN32)
555 string.replace('/', '\\');
556#else
557 string.replace('\\', '/');
558#endif
559 } else if(flags & Option::FixPathToTargetSeparators) {
560 string.replace('/', Option::dir_sep).replace('\\', Option::dir_sep);
561 }
562
563 if ((string.startsWith("\"") && string.endsWith("\"")) ||
564 (string.startsWith("\'") && string.endsWith("\'")))
565 string = string.mid(1, string.length()-2);
566
567 //cache
568 //qDebug() << "Fix" << orig_string << "->" << string;
569 cache->insert(cacheKey, string);
570 return string;
571}
572
573void debug_msg_internal(int level, const char *fmt, ...)
574{
575 if(Option::debug_level < level)
576 return;
577 fprintf(stderr, "DEBUG %d: ", level);
578 {
579 va_list ap;
580 va_start(ap, fmt);
581 vfprintf(stderr, fmt, ap);
582 va_end(ap);
583 }
584 fprintf(stderr, "\n");
585}
586
587void warn_msg(QMakeWarn type, const char *fmt, ...)
588{
589 if(!(Option::warn_level & type))
590 return;
591 fprintf(stderr, "WARNING: ");
592 {
593 va_list ap;
594 va_start(ap, fmt);
595 vfprintf(stderr, fmt, ap);
596 va_end(ap);
597 }
598 fprintf(stderr, "\n");
599}
600
601void EvalHandler::message(int type, const QString &msg, const QString &fileName, int lineNo)
602{
603 QString pfx;
604 if ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage) {
605 int code = (type & QMakeHandler::CodeMask);
606 if ((code == QMakeHandler::WarnLanguage && !(Option::warn_level & WarnParser))
607 || (code == QMakeHandler::WarnDeprecated && !(Option::warn_level & WarnDeprecated)))
608 return;
609 pfx = QString::fromLatin1("WARNING: ");
610 }
611 if (lineNo > 0)
612 fprintf(stderr, "%s%s:%d: %s\n", qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg));
613 else if (lineNo)
614 fprintf(stderr, "%s%s: %s\n", qPrintable(pfx), qPrintable(fileName), qPrintable(msg));
615 else
616 fprintf(stderr, "%s%s\n", qPrintable(pfx), qPrintable(msg));
617}
618
619void EvalHandler::fileMessage(int type, const QString &msg)
620{
621 Q_UNUSED(type);
622 fprintf(stderr, "%s\n", qPrintable(msg));
623}
624
625void EvalHandler::aboutToEval(ProFile *, ProFile *, EvalFileType)
626{
627}
628
629void EvalHandler::doneWithEval(ProFile *)
630{
631}
632
633class QMakeCacheClearItem {
634private:
635 qmakeCacheClearFunc func;
636 void **data;
637public:
638 QMakeCacheClearItem(qmakeCacheClearFunc f, void **d) : func(f), data(d) { }
639 ~QMakeCacheClearItem() {
640 (*func)(*data);
641 *data = nullptr;
642 }
643};
644static QList<QMakeCacheClearItem*> cache_items;
645
646void
647qmakeClearCaches()
648{
649 qDeleteAll(cache_items);
650 cache_items.clear();
651}
652
653void
654qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
655{
656 cache_items.append(new QMakeCacheClearItem(func, data));
657}
658
659QString qmake_libraryInfoFile()
660{
661 if (!Option::globals->qtconf.isEmpty())
662 return Option::globals->qtconf;
663 if (!Option::globals->qmake_abslocation.isEmpty())
664 return QDir(QFileInfo(Option::globals->qmake_abslocation).absolutePath()).filePath("qt.conf");
665 return QString();
666}
667
668QString qmake_abslocation()
669{
670 return Option::globals->qmake_abslocation;
671}
672
673QT_END_NAMESPACE
674