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

source code of qtbase/qmake/option.cpp