qmltyperegistrar: Extract into own library

Split qmltyperegistrar in two parts: the tool (commandline parsing etc)
and the lib (that does the actual qmltyperegistration generation).
The tool lives at tools/qmltyperegistrar and the lib lives in
src/qmltyperegistrar.
This would allow to test qmltyperegistrar and is a first step into adding
some structure to qmltyperegistrar.

Moves the qqmljsstreamwriter from QmlCompiler to QmlTypeRegistrar.
Also, moves the qmltypes.prf from the lib to the tool, so it can still
be used from qmake projects!

Fixes: QTBUG-103862
Change-Id: I8627d1181db139d043228a802f047a35bff63bb5
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Sami Shalayel 2022-06-02 12:18:18 +02:00
parent 281c5bf815
commit aba13583ac
19 changed files with 475 additions and 305 deletions

View File

@ -28,7 +28,6 @@ qt_internal_add_module(QmlCompilerPrivate
qqmljsscopesbyid_p.h qqmljsscopesbyid_p.h
qqmljsshadowcheck.cpp qqmljsshadowcheck_p.h qqmljsshadowcheck.cpp qqmljsshadowcheck_p.h
qqmljsstoragegeneralizer.cpp qqmljsstoragegeneralizer_p.h qqmljsstoragegeneralizer.cpp qqmljsstoragegeneralizer_p.h
qqmljsstreamwriter.cpp qqmljsstreamwriter_p.h
qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h
qqmljstypepropagator.cpp qqmljstypepropagator_p.h qqmljstypepropagator.cpp qqmljstypepropagator_p.h
qqmljstypereader.cpp qqmljstypereader_p.h qqmljstypereader.cpp qqmljstypereader_p.h

View File

@ -1,52 +1,21 @@
# Generated from qmltyperegistrar.pro.
##################################################################### #####################################################################
## qmltyperegistrar Tool: ## qmltyperegistrarprivate:
##################################################################### #####################################################################
qt_get_tool_target_name(target_name qmltyperegistrar) qt_internal_add_module(QmlTypeRegistrarPrivate
qt_internal_add_tool(${target_name} STATIC
TARGET_DESCRIPTION "QML Types Registrar" INTERNAL_MODULE
TOOLS_TARGET Qml # special case
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
SOURCES SOURCES
../qmlcompiler/qqmljsstreamwriter.cpp ../qmlcompiler/qqmljsstreamwriter_p.h qqmljsstreamwriter.cpp qqmljsstreamwriter_p.h
metatypesjsonprocessor.cpp metatypesjsonprocessor.h qmetatypesjsonprocessor.cpp qmetatypesjsonprocessor_p.h
qmltyperegistrar.cpp qqmltyperegistrar.cpp qqmltyperegistrar_p.h
qmltypesclassdescription.cpp qmltypesclassdescription.h qqmltypesclassdescription.cpp qqmltypesclassdescription_p.h
qmltypescreator.cpp qmltypescreator.h qqmltypescreator.cpp qqmltypescreator_p.h
DEFINES DEFINES
QT_NO_CAST_FROM_ASCII QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII QT_NO_CAST_TO_ASCII
INCLUDE_DIRECTORIES
../qmlcompiler
PUBLIC_LIBRARIES PUBLIC_LIBRARIES
Qt::CorePrivate Qt::CorePrivate
GENERATE_CPP_EXPORTS
GENERATE_PRIVATE_CPP_EXPORTS
) )
# Install public prf files.
set(qmltyperegistrar_mkspecs "${CMAKE_CURRENT_SOURCE_DIR}/qmltypes.prf")
set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}")
qt_path_join(mkspecs_install_dir "${QT_INSTALL_DIR}" "${mkspecs_install_dir}" "features")
qt_copy_or_install(FILES "${qmltyperegistrar_mkspecs}"
DESTINATION ${mkspecs_install_dir})
qt_internal_return_unless_building_tools()
#### Keys ignored in scope 1:.:.:qmltyperegistrar.pro:<TRUE>:
# QMAKE_TARGET_DESCRIPTION = "QML" "Types" "Registrar"
# _OPTION = "host_build"
# build_integration.files = "qmltypes.prf"
# build_integration.path = "$$[QT_HOST_DATA]/mkspecs/features"
## Scopes:
#####################################################################
#### Keys ignored in scope 2:.:.:qmltyperegistrar.pro:prefix_build:
# COPIES = "qmltypes_to_builddir"
# INSTALLS = "build_integration"
# qmltypes_to_builddir.files = "qmltypes.prf"
# qmltypes_to_builddir.path = "$$MODULE_BASE_OUTDIR/mkspecs/features"
#### Keys ignored in scope 3:.:.:qmltyperegistrar.pro:else:
# COPIES = "build_integration"

View File

@ -1,13 +1,15 @@
// Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "metatypesjsonprocessor.h" #include "qmetatypesjsonprocessor_p.h"
#include <QtCore/qfile.h> #include <QtCore/qfile.h>
#include <QtCore/qjsonarray.h> #include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h> #include <QtCore/qjsondocument.h>
#include <QtCore/qqueue.h> #include <QtCore/qqueue.h>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
bool MetaTypesJsonProcessor::processTypes(const QStringList &files) bool MetaTypesJsonProcessor::processTypes(const QStringList &files)
@ -356,3 +358,5 @@ void MetaTypesJsonProcessor::processForeignTypes(const QJsonObject &types)
m_foreignTypes.append(classDef); m_foreignTypes.append(classDef);
} }
} }
QT_END_NAMESPACE

View File

