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