Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
4
5#include <depfile_shared.h>
6#include "preprocessor.h"
7#include "moc.h"
9#include "collectjson.h"
10
11#include <qfile.h>
12#include <qfileinfo.h>
13#include <qdir.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <ctype.h>
17#include <errno.h>
18
19#include <qcoreapplication.h>
20#include <qcommandlineoption.h>
21#include <qcommandlineparser.h>
22
23#include <memory>
24
26
27using namespace Qt::StringLiterals;
28
29/*
30 This function looks at two file names and returns the name of the
31 infile with a path relative to outfile.
32
33 Examples:
34
35 /tmp/abc, /tmp/bcd -> abc
36 xyz/a/bc, xyz/b/ac -> ../a/bc
37 /tmp/abc, xyz/klm -> /tmp/abc
38 */
39
40static QByteArray combinePath(const QString &infile, const QString &outfile)
41{
42 QFileInfo inFileInfo(QDir::current(), infile);
43 QFileInfo outFileInfo(QDir::current(), outfile);
44 const QByteArray relativePath = QFile::encodeName(outFileInfo.dir().relativeFilePath(inFileInfo.filePath()));
45#ifdef Q_OS_WIN
46 // It's a system limitation.
47 // It depends on the Win API function which is used by the program to open files.
48 // cl apparently uses the functions that have the MAX_PATH limitation.
49 if (outFileInfo.dir().absolutePath().length() + relativePath.length() + 1 >= 260)
50 return QFile::encodeName(inFileInfo.absoluteFilePath());
51#endif
52 return relativePath;
53}
54
55
56void error(const char *msg = "Invalid argument")
57{
58 if (msg)
59 fprintf(stderr, "moc: %s\n", msg);
60}
61
62static auto openFileForWriting(const QString &name)
63{
64 struct Closer { void operator()(FILE *handle) const { fclose(handle); } };
65 using R = std::unique_ptr<FILE, Closer>;
66
67#ifdef _MSC_VER
68 FILE *file;
69 if (_wfopen_s(&file, reinterpret_cast<const wchar_t *>(name.utf16()), L"w") != 0)
70 return R{};
71 return R{file};
72#else
73 return R{fopen(QFile::encodeName(name).constData(), "w")};
74#endif
75}
76using File = decltype(openFileForWriting({}));
77
78static inline bool hasNext(const Symbols &symbols, int i)
79{ return (i < symbols.size()); }
80
81static inline const Symbol &next(const Symbols &symbols, int &i)
82{ return symbols.at(i++); }
83
84
86 QByteArray output;
87 int lineNum = 1;
88 Token last = PP_NOTOKEN;
89 Token secondlast = last;
90 int i = 0;
91 while (hasNext(symbols, i)) {
92 Symbol sym = next(symbols, i);
93 switch (sym.token) {
94 case PP_NEWLINE:
95 case PP_WHITESPACE:
96 if (last != PP_WHITESPACE) {
97 secondlast = last;
98 last = PP_WHITESPACE;
99 output += ' ';
100 }
101 continue;
102 case PP_STRING_LITERAL:
103 if (last == PP_STRING_LITERAL)
104 output.chop(1);
105 else if (secondlast == PP_STRING_LITERAL && last == PP_WHITESPACE)
106 output.chop(2);
107 else
108 break;
109 output += sym.lexem().mid(1);
110 secondlast = last;
111 last = PP_STRING_LITERAL;
112 continue;
113 case MOC_INCLUDE_BEGIN:
114 lineNum = 0;
115 continue;
116 case MOC_INCLUDE_END:
117 lineNum = sym.lineNum;
118 continue;
119 default:
120 break;
121 }
122 secondlast = last;
123 last = sym.token;
124
125 const int padding = sym.lineNum - lineNum;
126 if (padding > 0) {
127 output.resize(output.size() + padding);
128 memset(output.data() + output.size() - padding, '\n', padding);
129 lineNum = sym.lineNum;
130 }
131
132 output += sym.lexem();
133 }
134
135 return output;
136}
137
138static QStringList argumentsFromCommandLineAndFile(const QStringList &arguments, bool &hasOptionFiles)
139{
140 QStringList allArguments;
141 hasOptionFiles = false;
142 allArguments.reserve(arguments.size());
143 for (const QString &argument : arguments) {
144 // "@file" doesn't start with a '-' so we can't use QCommandLineParser for it
145 if (argument.startsWith(u'@')) {
146 QString optionsFile = argument;
147 optionsFile.remove(0, 1);
148 if (optionsFile.isEmpty()) {
149 error("The @ option requires an input file");
150 return QStringList();
151 }
152 QFile f(optionsFile);
153 if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
154 error("Cannot open options file specified with @");
155 return QStringList();
156 }
157 hasOptionFiles = true;
158 while (!f.atEnd()) {
159 QString line = QString::fromLocal8Bit(f.readLine().trimmed());
160 if (!line.isEmpty())
161 allArguments << line;
162 }
163 } else {
164 allArguments << argument;
165 }
166 }
167 return allArguments;
168}
169
170int runMoc(int argc, char **argv)
171{
172 QCoreApplication app(argc, argv);
173 QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_VERSION_STR));
174 // let moc identify itself as moc, even if the binary has been renamed
175 QCoreApplication::setApplicationName(QString::fromLatin1("moc"));
176
177 bool autoInclude = true;
178 bool defaultInclude = true;
179 Preprocessor pp;
180 Moc moc;
181 pp.macros["Q_MOC_RUN"];
182 pp.macros["__cplusplus"];
183
184 // Don't stumble over GCC extensions
185 Macro dummyVariadicFunctionMacro;
186 dummyVariadicFunctionMacro.isFunction = true;
187 dummyVariadicFunctionMacro.isVariadic = true;
188 dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__");
189 pp.macros["__attribute__"] = dummyVariadicFunctionMacro;
190 pp.macros["__declspec"] = dummyVariadicFunctionMacro;
191
192 QString filename;
193 QString output;
194 QFile in;
195 File out;
196
197 // Note that moc isn't translated.
198 // If you use this code as an example for a translated app, make sure to translate the strings.
199 QCommandLineParser parser;
200 parser.setApplicationDescription(QStringLiteral("Qt Meta Object Compiler version %1 (Qt %2)")
201 .arg(mocOutputRevision).arg(QString::fromLatin1(QT_VERSION_STR)));
202 parser.addHelpOption();
203 parser.addVersionOption();
204 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
205
206 QCommandLineOption outputOption(QStringLiteral("o"));
207 outputOption.setDescription(QStringLiteral("Write output to file rather than stdout."));
208 outputOption.setValueName(QStringLiteral("file"));
209 outputOption.setFlags(QCommandLineOption::ShortOptionStyle);
210 parser.addOption(outputOption);
211
212 QCommandLineOption includePathOption(QStringLiteral("I"));
213 includePathOption.setDescription(QStringLiteral("Add dir to the include path for header files."));
214 includePathOption.setValueName(QStringLiteral("dir"));
215 includePathOption.setFlags(QCommandLineOption::ShortOptionStyle);
216 parser.addOption(includePathOption);
217
218 QCommandLineOption macFrameworkOption(QStringLiteral("F"));
219 macFrameworkOption.setDescription(QStringLiteral("Add Mac framework to the include path for header files."));
220 macFrameworkOption.setValueName(QStringLiteral("framework"));
221 macFrameworkOption.setFlags(QCommandLineOption::ShortOptionStyle);
222 parser.addOption(macFrameworkOption);
223
224 QCommandLineOption preprocessOption(QStringLiteral("E"));
225 preprocessOption.setDescription(QStringLiteral("Preprocess only; do not generate meta object code."));
226 parser.addOption(preprocessOption);
227
228 QCommandLineOption defineOption(QStringLiteral("D"));
229 defineOption.setDescription(QStringLiteral("Define macro, with optional definition."));
230 defineOption.setValueName(QStringLiteral("macro[=def]"));
231 defineOption.setFlags(QCommandLineOption::ShortOptionStyle);
232 parser.addOption(defineOption);
233
234 QCommandLineOption undefineOption(QStringLiteral("U"));
235 undefineOption.setDescription(QStringLiteral("Undefine macro."));
236 undefineOption.setValueName(QStringLiteral("macro"));
237 undefineOption.setFlags(QCommandLineOption::ShortOptionStyle);
238 parser.addOption(undefineOption);
239
240 QCommandLineOption metadataOption(QStringLiteral("M"));
241 metadataOption.setDescription(QStringLiteral("Add key/value pair to plugin meta data"));
242 metadataOption.setValueName(QStringLiteral("key=value"));
243 metadataOption.setFlags(QCommandLineOption::ShortOptionStyle);
244 parser.addOption(metadataOption);
245
246 QCommandLineOption compilerFlavorOption(QStringLiteral("compiler-flavor"));
247 compilerFlavorOption.setDescription(QStringLiteral("Set the compiler flavor: either \"msvc\" or \"unix\"."));
248 compilerFlavorOption.setValueName(QStringLiteral("flavor"));
249 parser.addOption(compilerFlavorOption);
250
251 QCommandLineOption noIncludeOption(QStringLiteral("i"));
252 noIncludeOption.setDescription(QStringLiteral("Do not generate an #include statement."));
253 parser.addOption(noIncludeOption);
254
255 QCommandLineOption pathPrefixOption(QStringLiteral("p"));
256 pathPrefixOption.setDescription(QStringLiteral("Path prefix for included file."));
257 pathPrefixOption.setValueName(QStringLiteral("path"));
258 pathPrefixOption.setFlags(QCommandLineOption::ShortOptionStyle);
259 parser.addOption(pathPrefixOption);
260
261 QCommandLineOption forceIncludeOption(QStringLiteral("f"));
262 forceIncludeOption.setDescription(QStringLiteral("Force #include <file> (overwrite default)."));
263 forceIncludeOption.setValueName(QStringLiteral("file"));
264 forceIncludeOption.setFlags(QCommandLineOption::ShortOptionStyle);
265 parser.addOption(forceIncludeOption);
266
267 QCommandLineOption prependIncludeOption(QStringLiteral("b"));
268 prependIncludeOption.setDescription(QStringLiteral("Prepend #include <file> (preserve default include)."));
269 prependIncludeOption.setValueName(QStringLiteral("file"));
270 prependIncludeOption.setFlags(QCommandLineOption::ShortOptionStyle);
271 parser.addOption(prependIncludeOption);
272
273 QCommandLineOption includeOption(QStringLiteral("include"));
274 includeOption.setDescription(QStringLiteral("Parse <file> as an #include before the main source(s)."));
275 includeOption.setValueName(QStringLiteral("file"));
276 parser.addOption(includeOption);
277
278 QCommandLineOption noNotesWarningsCompatOption(QStringLiteral("n"));
279 noNotesWarningsCompatOption.setDescription(QStringLiteral("Do not display notes (-nn) or warnings (-nw). Compatibility option."));
280 noNotesWarningsCompatOption.setValueName(QStringLiteral("which"));
281 noNotesWarningsCompatOption.setFlags(QCommandLineOption::ShortOptionStyle);
282 parser.addOption(noNotesWarningsCompatOption);
283
284 QCommandLineOption activeQtMode(QStringLiteral("active-qt"));
285 activeQtMode.setFlags(QCommandLineOption::HiddenFromHelp);
286 parser.addOption(activeQtMode);
287
288 QCommandLineOption noNotesOption(QStringLiteral("no-notes"));
289 noNotesOption.setDescription(QStringLiteral("Do not display notes."));
290 parser.addOption(noNotesOption);
291
292 QCommandLineOption noWarningsOption(QStringLiteral("no-warnings"));
293 noWarningsOption.setDescription(QStringLiteral("Do not display warnings (implies --no-notes)."));
294 parser.addOption(noWarningsOption);
295
296 QCommandLineOption ignoreConflictsOption(QStringLiteral("ignore-option-clashes"));
297 ignoreConflictsOption.setDescription(QStringLiteral("Ignore all options that conflict with compilers, like -pthread conflicting with moc's -p option."));
298 parser.addOption(ignoreConflictsOption);
299
300 QCommandLineOption jsonOption(QStringLiteral("output-json"));
301 jsonOption.setDescription(QStringLiteral("In addition to generating C++ code, create a machine-readable JSON file in a file that matches the output file and an extra .json extension."));
302 parser.addOption(jsonOption);
303
304 QCommandLineOption debugIncludesOption(QStringLiteral("debug-includes"));
305 debugIncludesOption.setDescription(QStringLiteral("Display debug messages of each considered include path."));
306 parser.addOption(debugIncludesOption);
307
308 QCommandLineOption collectOption(QStringLiteral("collect-json"));
309 collectOption.setDescription(QStringLiteral("Instead of processing C++ code, collect previously generated JSON output into a single file."));
310 parser.addOption(collectOption);
311
312 QCommandLineOption depFileOption(QStringLiteral("output-dep-file"));
313 depFileOption.setDescription(
314 QStringLiteral("Output a Make-style dep file for build system consumption."));
315 parser.addOption(depFileOption);
316
317 QCommandLineOption depFilePathOption(QStringLiteral("dep-file-path"));
318 depFilePathOption.setDescription(QStringLiteral("Path where to write the dep file."));
319 depFilePathOption.setValueName(QStringLiteral("file"));
320 parser.addOption(depFilePathOption);
321
322 QCommandLineOption depFileRuleNameOption(QStringLiteral("dep-file-rule-name"));
323 depFileRuleNameOption.setDescription(
324 QStringLiteral("The rule name (first line) of the dep file."));
325 depFileRuleNameOption.setValueName(QStringLiteral("rule name"));
326 parser.addOption(depFileRuleNameOption);
327
328 QCommandLineOption requireCompleTypesOption(QStringLiteral("require-complete-types"));
329 requireCompleTypesOption.setDescription(QStringLiteral("Require complete types for better performance"));
330 parser.addOption(requireCompleTypesOption);
331
332 parser.addPositionalArgument(QStringLiteral("[header-file]"),
333 QStringLiteral("Header file to read from, otherwise stdin."));
334 parser.addPositionalArgument(QStringLiteral("[@option-file]"),
335 QStringLiteral("Read additional options from option-file."));
336 parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
337 QStringLiteral("MOC generated json output"));
338
339 bool hasOptionFiles = false;
340 const QStringList arguments = argumentsFromCommandLineAndFile(app.arguments(), hasOptionFiles);
341 if (arguments.isEmpty())
342 return 1;
343
344 parser.process(arguments);
345
346 // used by ActiveQt's dumpcpp to suppress some functions
347 moc.activeQtMode = parser.isSet(activeQtMode);
348
349 const QStringList files = parser.positionalArguments();
350 output = parser.value(outputOption);
351 if (parser.isSet(collectOption))
352 return collectJson(files, output, hasOptionFiles);
353
354 if (files.size() > 1) {
355 error(qPrintable("Too many input files specified: '"_L1 + files.join("' '"_L1) + u'\''));
356 parser.showHelp(1);
357 } else if (!files.isEmpty()) {
358 filename = files.first();
359 }
360
361 const bool ignoreConflictingOptions = parser.isSet(ignoreConflictsOption);
362 pp.preprocessOnly = parser.isSet(preprocessOption);
363 pp.setDebugIncludes(parser.isSet(debugIncludesOption));
364 if (parser.isSet(noIncludeOption)) {
365 moc.noInclude = true;
366 autoInclude = false;
367 }
368 if (parser.isSet(requireCompleTypesOption))
369 moc.requireCompleteTypes = true;
370 if (!ignoreConflictingOptions) {
371 if (parser.isSet(forceIncludeOption)) {
372 moc.noInclude = false;
373 autoInclude = false;
374 const auto forceIncludes = parser.values(forceIncludeOption);
375 for (const QString &include : forceIncludes) {
376 moc.includeFiles.append(QFile::encodeName(include));
377 defaultInclude = false;
378 }
379 }
380 const auto prependIncludes = parser.values(prependIncludeOption);
381 for (const QString &include : prependIncludes)
382 moc.includeFiles.prepend(QFile::encodeName(include));
383 if (parser.isSet(pathPrefixOption))
384 moc.includePath = QFile::encodeName(parser.value(pathPrefixOption));
385 }
386
387 const auto includePaths = parser.values(includePathOption);
388 for (const QString &path : includePaths)
389 pp.includes += Preprocessor::IncludePath(QFile::encodeName(path));
390 QString compilerFlavor = parser.value(compilerFlavorOption);
391 if (compilerFlavor.isEmpty() || compilerFlavor == "unix"_L1) {
392 // traditional Unix compilers use both CPATH and CPLUS_INCLUDE_PATH
393 // $CPATH feeds to #include <...> and #include "...", whereas
394 // CPLUS_INCLUDE_PATH is equivalent to GCC's -isystem, so we parse later
395 const auto cpath = qgetenv("CPATH").split(QDir::listSeparator().toLatin1());
396 for (const QByteArray &p : cpath)
397 pp.includes += Preprocessor::IncludePath(p);
398 const auto cplus_include_path = qgetenv("CPLUS_INCLUDE_PATH").split(QDir::listSeparator().toLatin1());
399 for (const QByteArray &p : cplus_include_path)
400 pp.includes += Preprocessor::IncludePath(p);
401 } else if (compilerFlavor == "msvc"_L1) {
402 // MSVC uses one environment variable: INCLUDE
403 const auto include = qgetenv("INCLUDE").split(QDir::listSeparator().toLatin1());
404 for (const QByteArray &p : include)
405 pp.includes += Preprocessor::IncludePath(p);
406 } else {
407 error(qPrintable("Unknown compiler flavor '"_L1 + compilerFlavor +
408 "'; valid values are: msvc, unix."_L1));
409 parser.showHelp(1);
410 }
411
412 const auto macFrameworks = parser.values(macFrameworkOption);
413 for (const QString &path : macFrameworks) {
414 // minimalistic framework support for the mac
415 Preprocessor::IncludePath p(QFile::encodeName(path));
416 p.isFrameworkPath = true;
417 pp.includes += p;
418 }
419 const auto defines = parser.values(defineOption);
420 for (const QString &arg : defines) {
421 QByteArray name = arg.toLocal8Bit();
422 QByteArray value("1");
423 const qsizetype eq = name.indexOf('=');
424 if (eq >= 0) {
425 value = name.mid(eq + 1);
426 name = name.left(eq);
427 }
428 if (name.isEmpty()) {
429 error("Missing macro name");
430 parser.showHelp(1);
431 }
432 Macro macro;
433 macro.symbols = Preprocessor::tokenize(value, 1, Preprocessor::TokenizeDefine);
434 macro.symbols.removeLast(); // remove the EOF symbol
435 pp.macros.insert(name, macro);
436 }
437 const auto undefines = parser.values(undefineOption);
438 for (const QString &arg : undefines) {
439 QByteArray macro = arg.toLocal8Bit();
440 if (macro.isEmpty()) {
441 error("Missing macro name");
442 parser.showHelp(1);
443 }
444 pp.macros.remove(macro);
445 }
446 const QStringList noNotesCompatValues = parser.values(noNotesWarningsCompatOption);
447 if (parser.isSet(noNotesOption) || noNotesCompatValues.contains("n"_L1))
448 moc.displayNotes = false;
449 if (parser.isSet(noWarningsOption) || noNotesCompatValues.contains("w"_L1))
450 moc.displayWarnings = moc.displayNotes = false;
451
452 if (autoInclude) {
453 qsizetype spos = filename.lastIndexOf(QDir::separator());
454 qsizetype ppos = filename.lastIndexOf(u'.');
455 // spos >= -1 && ppos > spos => ppos >= 0
456 moc.noInclude = (ppos > spos && filename.at(ppos + 1).toLower() != u'h');
457 }
458 if (defaultInclude) {
459 if (moc.includePath.isEmpty()) {
460 if (filename.size()) {
461 if (output.size())
462 moc.includeFiles.append(combinePath(filename, output));
463 else
464 moc.includeFiles.append(QFile::encodeName(filename));
465 }
466 } else {
467 moc.includeFiles.append(combinePath(filename, filename));
468 }
469 }
470
471 if (filename.isEmpty()) {
472 filename = QStringLiteral("standard input");
473 if (!in.open(stdin, QIODevice::ReadOnly)) {
474 fprintf(stderr, "moc: cannot open standard input: %s\n", qPrintable(in.errorString()));
475 return 1;
476 }
477 } else {
478 in.setFileName(filename);
479 if (!in.open(QIODevice::ReadOnly)) {
480 fprintf(stderr, "moc: cannot open %s: %s\n", qPrintable(filename), qPrintable(in.errorString()));
481 return 1;
482 }
483 moc.filename = filename.toLocal8Bit();
484 }
485
486 const auto metadata = parser.values(metadataOption);
487 for (const QString &md : metadata) {
488 qsizetype split = md.indexOf(u'=');
489 QString key = md.left(split);
490 QString value = md.mid(split + 1);
491
492 if (split == -1 || key.isEmpty() || value.isEmpty()) {
493 error("missing key or value for option '-M'");
494 } else if (key.indexOf(u'.') != -1) {
495 // Don't allow keys with '.' for now, since we might need this
496 // format later for more advanced meta data API
497 error("A key cannot contain the letter '.' for option '-M'");
498 } else {
499 QJsonArray array = moc.metaArgs.value(key);
500 array.append(value);
501 moc.metaArgs.insert(key, array);
502 }
503 }
504
505 moc.currentFilenames.push(filename.toLocal8Bit());
506 moc.includes = pp.includes;
507
508 if (Q_UNLIKELY(parser.isSet(debugIncludesOption))) {
509 fprintf(stderr, "debug-includes: include search list:\n");
510
511 for (auto &includePath : pp.includes) {
512 fprintf(stderr, "debug-includes: '%s' framework: %d \n",
513 includePath.path.constData(),
514 includePath.isFrameworkPath);
515 }
516 fprintf(stderr, "debug-includes: end of search list.\n");
517 }
518
519 // 1. preprocess
520 const auto includeFiles = parser.values(includeOption);
521 QStringList validIncludesFiles;
522 for (const QString &includeName : includeFiles) {
523 QByteArray rawName = pp.resolveInclude(QFile::encodeName(includeName), moc.filename);
524 if (rawName.isEmpty()) {
525 fprintf(stderr, "Warning: Failed to resolve include \"%s\" for moc file %s\n",
526 includeName.toLocal8Bit().constData(),
527 moc.filename.isEmpty() ? "<standard input>" : moc.filename.constData());
528 } else {
529 QFile f(QFile::decodeName(rawName));
530 if (f.open(QIODevice::ReadOnly)) {
531 moc.symbols += Symbol(0, MOC_INCLUDE_BEGIN, rawName);
532 moc.symbols += pp.preprocessed(rawName, &f);
533 moc.symbols += Symbol(0, MOC_INCLUDE_END, rawName);
534 validIncludesFiles.append(includeName);
535 } else {
536 fprintf(stderr, "Warning: Cannot open %s included by moc file %s: %s\n",
537 rawName.constData(),
538 moc.filename.isEmpty() ? "<standard input>" : moc.filename.constData(),
539 f.errorString().toLocal8Bit().constData());
540 }
541 }
542 }
543 moc.symbols += pp.preprocessed(moc.filename, &in);
544
545 if (!pp.preprocessOnly) {
546 // 2. parse
547 moc.parse();
548 }
549
550 // 3. and output meta object code
551
552 File jsonOutput;
553
554 bool outputToFile = true;
555 if (output.size()) { // output file specified
556 out = openFileForWriting(output);
557 if (!out)
558 {
559 const auto fopen_errno = errno;
560 fprintf(stderr, "moc: Cannot create %s. Error: %s\n",
561 QFile::encodeName(output).constData(),
562 strerror(fopen_errno));
563 return 1;
564 }
565
566 if (parser.isSet(jsonOption)) {
567 const QString jsonOutputFileName = output + ".json"_L1;
568 jsonOutput = openFileForWriting(jsonOutputFileName);
569 if (!jsonOutput) {
570 const auto fopen_errno = errno;
571 fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n",
572 QFile::encodeName(jsonOutputFileName).constData(),
573 strerror(fopen_errno));
574 }
575 }
576 } else { // use stdout
577 out.reset(stdout);
578 outputToFile = false;
579 }
580
581 if (pp.preprocessOnly) {
582 fprintf(out.get(), "%s\n", composePreprocessorOutput(moc.symbols).constData());
583 } else if (moc.classList.isEmpty()) {
584 moc.note("No relevant classes found. No output generated.");
585 if (jsonOutput) {
586 const QJsonDocument jsonDoc(QJsonObject {
587 { "outputRevision"_L1, mocOutputRevision },
588 { "inputFile"_L1, QLatin1StringView(moc.strippedFileName()) }
589 });
590 fputs(jsonDoc.toJson().constData(), jsonOutput.get());
591 }
592 } else {
593 moc.generate(out.get(), jsonOutput.get());
594 }
595
596 out.reset();
597
598 if (parser.isSet(depFileOption)) {
599 // 4. write a Make-style dependency file (can also be consumed by Ninja).
600 QString depOutputFileName;
601 QString depRuleName = output;
602
603 if (parser.isSet(depFileRuleNameOption))
604 depRuleName = parser.value(depFileRuleNameOption);
605
606 if (parser.isSet(depFilePathOption)) {
607 depOutputFileName = parser.value(depFilePathOption);
608 } else if (outputToFile) {
609 depOutputFileName = output + ".d"_L1;
610 } else {
611 fprintf(stderr, "moc: Writing to stdout, but no depfile path specified.\n");
612 }
613
614 File depFileHandle = openFileForWriting(depOutputFileName);
615 if (!depFileHandle) {
616 const auto fopen_errno = errno;
617 fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n",
618 QFile::encodeName(depOutputFileName).constData(),
619 strerror(fopen_errno));
620 }
621
622 if (depFileHandle) {
623 // First line is the path to the generated file.
624 fprintf(depFileHandle.get(), "%s: ",
625 escapeAndEncodeDependencyPath(depRuleName).constData());
626
627 QByteArrayList dependencies;
628
629 // If there's an input file, it's the first dependency.
630 if (!filename.isEmpty()) {
631 dependencies.append(escapeAndEncodeDependencyPath(filename).constData());
632 }
633
634 // Additional passed-in includes are dependencies (like moc_predefs.h).
635 for (const QString &includeName : validIncludesFiles) {
636 dependencies.append(escapeAndEncodeDependencyPath(includeName).constData());
637 }
638
639 // Plugin metadata json files discovered via Q_PLUGIN_METADATA macros are also
640 // dependencies.
641 for (const QString &pluginMetadataFile : moc.parsedPluginMetadataFiles) {
642 dependencies.append(escapeAndEncodeDependencyPath(pluginMetadataFile).constData());
643 }
644
645 // All pre-processed includes are dependnecies.
646 // Sort the entries for easier human consumption.
647 auto includeList = pp.preprocessedIncludes.values();
648 std::sort(includeList.begin(), includeList.end());
649
650 for (QByteArray &includeName : includeList) {
651 dependencies.append(escapeDependencyPath(includeName));
652 }
653
654 // Join dependencies, output them, and output a final new line.
655 const auto dependenciesJoined = dependencies.join(QByteArrayLiteral(" \\\n "));
656 fprintf(depFileHandle.get(), "%s\n", dependenciesJoined.constData());
657 }
658 }
659
660 return 0;
661}
662
664
665int main(int _argc, char **_argv)
666{
667 return QT_PREPEND_NAMESPACE(runMoc)(_argc, _argv);
668}
int main(int argc, char *argv[])
[2]
Definition buffer.cpp:77
Definition moc.h:220
void parse()
Definition moc.cpp:669
bool requireCompleteTypes
Definition moc.h:232
void generate(FILE *out, FILE *jsonOutput)
Definition moc.cpp:1179
bool noInclude
Definition moc.h:230
static bool preprocessOnly
The QCommandLineOption class defines a possible command-line option. \inmodule QtCore.
The QCommandLineParser class provides a means for handling the command line options.
Combined button and popup list for selecting options.
#define qPrintable(string)
Definition qstring.h:1666
static QByteArray combinePath(const QString &infile, const QString &outfile)
Definition main.cpp:40
static bool hasNext(const Symbols &symbols, int i)
Definition main.cpp:78
static const Symbol & next(const Symbols &symbols, int &i)
Definition main.cpp:81
int runMoc(int argc, char **argv)
Definition main.cpp:170
static auto openFileForWriting(const QString &name)
Definition main.cpp:62
void error(const char *msg="Invalid argument")
Definition main.cpp:56
static QStringList argumentsFromCommandLineAndFile(const QStringList &arguments, bool &hasOptionFiles)
Definition main.cpp:138
QByteArray composePreprocessorOutput(const Symbols &symbols)
Definition main.cpp:85
Simple structure used by the Doc and DocParser classes.
bool isVariadic
bool isFunction
Token token
Definition symbols.h:58
int lineNum
Definition symbols.h:57
QList< Symbol > Symbols
Definition symbols.h:72