@ -1,15 +1,28 @@
// Copyright (C) 2020 The Qt Company Ltd. // Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef METATYPESJSONPROCESSOR_H #ifndef METATYPESJSONPROCESSOR_P_H
#define METATYPESJSONPROCESSOR_H #define METATYPESJSONPROCESSOR_P_H
#include "qmltypesclassdescription.h" //
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qqmltypesclassdescription_p.h"
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qvector.h> #include <QtCore/qvector.h>
#include <QtCore/qjsonobject.h> #include <QtCore/qjsonobject.h>
QT_BEGIN_NAMESPACE
class MetaTypesJsonProcessor class MetaTypesJsonProcessor
{ {
public: public:
@ -40,7 +53,7 @@ private:
void addRelatedTypes(); void addRelatedTypes();
void sortTypes(QVector<QJsonObject> &types); void sortTypes(QVector<QJsonObject> &types);
QString resolvedInclude(const QString &include);; QString resolvedInclude(const QString &include);
void processTypes(const QJsonObject &types); void processTypes(const QJsonObject &types);
void processForeignTypes(const QJsonObject &types); void processForeignTypes(const QJsonObject &types);
@ -50,5 +63,6 @@ private:
QVector<QJsonObject> m_foreignTypes; QVector<QJsonObject> m_foreignTypes;
bool m_privateIncludes = false; bool m_privateIncludes = false;
}; };
QT_END_NAMESPACE
#endif // METATYPESJSONPROCESSOR_H #endif // METATYPESJSONPROCESSOR_P_H

View File

