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) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5#include "codemarker.h"
6#include "codeparser.h"
7#include "config.h"
9#include "doc.h"
11#include "htmlgenerator.h"
12#include "location.h"
13#include "puredocparser.h"
14#include "qdocdatabase.h"
15#include "qmlcodemarker.h"
16#include "qmlcodeparser.h"
18#include "utilities.h"
19#include "tokenizer.h"
20#include "tree.h"
22
23#include "filesystem/fileresolver.h"
24#include "boundaries/filesystem/directorypath.h"
25
26#include <QtCore/qcompilerdetection.h>
27#include <QtCore/qdatetime.h>
28#include <QtCore/qdebug.h>
29#include <QtCore/qglobal.h>
30#include <QtCore/qhashfunctions.h>
31
32#include <set>
33
34#ifndef QT_BOOTSTRAPPED
35# include <QtCore/qcoreapplication.h>
36#endif
37
38#include <algorithm>
39#include <cstdlib>
40
42
43using namespace Qt::StringLiterals;
44
45bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2)
46{
47 return fi1.lastModified() < fi2.lastModified();
48}
49
50/*!
51 \internal
52 Inspects each file path in \a sources. File paths with a known
53 source file type are parsed to extract user-provided
54 documentation and information about source code level elements.
55
56 \note Unknown source file types are silently ignored.
57
58 The validity or availability of the file paths may or may not cause QDoc
59 to generate warnings; this depends on the implementation of
60 parseSourceFile() for the relevant parser.
61
62 \sa CodeParser::parserForSourceFile, CodeParser::sourceFileNameFilter
63*/
64static void parseSourceFiles(
65 std::vector<QString>&& sources,
66 SourceFileParser& source_file_parser,
67 CppCodeParser& cpp_code_parser
68) {
69 ParserErrorHandler error_handler{};
70 std::stable_sort(sources.begin(), sources.end());
71
72 sources.erase (
73 std::unique(sources.begin(), sources.end()),
74 sources.end()
75 );
76
77 auto qml_sources =
78 std::stable_partition(sources.begin(), sources.end(), [](const QString& source){
79 return CodeParser::parserForSourceFile(source) == CodeParser::parserForLanguage("QML");
80 });
81
82
83 std::for_each(qml_sources, sources.end(),
84 [&source_file_parser, &cpp_code_parser, &error_handler](const QString& source){
85 qCDebug(lcQdoc, "Parsing %s", qPrintable(source));
86
87 auto [untied_documentation, tied_documentation] = source_file_parser(tag_source_file(source));
88 std::vector<FnMatchError> errors{};
89
90 for (auto untied : untied_documentation) {
91 auto result = cpp_code_parser.processTopicArgs(untied);
92 tied_documentation.insert(tied_documentation.end(), result.first.begin(), result.first.end());
93 };
94
95 cpp_code_parser.processMetaCommands(tied_documentation);
96
97 // Process errors that occurred during parsing
98 for (const auto &e : errors)
99 error_handler(e);
100 });
101
102 std::for_each(sources.begin(), qml_sources, [&cpp_code_parser](const QString& source){
103 auto *codeParser = CodeParser::parserForSourceFile(source);
104 if (!codeParser) return;
105
106 qCDebug(lcQdoc, "Parsing %s", qPrintable(source));
107 codeParser->parseSourceFile(Config::instance().location(), source, cpp_code_parser);
108 });
109
110}
111
112/*!
113 Read some XML indexes containing definitions from other
114 documentation sets. \a config contains a variable that
115 lists directories where index files can be found. It also
116 contains the \c depends variable, which lists the modules
117 that the current module depends on. \a formats contains
118 a list of output formats; each format may have a different
119 output subdirectory where index files are located.
120*/
121static void loadIndexFiles(const QSet<QString> &formats)
122{
123 Config &config = Config::instance();
125 QStringList indexFiles;
126 const QStringList configIndexes{config.get(CONFIG_INDEXES).asStringList()};
127 bool warn = !config.get(CONFIG_NOLINKERRORS).asBool();
128
129 for (const auto &index : configIndexes) {
130 QFileInfo fi(index);
131 if (fi.exists() && fi.isFile())
132 indexFiles << index;
133 else if (warn)
134 Location().warning(QString("Index file not found: %1").arg(index));
135 }
136
137 config.dependModules() += config.get(CONFIG_DEPENDS).asStringList();
138 config.dependModules().removeDuplicates();
139 bool useNoSubDirs = false;
140 QSet<QString> subDirs;
141
142 // Add format-specific output subdirectories to the set of
143 // subdirectories where we look for index files
144 for (const auto &format : formats) {
145 if (config.get(format + Config::dot + "nosubdirs").asBool()) {
146 useNoSubDirs = true;
147 const auto singleOutputSubdir{QDir(config.getOutputDir(format)).dirName()};
148 if (!singleOutputSubdir.isEmpty())
149 subDirs << singleOutputSubdir;
150 }
151 }
152
153 if (!config.dependModules().empty()) {
154 if (!config.indexDirs().empty()) {
155 for (auto &dir : config.indexDirs()) {
156 if (dir.startsWith("..")) {
157 const QString prefix(QDir(config.currentDir())
158 .relativeFilePath(config.previousCurrentDir()));
159 if (!prefix.isEmpty())
160 dir.prepend(prefix + QLatin1Char('/'));
161 }
162 }
163 /*
164 Load all dependencies:
165 Either add all subdirectories of the indexdirs as dependModules,
166 when an asterisk is used in the 'depends' list, or
167 when <format>.nosubdirs is set, we need to look for all .index files
168 in the output subdirectory instead.
169 */
170 bool asteriskUsed = false;
171 if (config.dependModules().contains("*")) {
172 config.dependModules().removeOne("*");
173 asteriskUsed = true;
174 if (useNoSubDirs) {
175 std::for_each(formats.begin(), formats.end(), [&](const QString &format) {
176 QDir scanDir(config.getOutputDir(format));
177 QStringList foundModules =
178 scanDir.entryList(QStringList("*.index"), QDir::Files);
179 std::transform(
180 foundModules.begin(), foundModules.end(), foundModules.begin(),
181 [](const QString &index) { return QFileInfo(index).baseName(); });
182 config.dependModules() << foundModules;
183 });
184 } else {
185 for (const auto &indexDir : config.indexDirs()) {
186 QDir scanDir = QDir(indexDir);
187 scanDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
188 QFileInfoList dirList = scanDir.entryInfoList();
189 for (const auto &dir : dirList)
190 config.dependModules().append(dir.fileName());
191 }
192 }
193 // Remove self-dependencies and possible duplicates
194 QString project{config.get(CONFIG_PROJECT).asString()};
195 config.dependModules().removeAll(project.toLower());
196 config.dependModules().removeDuplicates();
197 qCCritical(lcQdoc) << "Configuration file for"
198 << project << "has depends = *; loading all"
199 << config.dependModules().size()
200 << "index files found";
201 }
202 for (const auto &module : config.dependModules()) {
203 QList<QFileInfo> foundIndices;
204 // Always look in module-specific subdir, even with *.nosubdirs config
205 bool useModuleSubDir = !subDirs.contains(module);
206 subDirs << module;
207
208 for (const auto &dir : config.indexDirs()) {
209 for (const auto &subDir : std::as_const(subDirs)) {
210 QString fileToLookFor = dir + QLatin1Char('/') + subDir + QLatin1Char('/')
211 + module + ".index";
212 if (QFile::exists(fileToLookFor)) {
213 QFileInfo tempFileInfo(fileToLookFor);
214 if (!foundIndices.contains(tempFileInfo))
215 foundIndices.append(tempFileInfo);
216 }
217 }
218 }
219 // Clear the temporary module-specific subdir
220 if (useModuleSubDir)
221 subDirs.remove(module);
222 std::sort(foundIndices.begin(), foundIndices.end(), creationTimeBefore);
223 QString indexToAdd;
224 if (foundIndices.size() > 1) {
225 /*
226 QDoc should always use the last entry in the multimap when there are
227 multiple index files for a module, since the last modified file has the
228 highest UNIX timestamp.
229 */
230 QStringList indexPaths;
231 indexPaths.reserve(foundIndices.size());
232 for (const auto &found : std::as_const(foundIndices))
233 indexPaths << found.absoluteFilePath();
234 if (warn) {
235 Location().warning(
236 QString("Multiple index files found for dependency \"%1\":\n%2")
237 .arg(module, indexPaths.join('\n')));
238 Location().warning(
239 QString("Using %1 as index file for dependency \"%2\"")
240 .arg(foundIndices[foundIndices.size() - 1].absoluteFilePath(),
241 module));
242 }
243 indexToAdd = foundIndices[foundIndices.size() - 1].absoluteFilePath();
244 } else if (foundIndices.size() == 1) {
245 indexToAdd = foundIndices[0].absoluteFilePath();
246 }
247 if (!indexToAdd.isEmpty()) {
248 if (!indexFiles.contains(indexToAdd))
249 indexFiles << indexToAdd;
250 } else if (!asteriskUsed && warn) {
251 Location().warning(
252 QString(R"("%1" Cannot locate index file for dependency "%2")")
253 .arg(config.get(CONFIG_PROJECT).asString(), module));
254 }
255 }
256 } else if (warn) {
257 Location().warning(
258 QLatin1String("Dependent modules specified, but no index directories were set. "
259 "There will probably be errors for missing links."));
260 }
261 }
262 qdb->readIndexes(indexFiles);
263}
264
265/*!
266 \internal
267 Prints to stderr the name of the project that QDoc is running for,
268 in which mode and which phase.
269
270 If QDoc is not running in debug mode or --log-progress command line
271 option is not set, do nothing.
272 */
273void logStartEndMessage(const QLatin1String &startStop, Config &config)
274{
275 if (!config.get(CONFIG_LOGPROGRESS).asBool())
276 return;
277
278 const QString runName = " qdoc for "
279 + config.get(CONFIG_PROJECT).asString()
280 + QLatin1String(" in ")
281 + QLatin1String(config.singleExec() ? "single" : "dual")
282 + QLatin1String(" process mode: ")
283 + QLatin1String(config.preparing() ? "prepare" : "generate")
284 + QLatin1String(" phase.");
285
286 const QString msg = startStop + runName;
287 qCInfo(lcQdoc) << msg.toUtf8().data();
288}
289
290/*!
291 Processes the qdoc config file \a fileName. This is the controller for all
292 of QDoc. The \a config instance represents the configuration data for QDoc.
293 All other classes are initialized with the same config.
294 */
295static void processQdocconfFile(const QString &fileName)
296{
297 Config &config = Config::instance();
298 config.setPreviousCurrentDir(QDir::currentPath());
299
300 /*
301 With the default configuration values in place, load
302 the qdoc configuration file. Note that the configuration
303 file may include other configuration files.
304
305 The Location class keeps track of the current location
306 in the file being processed, mainly for error reporting
307 purposes.
308 */
310 config.load(fileName);
311 QString project{config.get(CONFIG_PROJECT).asString()};
312 if (project.isEmpty()) {
313 qCCritical(lcQdoc) << QLatin1String("qdoc can't run; no project set in qdocconf file");
314 exit(1);
315 }
317
318 config.setCurrentDir(QFileInfo(fileName).path());
319 if (!config.currentDir().isEmpty())
320 QDir::setCurrent(config.currentDir());
321
322 logStartEndMessage(QLatin1String("Start"), config);
323
324 if (config.getDebug()) {
325 Utilities::startDebugging(QString("command line"));
326 qCDebug(lcQdoc).noquote() << "Arguments:" << QCoreApplication::arguments();
327 }
328
329 // <<TODO: [cleanup-temporary-kludges]
330 // The underlying validation should be performed at the
331 // configuration level during parsing.
332 // This cannot be done straightforwardly with how the Config class
333 // is implemented.
334 // When the Config class will be deprived of logic and
335 // restructured, the compiler will notify us of this kludge, but
336 // remember to reevaluate the code itself considering the new
337 // data-flow and the possibility for optimizations as this is not
338 // done for temporary code. Indeed some of the code is visibly wasteful.
339 // Similarly, ensure that the loose definition that we use here is
340 // not preserved.
341
342 QStringList search_directories{config.getCanonicalPathList(CONFIG_EXAMPLEDIRS)};
343 QStringList image_search_directories{config.getCanonicalPathList(CONFIG_IMAGEDIRS)};
344
345 const auto& [excludedDirs, excludedFiles] = config.getExcludedPaths();
346
347 qCDebug(lcQdoc, "Adding doc/image dirs found in exampledirs to imagedirs");
348 QSet<QString> exampleImageDirs;
349 QStringList exampleImageList = config.getExampleImageFiles(excludedDirs, excludedFiles);
350 for (const auto &image : exampleImageList) {
351 if (image.contains("doc/images")) {
352 QString t = image.left(image.lastIndexOf("doc/images") + 10);
353 if (!exampleImageDirs.contains(t))
354 exampleImageDirs.insert(t);
355 }
356 }
357
358 // REMARK: The previous system discerned between search directories based on the kind of file that was searched for.
359 // For example, an image search was bounded to some directories
360 // that may or may not be the same as the ones where examples are
361 // searched for.
362 // The current Qt documentation does not use this feature. That
363 // is, the output of QDoc when a unified search list is used is
364 // the same as the output for that of separated lists.
365 // For this reason, we currently simplify the process, albeit this
366 // may at some point change, by joining the various lists into a
367 // single search list and a unified interface.
368 // Do note that the configuration still allows for those
369 // parameters to be user defined in a split-way as this will not
370 // be able to be changed until Config itself is looked upon.
371 // Hence, we join the various directory sources into one list for the time being.
372 // Do note that this means that the amount of searched directories for a file is now increased.
373 // This shouldn't matter as the amount of directories is expected
374 // to be generally small and the search routine complexity is
375 // linear in the amount of directories.
376 // There are some complications that may arise in very specific
377 // cases by this choice (some of which where there before under
378 // possibly different circumstances), making some files
379 // unreachable.
380 // See the remarks in FileResolver for more infomration.
381 std::copy(image_search_directories.begin(), image_search_directories.end(), std::back_inserter(search_directories));
382 std::copy(exampleImageDirs.begin(), exampleImageDirs.end(), std::back_inserter(search_directories));
383
384 std::vector<DirectoryPath> validated_search_directories{};
385 for (const QString& path : search_directories) {
386 auto maybe_validated_path{DirectoryPath::refine(path)};
387 if (!maybe_validated_path)
388 // TODO: [uncentralized-admonition]
389 qCDebug(lcQdoc).noquote() << u"%1 is not a valid path, it will be ignored when resolving a file"_s.arg(path);
390 else validated_search_directories.push_back(*maybe_validated_path);
391 }
392
393 // TODO>>
394
395 FileResolver file_resolver{std::move(validated_search_directories)};
396
397 // REMARK: The constructor for generators doesn't actually perform
398 // initialization of their content.
399 // Indeed, Generators use the general antipattern of the static
400 // initialize-terminate non-scoped mutable state that we see in
401 // many parts of QDoc.
402 // In their constructor, Generators mainly register themselves into a static list.
403 // Previously, this was done at the start of main.
404 // To be able to pass a correct FileResolver or other systems, we
405 // need to construct them after the configuration has been read
406 // and has been destructured.
407 // For this reason, their construction was moved here.
408 // This function may be called more than once for some of QDoc's
409 // call, albeit this should not actually happen in Qt's
410 // documentation.
411 // Then, constructing the generators here might provide for some
412 // unexpected behavior as new generators are appended to the list
413 // and never used, considering that the list is searched in a
414 // linearly fashion and each generator of some type T, in the
415 // current codebase, will always be found if another instance of
416 // that same type would have been found.
417 // Furthermore, those instances would be destroyed by then, such
418 // that accessing them would be erroneous.
419 // To avoid this, the static list was made to be cleared in
420 // Generator::terminate, which, in theory, will be called before
421 // the generators will be constructed again.
422 // We could have used the initialize method for this, but this
423 // would force us into a limited and more complex semantic, see an
424 // example of this in DocParser, and would restrain us further to
425 // the initialize-terminate idiom which is expect to be purged in
426 // the future.
427 HtmlGenerator htmlGenerator{file_resolver};
428 WebXMLGenerator webXMLGenerator{file_resolver};
429 DocBookGenerator docBookGenerator{file_resolver};
430
432
433 /*
434 Initialize the qdoc database, where all the parsed source files
435 will be stored. The database includes a tree of nodes, which gets
436 built as the source files are parsed. The documentation output is
437 generated by traversing that tree.
438
439 Note: qdocDB() allocates a new instance only if no instance exists.
440 So it is safe to call qdocDB() any time.
441 */
443 qdb->setVersion(config.get(CONFIG_VERSION).asString());
444 /*
445 By default, the only output format is HTML.
446 */
447 const QSet<QString> outputFormats = config.getOutputFormats();
448
450 if (!config.singleExec()) {
451 if (!config.preparing()) {
452 qCDebug(lcQdoc, " loading index files");
453 loadIndexFiles(outputFormats);
454 qCDebug(lcQdoc, " done loading index files");
455 }
456 qdb->newPrimaryTree(project);
457 } else if (config.preparing())
458 qdb->newPrimaryTree(project);
459 else
460 qdb->setPrimaryTree(project);
461
462 // Retrieve the dependencies if loadIndexFiles() was not called
463 if (config.dependModules().isEmpty()) {
464 config.dependModules() = config.get(CONFIG_DEPENDS).asStringList();
465 config.dependModules().removeDuplicates();
466 }
467 qdb->setSearchOrder(config.dependModules());
468
469 // Store the title of the index (landing) page
471 if (root) {
472 QString title{config.get(CONFIG_NAVIGATION + Config::dot + CONFIG_LANDINGPAGE).asString()};
473 root->tree()->setIndexTitle(
474 config.get(CONFIG_NAVIGATION + Config::dot + CONFIG_LANDINGTITLE).asString(title));
475 }
476
477
478 std::vector<QByteArray> include_paths{};
479 {
480 auto args = config.getCanonicalPathList(CONFIG_INCLUDEPATHS,
482#ifdef Q_OS_MACOS
483 args.append(Utilities::getInternalIncludePaths(QStringLiteral("clang++")));
484#elif defined(Q_OS_LINUX)
485 args.append(Utilities::getInternalIncludePaths(QStringLiteral("g++")));
486#endif
487
488 for (const auto &path : std::as_const(args)) {
489 if (!path.isEmpty())
490 include_paths.push_back(path.toUtf8());
491 }
492
493 include_paths.erase(std::unique(include_paths.begin(), include_paths.end()),
494 include_paths.end());
495 }
496
497 QList<QByteArray> clang_defines{};
498 {
499 const QStringList config_defines{config.get(CONFIG_DEFINES).asStringList()};
500 for (const QString &def : config_defines) {
501 if (!def.contains(QChar('*'))) {
502 QByteArray tmp("-D");
503 tmp.append(def.toUtf8());
504 clang_defines.append(tmp.constData());
505 }
506 }
507 }
508
509 std::optional<PCHFile> pch = std::nullopt;
510 if (config.dualExec() || config.preparing()) {
511 const QString moduleHeader = config.get(CONFIG_MODULEHEADER).asString();
512 pch = buildPCH(
513 QDocDatabase::qdocDB(),
514 moduleHeader.isNull() ? project : moduleHeader,
515 Config::instance().getHeaderFiles(),
516 include_paths,
517 clang_defines
518 );
519 }
520
521 ClangCodeParser clangParser(QDocDatabase::qdocDB(), Config::instance(), include_paths, clang_defines, pch);
522 PureDocParser docParser{config.location()};
523
524 /*
525 Initialize all the classes and data structures with the
526 qdoc configuration. This is safe to do for each qdocconf
527 file processed, because all the data structures created
528 are either cleared after they have been used, or they
529 are cleared in the terminate() functions below.
530 */
535 Doc::initialize(file_resolver);
536
537 if (config.dualExec() || config.preparing()) {
538 QStringList sourceList;
539
540 qCDebug(lcQdoc, "Reading sourcedirs");
541
543 sourceList += config.getAllFiles(CONFIG_HEADERS, CONFIG_HEADERDIRS, excludedDirs,
544 excludedFiles);
545 }
546 sourceList +=
547 config.getAllFiles(CONFIG_SOURCES, CONFIG_SOURCEDIRS, excludedDirs, excludedFiles);
548
549 std::vector<QString> sources{};
550 for (const auto &source : sourceList) {
551 if (source.contains(QLatin1String("doc/snippets")))
552 continue;
553 sources.emplace_back(source);
554 }
555 /*
556 Find all the qdoc files in the example dirs, and add
557 them to the source files to be parsed.
558 */
559 qCDebug(lcQdoc, "Reading exampledirs");
560 QStringList exampleQdocList = config.getExampleQdocFiles(excludedDirs, excludedFiles);
561 for (const auto &example : exampleQdocList) {
562 sources.emplace_back(example);
563 }
564
565 /*
566 Parse each source text file in the set using the appropriate parser and
567 add it to the big tree.
568 */
569 if (config.get(CONFIG_LOGPROGRESS).asBool())
570 qCInfo(lcQdoc) << "Parse source files for" << project;
571
572
573 auto headers = config.getHeaderFiles();
574 CppCodeParser cpp_code_parser(FnCommandParser(qdb, headers, clang_defines, pch));
575
576 SourceFileParser source_file_parser{clangParser, docParser};
577 parseSourceFiles(std::move(sources), source_file_parser, cpp_code_parser);
578
579 if (config.get(CONFIG_LOGPROGRESS).asBool())
580 qCInfo(lcQdoc) << "Source files parsed for" << project;
581 }
582 /*
583 Now the primary tree has been built from all the header and
584 source files. Resolve all the class names, function names,
585 targets, URLs, links, and other stuff that needs resolving.
586 */
587 qCDebug(lcQdoc, "Resolving stuff prior to generating docs");
589
590 /*
591 The primary tree is built and all the stuff that needed
592 resolving has been resolved. Now traverse the tree and
593 generate the documentation output. More than one output
594 format can be requested. The tree is traversed for each
595 one.
596 */
597 qCDebug(lcQdoc, "Generating docs");
598 for (const auto &format : outputFormats) {
599 auto *generator = Generator::generatorForFormat(format);
600 if (generator) {
601 generator->initializeFormat();
602 generator->generateDocs();
603 } else {
604 config.get(CONFIG_OUTPUTFORMATS)
605 .location()
606 .fatal(QStringLiteral("QDoc: Unknown output format '%1'").arg(format));
607 }
608 }
609
610 qCDebug(lcQdoc, "Terminating qdoc classes");
612 Utilities::stopDebugging(project);
613
614 logStartEndMessage(QLatin1String("End"), config);
615 QDocDatabase::qdocDB()->setVersion(QString());
622 QDir::setCurrent(config.previousCurrentDir());
623
624 qCDebug(lcQdoc, "qdoc classes terminated");
625}
626
627/*!
628 \internal
629 For each file in \a qdocFiles, first clear the configured module
630 dependencies and then pass the file to processQdocconfFile().
631
632 \sa processQdocconfFile(), singleExecutionMode(), dualExecutionMode()
633*/
634static void clearModuleDependenciesAndProcessQdocconfFile(const QStringList &qdocFiles)
635{
636 for (const auto &file : std::as_const(qdocFiles)) {
637 Config::instance().dependModules().clear();
638 processQdocconfFile(file);
639 }
640}
641
642/*!
643 \internal
644
645 A single QDoc process for prepare and generate phases.
646 The purpose is to first generate all index files for all documentation
647 projects that combined make out the documentation set being generated.
648 This allows QDoc to link to all content contained in all projects, e.g.
649 user-defined types or overview documentation, regardless of the project
650 that content belongs to when generating the final output.
651*/
653{
654 const QStringList qdocFiles = Config::loadMaster(Config::instance().qdocFiles().at(0));
655
656 Config::instance().setQDocPass(Config::Prepare);
657 clearModuleDependenciesAndProcessQdocconfFile(qdocFiles);
658
659 Config::instance().setQDocPass(Config::Generate);
661 clearModuleDependenciesAndProcessQdocconfFile(qdocFiles);
662}
663
664/*!
665 \internal
666
667 Process each .qdocconf-file passed as command line argument(s).
668*/
669static void dualExecutionMode()
670{
671 const QStringList qdocFiles = Config::instance().qdocFiles();
672 clearModuleDependenciesAndProcessQdocconfFile(qdocFiles);
673}
674
676
677int main(int argc, char **argv)
678{
679 QT_USE_NAMESPACE
680
681 // Initialize Qt:
682#ifndef QT_BOOTSTRAPPED
683 // use deterministic hash seed
684 QHashSeed::setDeterministicGlobalSeed();
685#endif
686 QCoreApplication app(argc, argv);
687 app.setApplicationVersion(QLatin1String(QT_VERSION_STR));
688
689 // Instantiate various singletons (used via static methods):
690 /*
691 Create code parsers for the languages to be parsed,
692 and create a tree for C++.
693 */
694 QmlCodeParser qmlParser;
695
696 /*
697 Create code markers for plain text, C++,
698 and QML.
699
700 The plain CodeMarker must be instantiated first because it is used as
701 fallback when the other markers cannot be used.
702
703 Each marker instance is prepended to the CodeMarker::markers list by the
704 base class constructor.
705 */
706 CodeMarker fallbackMarker;
707 CppCodeMarker cppMarker;
708 QmlCodeMarker qmlMarker;
709
710 Config::instance().init("QDoc", app.arguments());
711
712 if (Config::instance().qdocFiles().isEmpty())
713 Config::instance().showHelp();
714
715 if (Config::instance().singleExec()) {
717 } else {
719 }
720
721 // Tidy everything away:
725}
int main(int argc, char *argv[])
[2]
Definition buffer.cpp:77
static void initialize()
All the code markers in the static list are initialized here, after the qdoc configuration file has b...
static void terminate()
All the code markers in the static list are terminated here.
static CodeParser * parserForSourceFile(const QString &filePath)
static void initialize()
All the code parsers in the static list are initialized here, after the qdoc configuration variables ...
static void terminate()
All the code parsers in the static list are terminated here.
bool asBool() const
Returns this config variable as a boolean.
Definition config.cpp:264
The Config class contains the configuration variables for controlling how qdoc produces documentation...
Definition config.h:84
static const QString dot
Definition config.h:162
bool singleExec() const
Definition config.h:404
@ IncludePaths
Definition config.h:104
const Location & location() const
Definition config.h:121
const ExcludedPaths & getExcludedPaths()
Definition config.cpp:1406
bool dualExec() const
Definition config.h:409
bool preparing() const
Definition config.h:181
bool getDebug() const
Definition config.h:108
CppCodeParser(FnCommandParser &&parser)
void processMetaCommands(const Doc &doc, Node *node)
The topic command has been processed, and now doc and node are passed to this function to get the met...
DocBookGenerator(FileResolver &file_resolver)
Definition doc.h:31
static void initialize(FileResolver &file_resolver)
Definition doc.cpp:308
static void terminate()
All the heap allocated variables are deleted.
Definition doc.cpp:361
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
static void initialize()
static void terminate()
HtmlGenerator(FileResolver &file_resolver)
The Location class provides a way to mark a location in a file.
Definition location.h:15
static int exitCode()
Returns the error code QDoc should exit with; EXIT_SUCCESS or the number of documentation warnings if...
Definition location.cpp:244
static void initialize()
Gets several parameters from the config, including tab size, program name, and a regular expression t...
Definition location.cpp:297
Location()
Constructs an empty location.
Definition location.cpp:40
static void terminate()
Apparently, all this does is delete the regular expression used for intercepting certain error messag...
Definition location.cpp:324
This class represents a C++ namespace.
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
PureDocParser(const Location &location)
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static void destroyQdocDB()
Destroys the singleton.
static QDocDatabase * qdocDB()
Creates the singleton.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
void processForest()
This function calls a set of functions for each tree in the forest that has not already been analyzed...
void clearSearchOrder()
void resolveStuff()
Performs several housekeeping tasks prior to generating the documentation.
static void terminate()
Clear the static maps so that subsequent runs don't try to use contents from a previous run.
SourceFileParser(ClangCodeParser &clang_parser, PureDocParser &pure_parser)
static void terminate()
The heap allocated variables are freed here.
static void initialize()
WebXMLGenerator(FileResolver &file_resolver)
#define CONFIG_SOURCES
Definition config.h:384
#define CONFIG_VERSION
Definition config.h:394
#define CONFIG_EXAMPLEDIRS
Definition config.h:337
#define CONFIG_INDEXES
Definition config.h:358
#define CONFIG_DEFINES
Definition config.h:331
#define CONFIG_DEPENDS
Definition config.h:332
#define CONFIG_NOLINKERRORS
Definition config.h:369
#define CONFIG_LOGPROGRESS
Definition config.h:363
#define CONFIG_IMAGEDIRS
Definition config.h:355
#define CONFIG_PROJECT
Definition config.h:375
#define CONFIG_SOURCEDIRS
Definition config.h:382
#define CONFIG_HEADERS
Definition config.h:346
#define CONFIG_DOCUMENTATIONINHEADERS
Definition config.h:335
#define CONFIG_NAVIGATION
Definition config.h:368
#define CONFIG_LANDINGPAGE
Definition config.h:359
#define CONFIG_OUTPUTFORMATS
Definition config.h:371
#define CONFIG_LANDINGTITLE
Definition config.h:360
#define CONFIG_MODULEHEADER
Definition config.h:366
#define CONFIG_HEADERDIRS
Definition config.h:345
#define CONFIG_INCLUDEPATHS
Definition config.h:356
Combined button and popup list for selecting options.
This namespace holds QDoc-internal utility methods.
Definition utilities.h:15
bool debugging()
Definition utilities.cpp:38
static void parseSourceFiles(std::vector< QString > &&sources, SourceFileParser &source_file_parser, CppCodeParser &cpp_code_parser)
Definition main.cpp:64
static void singleExecutionMode()
Definition main.cpp:652
void logStartEndMessage(const QLatin1String &startStop, Config &config)
Definition main.cpp:273
static void processQdocconfFile(const QString &fileName)
Processes the qdoc config file fileName.
Definition main.cpp:295
static void clearModuleDependenciesAndProcessQdocconfFile(const QStringList &qdocFiles)
Definition main.cpp:634
static void dualExecutionMode()
Definition main.cpp:669
bool creationTimeBefore(const QFileInfo &fi1, const QFileInfo &fi2)
Definition main.cpp:45
static void loadIndexFiles(const QSet< QString > &formats)
Read some XML indexes containing definitions from other documentation sets.
Definition main.cpp:121
Processes parser errors and outputs warnings for them.
Definition parsererror.h:20