1// Copyright (C) 2022 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 <QCoreApplication>
5#include <QCommandLineParser>
6#include <QDir>
7#include <QFile>
8#include <QScopedPointer>
9
10#include <cstdlib>
11
12#include <QtQmlTypeRegistrar/private/qqmltyperegistrar_p.h>
13
14using namespace Qt::Literals;
15
16int main(int argc, char **argv)
17{
18 // Produce reliably the same output for the same input by disabling QHash's random seeding.
19 QHashSeed::setDeterministicGlobalSeed();
20
21 QCoreApplication app(argc, argv);
22 QCoreApplication::setApplicationName(QStringLiteral("qmltyperegistrar"));
23 QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
24
25 QCommandLineParser parser;
26 parser.addHelpOption();
27 parser.addVersionOption();
28
29 QCommandLineOption outputOption(QStringLiteral("o"));
30 outputOption.setDescription(QStringLiteral("Write output to specified file."));
31 outputOption.setValueName(QStringLiteral("file"));
32 outputOption.setFlags(QCommandLineOption::ShortOptionStyle);
33 parser.addOption(commandLineOption: outputOption);
34
35 QCommandLineOption privateIncludesOption(
36 QStringLiteral("private-includes"),
37 QStringLiteral("Include headers ending in \"_p.h\" using \"#include <private/foo_p.h>\""
38 "rather than \"#include <foo_p.h>\"."));
39 parser.addOption(commandLineOption: privateIncludesOption);
40
41 QCommandLineOption importNameOption(QStringLiteral("import-name"));
42 importNameOption.setDescription(QStringLiteral("Name of the module to use for type and module "
43 "registrations."));
44 importNameOption.setValueName(QStringLiteral("module name"));
45 parser.addOption(commandLineOption: importNameOption);
46
47 QCommandLineOption pastMajorVersionOption(QStringLiteral("past-major-version"));
48 pastMajorVersionOption.setDescription(
49 QStringLiteral("Past major version to use for type and module "
50 "registrations."));
51 pastMajorVersionOption.setValueName(QStringLiteral("past major version"));
52 parser.addOption(commandLineOption: pastMajorVersionOption);
53
54 QCommandLineOption majorVersionOption(QStringLiteral("major-version"));
55 majorVersionOption.setDescription(QStringLiteral("Major version to use for type and module "
56 "registrations."));
57 majorVersionOption.setValueName(QStringLiteral("major version"));
58 parser.addOption(commandLineOption: majorVersionOption);
59
60 QCommandLineOption minorVersionOption(QStringLiteral("minor-version"));
61 minorVersionOption.setDescription(QStringLiteral("Minor version to use for module "
62 "registration."));
63 minorVersionOption.setValueName(QStringLiteral("minor version"));
64 parser.addOption(commandLineOption: minorVersionOption);
65
66 QCommandLineOption namespaceOption(QStringLiteral("namespace"));
67 namespaceOption.setDescription(QStringLiteral("Generate type registration functions "
68 "into a C++ namespace."));
69 namespaceOption.setValueName(QStringLiteral("namespace"));
70 parser.addOption(commandLineOption: namespaceOption);
71
72 QCommandLineOption pluginTypesOption(QStringLiteral("generate-qmltypes"));
73 pluginTypesOption.setDescription(QStringLiteral("Generate qmltypes into specified file."));
74 pluginTypesOption.setValueName(QStringLiteral("qmltypes file"));
75 parser.addOption(commandLineOption: pluginTypesOption);
76
77 QCommandLineOption foreignTypesOption(QStringLiteral("foreign-types"));
78 foreignTypesOption.setDescription(
79 QStringLiteral("Comma separated list of other modules' metatypes files "
80 "to consult for foreign types when generating "
81 "qmltypes file."));
82 foreignTypesOption.setValueName(QStringLiteral("foreign types"));
83 parser.addOption(commandLineOption: foreignTypesOption);
84
85 QCommandLineOption followForeignVersioningOption(QStringLiteral("follow-foreign-versioning"));
86 followForeignVersioningOption.setDescription(
87 QStringLiteral("If this option is set the versioning scheme of foreign base classes "
88 "will be respected instead of ignored. Mostly useful for modules who "
89 "want to follow Qt's versioning scheme."));
90 parser.addOption(commandLineOption: followForeignVersioningOption);
91
92 QCommandLineOption extract(u"extract"_s);
93 extract.setDescription(
94 u"Extract QML types from a module and use QML_FOREIGN to register them"_s);
95 parser.addOption(commandLineOption: extract);
96
97 parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
98 QStringLiteral("MOC generated json output."));
99
100 QStringList arguments;
101 if (!QmlTypeRegistrar::argumentsFromCommandLineAndFile(allArguments&: arguments, arguments: app.arguments()))
102 return EXIT_FAILURE;
103
104 parser.process(arguments);
105
106 const QString module = parser.value(option: importNameOption);
107
108 MetaTypesJsonProcessor processor(parser.isSet(option: privateIncludesOption));
109 if (!processor.processTypes(files: parser.positionalArguments()))
110 return EXIT_FAILURE;
111
112 processor.postProcessTypes();
113
114 if (parser.isSet(option: foreignTypesOption))
115 processor.processForeignTypes(foreignTypesFiles: parser.value(option: foreignTypesOption).split(sep: QLatin1Char(',')));
116
117 processor.postProcessForeignTypes();
118
119 if (parser.isSet(option: extract)) {
120 if (!parser.isSet(option: outputOption)) {
121 fprintf(stderr, format: "Error: The output file name must be provided\n");
122 return EXIT_FAILURE;
123 }
124 QString baseName = parser.value(option: outputOption);
125 return QmlTypeRegistrar::runExtract(baseName, processor);
126 }
127
128 QmlTypeRegistrar typeRegistrar;
129 typeRegistrar.setIncludes(processor.includes());
130 typeRegistrar.setModuleNameAndNamespace(module, targetNamespace: parser.value(option: namespaceOption));
131 QTypeRevision moduleVersion = QTypeRevision::fromVersion(
132 majorVersion: parser.value(option: majorVersionOption).toInt(), minorVersion: parser.value(option: minorVersionOption).toInt());
133 QList<quint8> pastMajorVersions;
134 for (const auto &x : parser.values(option: pastMajorVersionOption))
135 pastMajorVersions.append(t: x.toUInt());
136
137 typeRegistrar.setModuleVersions(moduleVersion, pastMajorVersions,
138 followForeignVersioning: parser.isSet(option: followForeignVersioningOption));
139 typeRegistrar.setTypes(types: processor.types(), foreignTypes: processor.foreignTypes());
140
141 if (parser.isSet(option: outputOption)) {
142 // extract does its own file handling
143 QString outputName = parser.value(option: outputOption);
144 QFile file(outputName);
145 if (!file.open(flags: QIODeviceBase::WriteOnly)) {
146 fprintf(stderr, format: "Error: Cannot open \"%s\" for writing: %s\n",
147 qPrintable(QDir::toNativeSeparators(outputName)),
148 qPrintable(file.errorString()));
149 return EXIT_FAILURE;
150 }
151 QTextStream output(&file);
152 typeRegistrar.write(os&: output);
153 } else {
154 QTextStream output(stdout);
155 typeRegistrar.write(os&: output);
156 }
157
158 if (!parser.isSet(option: pluginTypesOption))
159 return EXIT_SUCCESS;
160
161 typeRegistrar.setReferencedTypes(processor.referencedTypes());
162 const QString qmltypes = parser.value(option: pluginTypesOption);
163 if (!typeRegistrar.generatePluginTypes(pluginTypesFile: qmltypes)) {
164 fprintf(stderr, format: "Error: Cannot generate qmltypes file %s\n", qPrintable(qmltypes));
165 return EXIT_FAILURE;
166 }
167 return EXIT_SUCCESS;
168}
169

source code of qtdeclarative/tools/qmltyperegistrar/qmltyperegistrar.cpp