@ -1,28 +1,15 @@
// Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmltypescreator.h"
#include "metatypesjsonprocessor.h"
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QtDebug>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QFile> #include <QFile>
#include <QScopedPointer> #include <QJsonArray>
#include <QSaveFile> #include <QJsonValue>
#include <QFileInfo>
#include <cstdlib> #include "qqmltyperegistrar_p.h"
#include "qqmltypescreator_p.h"
using namespace Qt::StringLiterals; QT_BEGIN_NAMESPACE
using namespace Qt::Literals;
struct ScopedPointerFileCloser
{
static inline void cleanup(FILE *handle) { if (handle) fclose(handle); }
};
struct ExclusiveVersionRange struct ExclusiveVersionRange
{ {
@ -54,7 +41,8 @@ bool operator==(const ExclusiveVersionRange &x, const ExclusiveVersionRange &y)
return !(x < y) && !(y < x); return !(x < y) && !(y < x);
} }
static bool argumentsFromCommandLineAndFile(QStringList &allArguments, const QStringList &arguments) bool QmlTypeRegistrar::argumentsFromCommandLineAndFile(QStringList &allArguments,
const QStringList &arguments)
{ {
allArguments.reserve(arguments.size()); allArguments.reserve(arguments.size());
for (const QString &argument : arguments) { for (const QString &argument : arguments) {
@ -83,7 +71,8 @@ static bool argumentsFromCommandLineAndFile(QStringList &allArguments, const QSt
return true; return true;
} }
static int runExtract(const QString & baseName, const MetaTypesJsonProcessor &processor) { int QmlTypeRegistrar::runExtract(const QString &baseName, const MetaTypesJsonProcessor &processor)
{
if (processor.types().isEmpty()) { if (processor.types().isEmpty()) {
fprintf(stderr, "Error: No types to register found in library\n"); fprintf(stderr, "Error: No types to register found in library\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -117,136 +106,43 @@ static int runExtract(const QString & baseName, const MetaTypesJsonProcessor &pr
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
int main(int argc, char **argv) QJsonValue QmlTypeRegistrar::findType(const QString &name) const
{ {
// Produce reliably the same output for the same input by disabling QHash's random seeding. for (const QJsonObject &type : m_types) {
qSetGlobalQHashSeed(0); if (type[QLatin1String("qualifiedClassName")] != name)
continue;
QCoreApplication app(argc, argv); return type;
QCoreApplication::setApplicationName(QStringLiteral("qmltyperegistrar"));
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption outputOption(QStringLiteral("o"));
outputOption.setDescription(QStringLiteral("Write output to specified file."));
outputOption.setValueName(QStringLiteral("file"));
outputOption.setFlags(QCommandLineOption::ShortOptionStyle);
parser.addOption(outputOption);
QCommandLineOption privateIncludesOption(
QStringLiteral("private-includes"),
QStringLiteral("Include headers ending in \"_p.h\" using \"#include <private/foo_p.h>\""
"rather than \"#include <foo_p.h>\"."));
parser.addOption(privateIncludesOption);
QCommandLineOption importNameOption(QStringLiteral("import-name"));
importNameOption.setDescription(QStringLiteral("Name of the module to use for type and module "
"registrations."));
importNameOption.setValueName(QStringLiteral("module name"));
parser.addOption(importNameOption);
QCommandLineOption pastMajorVersionOption(QStringLiteral("past-major-version"));
pastMajorVersionOption.setDescription(QStringLiteral("Past major version to use for type and module "
"registrations."));
pastMajorVersionOption.setValueName(QStringLiteral("past major version"));
parser.addOption(pastMajorVersionOption);
QCommandLineOption majorVersionOption(QStringLiteral("major-version"));
majorVersionOption.setDescription(QStringLiteral("Major version to use for type and module "
"registrations."));
majorVersionOption.setValueName(QStringLiteral("major version"));
parser.addOption(majorVersionOption);
QCommandLineOption minorVersionOption(QStringLiteral("minor-version"));
minorVersionOption.setDescription(QStringLiteral("Minor version to use for module "
"registration."));
minorVersionOption.setValueName(QStringLiteral("minor version"));
parser.addOption(minorVersionOption);
QCommandLineOption namespaceOption(QStringLiteral("namespace"));
namespaceOption.setDescription(QStringLiteral("Generate type registration functions "
"into a C++ namespace."));
namespaceOption.setValueName(QStringLiteral("namespace"));
parser.addOption(namespaceOption);
QCommandLineOption pluginTypesOption(QStringLiteral("generate-qmltypes"));
pluginTypesOption.setDescription(QStringLiteral("Generate qmltypes into specified file."));
pluginTypesOption.setValueName(QStringLiteral("qmltypes file"));
parser.addOption(pluginTypesOption);
QCommandLineOption foreignTypesOption(QStringLiteral("foreign-types"));
foreignTypesOption.setDescription(QStringLiteral(
"Comma separated list of other modules' metatypes files "
"to consult for foreign types when generating "
"qmltypes file."));
foreignTypesOption.setValueName(QStringLiteral("foreign types"));
parser.addOption(foreignTypesOption);
QCommandLineOption followForeignVersioningOption(QStringLiteral("follow-foreign-versioning"));
followForeignVersioningOption.setDescription(
QStringLiteral("If this option is set the versioning scheme of foreign base classes "
"will be respected instead of ignored. Mostly useful for modules who "
"want to follow Qt's versioning scheme."));
parser.addOption(followForeignVersioningOption);
QCommandLineOption extract(u"extract"_s);
extract.setDescription(u"Extract QML types from a module and use QML_FOREIGN to register them"_s);
parser.addOption(extract);
parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
QStringLiteral("MOC generated json output."));
QStringList arguments;
if (!argumentsFromCommandLineAndFile(arguments, app.arguments()))
return EXIT_FAILURE;
parser.process(arguments);
const QString module = parser.value(importNameOption);
MetaTypesJsonProcessor processor(parser.isSet(privateIncludesOption));
if (!processor.processTypes(parser.positionalArguments()))
return EXIT_FAILURE;
processor.postProcessTypes();
if (parser.isSet(foreignTypesOption))
processor.processForeignTypes(parser.value(foreignTypesOption).split(QLatin1Char(',')));
processor.postProcessForeignTypes();
if (parser.isSet(extract)) {
if (!parser.isSet(outputOption)) {
fprintf(stderr, "Error: The output file name must be provided\n");
return EXIT_FAILURE;
}
QString baseName = parser.value(outputOption);
return runExtract(baseName, processor);
} }
return QJsonValue();
};
FILE *output = stdout; QJsonValue QmlTypeRegistrar::findTypeForeign(const QString &name) const
QScopedPointer<FILE, ScopedPointerFileCloser> outputFile; {
for (const QJsonObject &type : m_foreignTypes) {
if (type[QLatin1String("qualifiedClassName")] != name)
if (parser.isSet(outputOption)) { continue;
// extract does its own file handling return type;
QString outputName = parser.value(outputOption);
#if defined(_MSC_VER)
if (_wfopen_s(&output, reinterpret_cast<const wchar_t *>(outputName.utf16()), L"w") != 0) {
#else
output = fopen(QFile::encodeName(outputName).constData(), "w"); // create output file
if (!output) {
#endif
fprintf(stderr, "Error: Cannot open %s for writing\n", qPrintable(outputName));
return EXIT_FAILURE;
}
outputFile.reset(output);
} }
return QJsonValue();
};
QString conflictingVersionToString(const ExclusiveVersionRange &r)
{
using namespace Qt::StringLiterals;
QString s = r.claimerName;
if (r.addedIn.isValid()) {
s += u" (added in %1.%2)"_s.arg(r.addedIn.majorVersion()).arg(r.addedIn.minorVersion());
}
if (r.removedIn.isValid()) {
s += u" (removed in %1.%2)"_s.arg(r.removedIn.majorVersion())
.arg(r.removedIn.minorVersion());
}
return s;
};
void QmlTypeRegistrar::write(FILE *output)
{
fprintf(output, fprintf(output,
"/****************************************************************************\n" "/****************************************************************************\n"
"** Generated QML type registration code\n**\n"); "** Generated QML type registration code\n**\n");
@ -257,23 +153,22 @@ int main(int argc, char **argv)
"#include <QtQml/qqml.h>\n" "#include <QtQml/qqml.h>\n"
"#include <QtQml/qqmlmoduleregistration.h>\n"); "#include <QtQml/qqmlmoduleregistration.h>\n");
const QStringList includes = processor.includes(); for (const QString &include : m_includes)
for (const QString &include : includes)
fprintf(output, "\n#include <%s>", qPrintable(include)); fprintf(output, "\n#include <%s>", qPrintable(include));
fprintf(output, "\n\n"); fprintf(output, "\n\n");
// Keep this in sync with _qt_internal_get_escaped_uri in CMake // Keep this in sync with _qt_internal_get_escaped_uri in CMake
QString moduleAsSymbol = module; QString moduleAsSymbol = m_module;
moduleAsSymbol.replace(QRegularExpression(QStringLiteral("[^A-Za-z0-9]")), QStringLiteral("_")); moduleAsSymbol.replace(QRegularExpression(QStringLiteral("[^A-Za-z0-9]")), QStringLiteral("_"));
QString underscoredModuleAsSymbol = module; QString underscoredModuleAsSymbol = m_module;
underscoredModuleAsSymbol.replace(QLatin1Char('.'), QLatin1Char('_')); underscoredModuleAsSymbol.replace(QLatin1Char('.'), QLatin1Char('_'));
if (underscoredModuleAsSymbol != moduleAsSymbol if (underscoredModuleAsSymbol != moduleAsSymbol
|| underscoredModuleAsSymbol.isEmpty() || underscoredModuleAsSymbol.isEmpty()
|| underscoredModuleAsSymbol.front().isDigit()) { || underscoredModuleAsSymbol.front().isDigit()) {
qWarning() << module << "is an invalid QML module URI. You cannot import this."; qWarning() << m_module << "is an invalid QML module URI. You cannot import this.";
} }
const QString functionName = QStringLiteral("qml_register_types_") + moduleAsSymbol; const QString functionName = QStringLiteral("qml_register_types_") + moduleAsSymbol;
@ -285,53 +180,28 @@ int main(int argc, char **argv)
"#endif\n" "#endif\n"
"\n"); "\n");
const QString targetNamespace = parser.value(namespaceOption); if (!m_targetNamespace.isEmpty())
if (!targetNamespace.isEmpty()) fprintf(output, "namespace %s {\n", qPrintable(m_targetNamespace));
fprintf(output, "namespace %s {\n", qPrintable(targetNamespace));
fprintf(output, "Q_QMLTYPE_EXPORT void %s()\n{", qPrintable(functionName)); fprintf(output, "Q_QMLTYPE_EXPORT void %s()\n{", qPrintable(functionName));
const auto majorVersion = parser.value(majorVersionOption); const quint8 majorVersion = m_moduleVersion.majorVersion();
const auto pastMajorVersions = parser.values(pastMajorVersionOption); const quint8 minorVersion = m_moduleVersion.minorVersion();
const auto minorVersion = parser.value(minorVersionOption);
const bool followForeignVersioning = parser.isSet(followForeignVersioningOption);
for (const auto &version : pastMajorVersions) { for (const auto &version : m_pastMajorVersions) {
fprintf(output, "\n qmlRegisterModule(\"%s\", %s, 0);\n qmlRegisterModule(\"%s\", %s, 254);", fprintf(output,
qPrintable(module), qPrintable(version), qPrintable(module), qPrintable(version)); "\n qmlRegisterModule(\"%s\", %u, 0);\n qmlRegisterModule(\"%s\", %u, 254);",
qPrintable(m_module), (version), qPrintable(m_module), (version));
} }
if (minorVersion.toInt() != 0) { if (minorVersion != 0) {
fprintf(output, "\n qmlRegisterModule(\"%s\", %s, 0);", fprintf(output, "\n qmlRegisterModule(\"%s\", %u, 0);", qPrintable(m_module),
qPrintable(module), qPrintable(majorVersion)); majorVersion);
} }
auto moduleVersion = QTypeRevision::fromVersion(majorVersion.toInt(), minorVersion.toInt());
const QVector<QJsonObject> types = processor.types();
const QVector<QJsonObject> foreignTypes = processor.foreignTypes();
QVector<QString> typesRegisteredAnonymously; QVector<QString> typesRegisteredAnonymously;
const auto &findType = [&](const QString &name) -> QJsonValue {
for (const QJsonObject &type : types) {
if (type[QLatin1String("qualifiedClassName")] != name)
continue;
return type;
}
return QJsonValue();
};
const auto &findTypeForeign = [&](const QString &name) -> QJsonValue {
for (const QJsonObject &type : foreignTypes) {
if (type[QLatin1String("qualifiedClassName")] != name)
continue;
return type;
}
return QJsonValue();
};
QHash<QString, QList<ExclusiveVersionRange>> qmlElementInfos; QHash<QString, QList<ExclusiveVersionRange>> qmlElementInfos;
for (const QJsonObject &classDef : types) { for (const QJsonObject &classDef : m_types) {
const QString className = classDef[QLatin1String("qualifiedClassName")].toString(); const QString className = classDef[QLatin1String("qualifiedClassName")].toString();
QString targetName = className; QString targetName = className;
@ -378,9 +248,9 @@ int main(int argc, char **argv)
if (className == targetName) if (className == targetName)
return true; return true;
const QJsonObject *target = QmlTypesClassDescription::findType(types, targetName); const QJsonObject *target = QmlTypesClassDescription::findType(m_types, targetName);
if (!target) if (!target)
target = QmlTypesClassDescription::findType(foreignTypes, targetName); target = QmlTypesClassDescription::findType(m_foreignTypes, targetName);
if (!target) if (!target)
return false; return false;
@ -414,10 +284,11 @@ int main(int argc, char **argv)
}; };
if (seenQmlElement) { if (seenQmlElement) {
fprintf(output, "\n qmlRegisterNamespaceAndRevisions(%s, " fprintf(output,
"\"%s\", %s, nullptr, %s, %s);", "\n qmlRegisterNamespaceAndRevisions(%s, "
qPrintable(metaObjectPointer(targetName)), qPrintable(module), "\"%s\", %u, nullptr, %s, %s);",
qPrintable(majorVersion), qPrintable(metaObjectPointer(className)), qPrintable(metaObjectPointer(targetName)), qPrintable(m_module),
(majorVersion), qPrintable(metaObjectPointer(className)),
extendedName.isEmpty() ? "nullptr" extendedName.isEmpty() ? "nullptr"
: qPrintable(metaObjectPointer(extendedName))); : qPrintable(metaObjectPointer(extendedName)));
} }
@ -430,12 +301,12 @@ int main(int argc, char **argv)
continue; continue;
QTypeRevision revision = QTypeRevision::fromEncodedVersion(object[QLatin1String("revision")].toInt()); QTypeRevision revision = QTypeRevision::fromEncodedVersion(object[QLatin1String("revision")].toInt());
if (moduleVersion < revision) { if (m_moduleVersion < revision) {
qWarning().noquote() qWarning().noquote()
<< "Warning:" << className << "is trying to register" << type << "Warning:" << className << "is trying to register" << type
<< object[QStringLiteral("name")].toString() << object[QStringLiteral("name")].toString()
<< "with future version" << revision << "with future version" << revision
<< "when module version is only" << moduleVersion; << "when module version is only" << m_moduleVersion;
} }
} }
}; };
@ -443,13 +314,13 @@ int main(int argc, char **argv)
const QJsonArray methods = classDef[QLatin1String("methods")].toArray(); const QJsonArray methods = classDef[QLatin1String("methods")].toArray();
const QJsonArray properties = classDef[QLatin1String("properties")].toArray(); const QJsonArray properties = classDef[QLatin1String("properties")].toArray();
if (moduleVersion.isValid()) { if (m_moduleVersion.isValid()) {
checkRevisions(properties, QLatin1String("property")); checkRevisions(properties, QLatin1String("property"));
checkRevisions(methods, QLatin1String("method")); checkRevisions(methods, QLatin1String("method"));
} }
fprintf(output, "\n qmlRegisterTypesAndRevisions<%s>(\"%s\", %s);", fprintf(output, "\n qmlRegisterTypesAndRevisions<%s>(\"%s\", %u);",
qPrintable(className), qPrintable(module), qPrintable(majorVersion)); qPrintable(className), qPrintable(m_module), (majorVersion));
const QJsonValue superClasses = classDef[QLatin1String("superClasses")]; const QJsonValue superClasses = classDef[QLatin1String("superClasses")];
@ -486,25 +357,26 @@ int main(int argc, char **argv)
typesRegisteredAnonymously.append(typeName); typesRegisteredAnonymously.append(typeName);
if (followForeignVersioning) { if (m_followForeignVersioning) {
fprintf(output, fprintf(output,
"\n " "\n "
"qmlRegisterAnonymousTypesAndRevisions<%s>(\"%" "qmlRegisterAnonymousTypesAndRevisions<%s>(\"%"
"s\", " "s\", "
"%s);", "%u);",
qPrintable(typeName), qPrintable(module), qPrintable(typeName), qPrintable(m_module),
qPrintable(majorVersion)); (majorVersion));
break; break;
} }
for (const QString &version : for (const auto &version : m_pastMajorVersions
pastMajorVersions + QStringList { majorVersion }) { + decltype(m_pastMajorVersions){
majorVersion }) {
fprintf(output, fprintf(output,
"\n " "\n "
"qmlRegisterAnonymousType<%s, 254>(\"%s\", " "qmlRegisterAnonymousType<%s, 254>(\"%s\", "
"%s);", "%u);",
qPrintable(typeName), qPrintable(module), qPrintable(typeName), qPrintable(m_module),
qPrintable(version)); (version));
} }
break; break;
} }
@ -537,19 +409,7 @@ int main(int argc, char **argv)
} }
} }
auto printConflictingVersion = [](const ExclusiveVersionRange &r) -> QString { for (const auto &[qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
QString s = r.claimerName;
if (r.addedIn.isValid()) {
s += u" (added in %1.%2)"_s.arg(r.addedIn.majorVersion()).arg(r.addedIn.minorVersion());
}
if (r.removedIn.isValid()) {
s += u" (removed in %1.%2)"_s.arg(r.removedIn.majorVersion())
.arg(r.removedIn.minorVersion());
}
return s;
};
for (const auto [qmlName, exportsForSameQmlName] : qmlElementInfos.asKeyValueRange()) {
// needs a least two cpp classes exporting the same qml element to potentially have a // needs a least two cpp classes exporting the same qml element to potentially have a
// conflict // conflict
if (exportsForSameQmlName.size() < 2) if (exportsForSameQmlName.size() < 2)
@ -571,7 +431,7 @@ int main(int argc, char **argv)
QString registeringCppClasses = conflictingExportStartIt->claimerName; QString registeringCppClasses = conflictingExportStartIt->claimerName;
std::for_each(std::next(conflictingExportStartIt), conflictingExportEndIt, std::for_each(std::next(conflictingExportStartIt), conflictingExportEndIt,
[&](const auto &q) { [&](const auto &q) {
registeringCppClasses += u", %1"_s.arg(printConflictingVersion(q)); registeringCppClasses += u", %1"_s.arg(conflictingVersionToString(q));
}); });
qWarning().noquote() << "Warning:" << qmlName qWarning().noquote() << "Warning:" << qmlName
<< "was registered multiple times by following Cpp classes: " << "was registered multiple times by following Cpp classes: "
@ -579,25 +439,55 @@ int main(int argc, char **argv)
conflictingExportStartIt = conflictingExportEndIt; conflictingExportStartIt = conflictingExportEndIt;
} }
} }
fprintf(output, "\n qmlRegisterModule(\"%s\", %s, %s);", fprintf(output, "\n qmlRegisterModule(\"%s\", %u, %u);", qPrintable(m_module),
qPrintable(module), qPrintable(majorVersion), qPrintable(minorVersion)); (majorVersion), (minorVersion));
fprintf(output, "\n}\n"); fprintf(output, "\n}\n");
fprintf(output, "\nstatic const QQmlModuleRegistration registration(\"%s\", %s);\n", fprintf(output, "\nstatic const QQmlModuleRegistration registration(\"%s\", %s);\n",
qPrintable(module), qPrintable(functionName)); qPrintable(m_module), qPrintable(functionName));
if (!targetNamespace.isEmpty()) if (!m_targetNamespace.isEmpty())
fprintf(output, "} // namespace %s\n", qPrintable(targetNamespace)); fprintf(output, "} // namespace %s\n", qPrintable(m_targetNamespace));
if (!parser.isSet(pluginTypesOption))
return EXIT_SUCCESS;
QmlTypesCreator creator;
creator.setOwnTypes(processor.types());
creator.setForeignTypes(processor.foreignTypes());
creator.setReferencedTypes(processor.referencedTypes());
creator.setModule(module);
creator.setVersion(QTypeRevision::fromVersion(parser.value(majorVersionOption).toInt(), 0));
creator.generate(parser.value(pluginTypesOption));
return EXIT_SUCCESS;
} }
void QmlTypeRegistrar::generatePluginTypes(const QString &pluginTypesFile)
{
QmlTypesCreator creator;
creator.setOwnTypes(m_types);
creator.setForeignTypes(m_foreignTypes);
creator.setReferencedTypes(m_referencedTypes);
creator.setModule(m_module);
creator.setVersion(m_moduleVersion);
creator.generate(pluginTypesFile);
}
void QmlTypeRegistrar::setModuleNameAndNamespace(const QString &module,
const QString &targetNamespace)
{
m_module = module;
m_targetNamespace = targetNamespace;
}
void QmlTypeRegistrar::setModuleVersions(QTypeRevision moduleVersion,
const QList<quint8> &pastMajorVersions,
bool followForeignVersioning)
{
m_moduleVersion = moduleVersion;
m_pastMajorVersions = pastMajorVersions;
m_followForeignVersioning = followForeignVersioning;
}
void QmlTypeRegistrar::setIncludes(const QList<QString> &includes)
{
m_includes = includes;
}
void QmlTypeRegistrar::setTypes(const QVector<QJsonObject> &types,
const QVector<QJsonObject> &foreignTypes)
{
m_types = types;
m_foreignTypes = foreignTypes;
}
void QmlTypeRegistrar::setReferencedTypes(const QStringList &referencedTypes)
{
m_referencedTypes = referencedTypes;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,58 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QMLTYPEREGISTRAR_P_H
#define QMLTYPEREGISTRAR_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QJsonObject>
#include <QTypeRevision>
#include <cstdlib>
#include "qmetatypesjsonprocessor_p.h"
QT_BEGIN_NAMESPACE
class QmlTypeRegistrar
{
QString m_module;
QString m_targetNamespace;
QTypeRevision m_moduleVersion;
QList<quint8> m_pastMajorVersions;
QStringList m_includes;
bool m_followForeignVersioning;
QVector<QJsonObject> m_types;
QVector<QJsonObject> m_foreignTypes;
QStringList m_referencedTypes;
QJsonValue findType(const QString &name) const;
QJsonValue findTypeForeign(const QString &name) const;
public:
void write(FILE *output);
void generatePluginTypes(const QString &pluginTypesFile);
void setModuleNameAndNamespace(const QString &module, const QString &targetNamespace);
void setModuleVersions(QTypeRevision moduleVersion, const QList<quint8> &pastMajorVersions,
bool followForeignVersioning);
void setIncludes(const QList<QString> &includes);
void setTypes(const QVector<QJsonObject> &types, const QVector<QJsonObject> &foreignTypes);
void setReferencedTypes(const QStringList &referencedTypes);
static bool argumentsFromCommandLineAndFile(QStringList &allArguments,
const QStringList &arguments);
static int runExtract(const QString &baseName, const MetaTypesJsonProcessor &processor);
};
QT_END_NAMESPACE
#endif // QMLTYPEREGISTRAR_P_H

View File

@ -1,11 +1,13 @@
// Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmltypesclassdescription.h" #include "qqmltypesclassdescription_p.h"
#include "qmltypescreator.h" #include "qqmltypescreator_p.h"
#include <QtCore/qjsonarray.h> #include <QtCore/qjsonarray.h>
QT_BEGIN_NAMESPACE
static void collectExtraVersions(const QJsonObject *component, const QString &key, static void collectExtraVersions(const QJsonObject *component, const QString &key,
QList<QTypeRevision> &extraVersions) QList<QTypeRevision> &extraVersions)
{ {
@ -265,3 +267,5 @@ void QmlTypesClassDescription::collectRelated(const QString &related,
else if (const QJsonObject *other = findType(foreign, related)) else if (const QJsonObject *other = findType(foreign, related))
collect(other, types, foreign, RelatedType, defaultRevision); collect(other, types, foreign, RelatedType, defaultRevision);
} }
QT_END_NAMESPACE

View File

@ -1,8 +1,19 @@
// Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QMLTYPESCLASSDESCRIPTION_H #ifndef QMLTYPESCLASSDESCRIPTION_P_H
#define QMLTYPESCLASSDESCRIPTION_H #define QMLTYPESCLASSDESCRIPTION_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qjsonobject.h> #include <QtCore/qjsonobject.h>
@ -10,6 +21,8 @@
#include <QtCore/qset.h> #include <QtCore/qset.h>
#include <QtCore/qversionnumber.h> #include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
struct QmlTypesClassDescription struct QmlTypesClassDescription
{ {
const QJsonObject *resolvedClass = nullptr; const QJsonObject *resolvedClass = nullptr;
@ -60,4 +73,5 @@ private:
void collectInterfaces(const QJsonObject *classDef); void collectInterfaces(const QJsonObject *classDef);
}; };
#endif // QMLTYPESCLASSDESCRIPTION_H QT_END_NAMESPACE
#endif // QMLTYPESCLASSDESCRIPTION_P_H

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qmltypescreator.h" #include "qqmltypescreator_p.h"
#include "qmltypesclassdescription.h" #include "qqmltypesclassdescription_p.h"
#include <QtCore/qset.h> #include <QtCore/qset.h>
#include <QtCore/qjsonarray.h> #include <QtCore/qjsonarray.h>
@ -13,6 +13,8 @@
using namespace Qt::StringLiterals; using namespace Qt::StringLiterals;
QT_BEGIN_NAMESPACE
static QString enquote(const QString &string) static QString enquote(const QString &string)
{ {
QString s = string; QString s = string;
@ -417,3 +419,5 @@ void QmlTypesCreator::generate(const QString &outFileName)
file.commit(); file.commit();
} }
QT_END_NAMESPACE

View File

@ -1,15 +1,28 @@
// Copyright (C) 2019 The Qt Company Ltd. // Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QMLTYPESCREATOR_H #ifndef QMLTYPESCREATOR_P_H
#define QMLTYPESCREATOR_H #define QMLTYPESCREATOR_P_H
#include "qmltypesclassdescription.h" //
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qqmltypesclassdescription_p.h"
#include "qqmljsstreamwriter_p.h" #include "qqmljsstreamwriter_p.h"
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qset.h> #include <QtCore/qset.h>
QT_BEGIN_NAMESPACE
class QmlTypesCreator class QmlTypesCreator
{ {
public: public:
@ -40,4 +53,6 @@ private:
QTypeRevision m_version = QTypeRevision::zero(); QTypeRevision m_version = QTypeRevision::zero();
}; };
#endif // QMLTYPESCREATOR_H QT_END_NAMESPACE
#endif // QMLTYPESCREATOR_P_H

View File

@ -13,6 +13,7 @@
"QtQmlModels" => "$basedir/src/qmlmodels", "QtQmlModels" => "$basedir/src/qmlmodels",
"QtQmlWorkerScript" => "$basedir/src/qmlworkerscript", "QtQmlWorkerScript" => "$basedir/src/qmlworkerscript",
"QtQmlCompiler" => "$basedir/src/qmlcompiler", "QtQmlCompiler" => "$basedir/src/qmlcompiler",
"QtQmlTypeRegistrar" => "$basedir/src/qmltyperegistrar/",
"QtQmlDom" => "$basedir/src/qmldom", "QtQmlDom" => "$basedir/src/qmldom",
"QtQuickLayouts" => "$basedir/src/quicklayouts", "QtQuickLayouts" => "$basedir/src/quicklayouts",
"QtQmlLocalStorage" => "$basedir/src/qmllocalstorage", "QtQmlLocalStorage" => "$basedir/src/qmllocalstorage",

View File

@ -5,6 +5,7 @@ if(QT_FEATURE_qml_devtools)
if(QT_FEATURE_commandlineparser) if(QT_FEATURE_commandlineparser)
add_subdirectory(qmllint) add_subdirectory(qmllint)
add_subdirectory(qmltc) add_subdirectory(qmltc)
add_subdirectory(qmltyperegistrar)
endif() endif()
add_subdirectory(qmlimportscanner) add_subdirectory(qmlimportscanner)
add_subdirectory(qmlformat) add_subdirectory(qmlformat)

View File

@ -9,11 +9,10 @@ qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "QML Plugin Metadata Dumper" TARGET_DESCRIPTION "QML Plugin Metadata Dumper"
TOOLS_TARGET Qml # special case TOOLS_TARGET Qml # special case
SOURCES SOURCES
../../src/qmlcompiler/qqmljsstreamwriter.cpp ../../src/qmlcompiler/qqmljsstreamwriter_p.h
main.cpp main.cpp
qmltypereader.cpp qmltypereader.h qmltypereader.cpp qmltypereader.h
INCLUDE_DIRECTORIES LIBRARIES
../../src/qmlcompiler Qt::QmlTypeRegistrarPrivate
PUBLIC_LIBRARIES PUBLIC_LIBRARIES
Qt::CorePrivate Qt::CorePrivate
Qt::Gui Qt::Gui

View File

@ -29,13 +29,13 @@
#include <QtCore/QProcess> #include <QtCore/QProcess>
#include <QtCore/private/qobject_p.h> #include <QtCore/private/qobject_p.h>
#include <QtCore/private/qmetaobject_p.h> #include <QtCore/private/qmetaobject_p.h>
#include <QtQmlTypeRegistrar/private/qqmljsstreamwriter_p.h>
#include <QRegularExpression> #include <QRegularExpression>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include "qmltypereader.h" #include "qmltypereader.h"
#include "qqmljsstreamwriter_p.h"
#ifdef QT_SIMULATOR #ifdef QT_SIMULATOR
#include <QtGui/private/qsimulatorconnection_p.h> #include <QtGui/private/qsimulatorconnection_p.h>

View File

@ -0,0 +1,25 @@
#####################################################################
## qmltyperegistrar Tool:
#####################################################################
qt_get_tool_target_name(target_name qmltyperegistrar)
qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "QML Types Registrar"
TOOLS_TARGET Qml # special case
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
SOURCES
qmltyperegistrar.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
PUBLIC_LIBRARIES
Qt::Core
Qt::QmlTypeRegistrarPrivate
)
# support for .pro projects needing qmltyperegistrar
set(qmltyperegistrar_mkspecs "${CMAKE_CURRENT_SOURCE_DIR}/qmltypes.prf")
set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}")
qt_path_join(mkspecs_install_dir "${QT_INSTALL_DIR}" "${mkspecs_install_dir}" "features")
qt_copy_or_install(FILES "${qmltyperegistrar_mkspecs}"
DESTINATION ${mkspecs_install_dir})

View File

@ -0,0 +1,173 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QCoreApplication>
#include <QCommandLineParser>
#include <QFile>
#include <QScopedPointer>
#include <cstdlib>
#include <QtQmlTypeRegistrar/private/qqmltyperegistrar_p.h>
using namespace Qt::Literals;
struct ScopedPointerFileCloser
{
static inline void cleanup(FILE *handle)
{
if (handle)
fclose(handle);
}
};
int main(int argc, char **argv)
{
// Produce reliably the same output for the same input by disabling QHash's random seeding.
qSetGlobalQHashSeed(0);
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName(QStringLiteral("qmltyperegistrar"));
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
QCommandLineParser parser;
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption outputOption(QStringLiteral("o"));
outputOption.setDescription(QStringLiteral("Write output to specified file."));
outputOption.setValueName(QStringLiteral("file"));
outputOption.setFlags(QCommandLineOption::ShortOptionStyle);
parser.addOption(outputOption);
QCommandLineOption privateIncludesOption(
QStringLiteral("private-includes"),
QStringLiteral("Include headers ending in \"_p.h\" using \"#include <private/foo_p.h>\""
"rather than \"#include <foo_p.h>\"."));
parser.addOption(privateIncludesOption);
QCommandLineOption importNameOption(QStringLiteral("import-name"));
importNameOption.setDescription(QStringLiteral("Name of the module to use for type and module "
"registrations."));
importNameOption.setValueName(QStringLiteral("module name"));
parser.addOption(importNameOption);
QCommandLineOption pastMajorVersionOption(QStringLiteral("past-major-version"));
pastMajorVersionOption.setDescription(
QStringLiteral("Past major version to use for type and module "
"registrations."));
pastMajorVersionOption.setValueName(QStringLiteral("past major version"));
parser.addOption(pastMajorVersionOption);
QCommandLineOption majorVersionOption(QStringLiteral("major-version"));
majorVersionOption.setDescription(QStringLiteral("Major version to use for type and module "
"registrations."));
majorVersionOption.setValueName(QStringLiteral("major version"));
parser.addOption(majorVersionOption);
QCommandLineOption minorVersionOption(QStringLiteral("minor-version"));
minorVersionOption.setDescription(QStringLiteral("Minor version to use for module "
"registration."));
minorVersionOption.setValueName(QStringLiteral("minor version"));
parser.addOption(minorVersionOption);
QCommandLineOption namespaceOption(QStringLiteral("namespace"));
namespaceOption.setDescription(QStringLiteral("Generate type registration functions "
"into a C++ namespace."));
namespaceOption.setValueName(QStringLiteral("namespace"));
parser.addOption(namespaceOption);
QCommandLineOption pluginTypesOption(QStringLiteral("generate-qmltypes"));
pluginTypesOption.setDescription(QStringLiteral("Generate qmltypes into specified file."));
pluginTypesOption.setValueName(QStringLiteral("qmltypes file"));
parser.addOption(pluginTypesOption);
QCommandLineOption foreignTypesOption(QStringLiteral("foreign-types"));
foreignTypesOption.setDescription(
QStringLiteral("Comma separated list of other modules' metatypes files "
"to consult for foreign types when generating "
"qmltypes file."));
foreignTypesOption.setValueName(QStringLiteral("foreign types"));
parser.addOption(foreignTypesOption);
QCommandLineOption followForeignVersioningOption(QStringLiteral("follow-foreign-versioning"));
followForeignVersioningOption.setDescription(
QStringLiteral("If this option is set the versioning scheme of foreign base classes "
"will be respected instead of ignored. Mostly useful for modules who "
"want to follow Qt's versioning scheme."));
parser.addOption(followForeignVersioningOption);
QCommandLineOption extract(u"extract"_s);
extract.setDescription(
u"Extract QML types from a module and use QML_FOREIGN to register them"_s);
parser.addOption(extract);
parser.addPositionalArgument(QStringLiteral("[MOC generated json file]"),
QStringLiteral("MOC generated json output."));
QStringList arguments;
if (!QmlTypeRegistrar::argumentsFromCommandLineAndFile(arguments, app.arguments()))
return EXIT_FAILURE;
parser.process(arguments);
const QString module = parser.value(importNameOption);
MetaTypesJsonProcessor processor(parser.isSet(privateIncludesOption));
if (!processor.processTypes(parser.positionalArguments()))
return EXIT_FAILURE;
processor.postProcessTypes();
if (parser.isSet(foreignTypesOption))
processor.processForeignTypes(parser.value(foreignTypesOption).split(QLatin1Char(',')));
processor.postProcessForeignTypes();
if (parser.isSet(extract)) {
if (!parser.isSet(outputOption)) {
fprintf(stderr, "Error: The output file name must be provided\n");
return EXIT_FAILURE;
}
QString baseName = parser.value(outputOption);
return QmlTypeRegistrar::runExtract(baseName, processor);
}
QmlTypeRegistrar typeRegistrar;
typeRegistrar.setIncludes(processor.includes());
typeRegistrar.setModuleNameAndNamespace(module, parser.value(namespaceOption));
QTypeRevision moduleVersion = QTypeRevision::fromVersion(
parser.value(majorVersionOption).toInt(), parser.value(minorVersionOption).toInt());
QList<quint8> pastMajorVersions;
for (const auto &x : parser.values(pastMajorVersionOption))
pastMajorVersions.append(x.toUInt());
typeRegistrar.setModuleVersions(moduleVersion, pastMajorVersions,
parser.isSet(followForeignVersioningOption));
typeRegistrar.setTypes(processor.types(), processor.foreignTypes());
FILE *output = stdout;
QScopedPointer<FILE, ScopedPointerFileCloser> outputFile;
if (parser.isSet(outputOption)) {
// extract does its own file handling
QString outputName = parser.value(outputOption);
#if defined(_MSC_VER)
if (_wfopen_s(&output, reinterpret_cast<const wchar_t *>(outputName.utf16()), L"w") != 0) {
#else
output = fopen(QFile::encodeName(outputName).constData(), "w"); // create output file
if (!output) {
#endif
fprintf(stderr, "Error: Cannot open %s for writing\n", qPrintable(outputName));
return EXIT_FAILURE;
}
}
typeRegistrar.write(output);
if (!parser.isSet(pluginTypesOption))
return EXIT_SUCCESS;
typeRegistrar.setReferencedTypes(processor.referencedTypes());
typeRegistrar.generatePluginTypes(parser.value(pluginTypesOption));
return EXIT_SUCCESS;
}