diff options
Diffstat (limited to 'sources/shiboken6/generator/main.cpp')
-rw-r--r-- | sources/shiboken6/generator/main.cpp | 868 |
1 files changed, 301 insertions, 567 deletions
diff --git a/sources/shiboken6/generator/main.cpp b/sources/shiboken6/generator/main.cpp index 049ffaf18..9871df206 100644 --- a/sources/shiboken6/generator/main.cpp +++ b/sources/shiboken6/generator/main.cpp @@ -1,674 +1,369 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QCoreApplication> -#include <QLibrary> -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QVariant> -#include <iostream> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "shibokenconfig.h" +#include "cppgenerator.h" +#include "generator.h" +#include "headergenerator.h" +#include "qtdocgenerator.h" + #include <apiextractor.h> #include <apiextractorresult.h> +#include <exception.h> #include <fileout.h> +#include <messages.h> +#include <optionsparser.h> #include <reporthandler.h> #include <typedatabase.h> -#include <messages.h> -#include "generator.h" -#include "shibokenconfig.h" -#include "cppgenerator.h" -#include "headergenerator.h" -#include "qtdocgenerator.h" -static const QChar clangOptionsSplitter = u','; -static const QChar dropTypeEntriesSplitter = u';'; -static const QChar apiVersionSplitter = u'|'; - -static inline QString clangOptionOption() { return QStringLiteral("clang-option"); } -static inline QString clangOptionsOption() { return QStringLiteral("clang-options"); } -static inline QString apiVersionOption() { return QStringLiteral("api-version"); } -static inline QString dropTypeEntriesOption() { return QStringLiteral("drop-type-entries"); } -static inline QString languageLevelOption() { return QStringLiteral("language-level"); } -static inline QString includePathOption() { return QStringLiteral("include-paths"); } -static inline QString frameworkIncludePathOption() { return QStringLiteral("framework-include-paths"); } -static inline QString systemIncludePathOption() { return QStringLiteral("system-include-paths"); } -static inline QString typesystemPathOption() { return QStringLiteral("typesystem-paths"); } -static inline QString helpOption() { return QStringLiteral("help"); } -static inline QString diffOption() { return QStringLiteral("diff"); } -static inline QString dryrunOption() { return QStringLiteral("dry-run"); } -static inline QString skipDeprecatedOption() { return QStringLiteral("skip-deprecated"); } +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibrary> +#include <QtCore/QVariant> -static const char helpHint[] = "Note: use --help or -h for more information.\n"; +#include "qtcompat.h" -using OptionDescriptions = Generator::OptionDescriptions; +#include <exception> +#include <iostream> -struct CommandLineArguments -{ - void addToOptionsList(const QString &option, - const QString &value); - void addToOptionsList(const QString &option, - const QStringList &value); - void addToOptionsList(const QString &option, - const QString &listValue, - QChar separator); - void addToOptionsPathList(const QString &option, - const QString &pathListValue) - { - addToOptionsList(option, pathListValue, QDir::listSeparator()); - } +using namespace Qt::StringLiterals; - QVariantMap options; // string,stringlist for path lists, etc. - QStringList positionalArguments; -}; +static const char helpHint[] = "Note: use --help or -h for more information.\n"; +static const char appName[] = "shiboken"; -void CommandLineArguments::addToOptionsList(const QString &option, - const QString &value) +static inline Generators docGenerators() { - auto it = options.find(option); - if (it == options.end()) { - options.insert(option, QVariant(QStringList(value))); - } else { - auto list = it.value().toStringList(); - list += value; - options[option] = QVariant(list); - } + Generators result; +#ifdef DOCSTRINGS_ENABLED + result.append(GeneratorPtr(new QtDocGenerator)); +#endif + return result; } -void CommandLineArguments::addToOptionsList(const QString &option, - const QStringList &value) +static inline Generators shibokenGenerators() { - auto it = options.find(option); - if (it == options.end()) { - options.insert(option, QVariant(value)); - } else { - auto list = it.value().toStringList(); - list += value; - options[option] = QVariant(list); - } + Generators result; + result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator); + return result; } -void CommandLineArguments::addToOptionsList(const QString &option, - const QString &listValue, - QChar separator) +struct CommonOptions { - const auto newValues = listValue.split(separator, Qt::SkipEmptyParts); - addToOptionsList(option, newValues); -} + QString generatorSet; + QString licenseComment; + QString outputDirectory = u"out"_s; + QStringList headers; + QString typeSystemFileName; + bool help = false; + bool version = false; + bool diff = false; + bool dryRun = false; + bool logUnmatched = false; + bool printBuiltinTypes = false; +}; -static void printOptions(QTextStream &s, const OptionDescriptions &options) +class CommonOptionsParser : public OptionsParser { - s.setFieldAlignment(QTextStream::AlignLeft); - for (const auto &od : options) { - if (!od.first.startsWith(QLatin1Char('-'))) - s << "--"; - s << od.first; - if (od.second.isEmpty()) { - s << ", "; - } else { - s << Qt::endl; - const auto lines = QStringView{od.second}.split(QLatin1Char('\n')); - for (const auto &line : lines) - s << " " << line << Qt::endl; - s << Qt::endl; - } - } -} +public: + explicit CommonOptionsParser(CommonOptions *o) : m_options(o) {} -static std::optional<CommandLineArguments> - processProjectFile(const QString &appName, QFile &projectFile) -{ - QByteArray line = projectFile.readLine().trimmed(); - if (line.isEmpty() || line != "[generator-project]") { - std::cerr << qPrintable(appName) << ": first line of project file \"" - << qPrintable(projectFile.fileName()) - << "\" must be the string \"[generator-project]\"\n"; - return {}; - } + bool handleBoolOption(const QString &key, OptionSource source) override; + bool handleOption(const QString &key, const QString &value, OptionSource source) override; - CommandLineArguments args; - - while (!projectFile.atEnd()) { - line = projectFile.readLine().trimmed(); - if (line.isEmpty()) - continue; - - int split = line.indexOf('='); - QByteArray key; - QString value; - if (split > 0) { - key = line.left(split).trimmed(); - value = QString::fromUtf8(line.mid(split + 1).trimmed()); - } else { - key = line; - } + static OptionDescriptions optionDescriptions(); - if (key == "include-path") { - args.addToOptionsList(includePathOption(), - QDir::toNativeSeparators(value)); - } else if (key == "framework-include-path") { - args.addToOptionsList(frameworkIncludePathOption(), - QDir::toNativeSeparators(value)); - } else if (key == "system-include-paths") { - args.addToOptionsList(systemIncludePathOption(), - QDir::toNativeSeparators(value)); - } else if (key == "typesystem-path") { - args.addToOptionsList(typesystemPathOption(), - QDir::toNativeSeparators(value)); - } else if (key == "language-level") { - args.options.insert(languageLevelOption(), value); - } else if (key == "clang-option") { - args.addToOptionsList(clangOptionsOption(), value); - } else if (key == "clang-options") { - args.addToOptionsList(clangOptionsOption(), - value, clangOptionsSplitter); - } else if (key == "api-version") { - args.addToOptionsList(apiVersionOption(), - value, apiVersionSplitter); - } else if (key == "drop-type-entries") { - args.addToOptionsList(dropTypeEntriesOption(), - value, dropTypeEntriesSplitter); - } else if (key == "header-file") { - args.positionalArguments.prepend(value); - } else if (key == "typesystem-file") { - args.positionalArguments.append(value); - } else { - args.options.insert(QString::fromUtf8(key), value); - } - } +private: + CommonOptions *m_options; +}; - return args; +OptionDescriptions CommonOptionsParser::optionDescriptions() +{ + return { + {u"debug-level=[sparse|medium|full]"_s, + u"Set the debug level"_s}, + {u"documentation-only"_s, + u"Do not generates any code, just the documentation"_s}, + {u"compiler=<type>"_s, + u"Emulated compiler type (g++, msvc, clang)"_s}, + {u"platform=<name>"_s, + u"Emulated platform (windows, darwin, unix)"_s}, + {u"compiler-path=<file>"_s, + u"Path to the compiler for determining builtin include paths"_s}, + {u"generator-set=<\"generator module\">"_s, + u"generator-set to be used. e.g. qtdoc"_s}, + {u"diff"_s, u"Print a diff of wrapper files"_s}, + {u"dry-run"_s, u"Dry run, do not generate wrapper files"_s}, + {u"-h"_s, {} }, + {u"help"_s, u"Display this help and exit"_s}, + {u"-I<path>"_s, {} }, + {u"include-paths="_s + OptionsParser::pathSyntax(), + u"Include paths used by the C++ parser"_s}, + {u"license-file=<license-file>"_s, + u"File used for copyright headers of generated files"_s}, + {u"no-suppress-warnings"_s, + u"Show all warnings"_s}, + {u"output-directory=<path>"_s, + u"The directory where the generated files will be written"_s}, + {u"project-file=<file>"_s, + u"text file containing a description of the binding project.\n" + "Replaces and overrides command line arguments"_s}, + {u"silent"_s, u"Avoid printing any message"_s}, + {u"print-builtin-types"_s, + u"Print information about builtin types"_s}, + {u"version"_s, + u"Output version information and exit"_s} + }; } -static std::optional<CommandLineArguments> getProjectFileArguments() +bool CommonOptionsParser::handleBoolOption(const QString &key, OptionSource source) { - QStringList arguments = QCoreApplication::arguments(); - QString appName = arguments.constFirst(); - arguments.removeFirst(); - - QString projectFileName; - for (const QString &arg : qAsConst(arguments)) { - if (arg.startsWith(QLatin1String("--project-file"))) { - int split = arg.indexOf(QLatin1Char('=')); - if (split > 0) - projectFileName = arg.mid(split + 1).trimmed(); - break; + if (source == OptionSource::CommandLineSingleDash) { + if (key == u"h") { + m_options->help = true; + return true; } + return false; } - if (projectFileName.isEmpty()) - return CommandLineArguments{}; - - if (!QFile::exists(projectFileName)) { - std::cerr << qPrintable(appName) << ": Project file \"" - << qPrintable(projectFileName) << "\" not found.\n"; - return {}; + if (key == u"version") { + m_options->version = true; + return true; } - - QFile projectFile(projectFileName); - if (!projectFile.open(QIODevice::ReadOnly)) { - std::cerr << qPrintable(appName) << ": Cannot open project file \"" - << qPrintable(projectFileName) << "\" : " << qPrintable(projectFile.errorString()) - << '\n'; - return {}; + if (key == u"help") { + m_options->help = true; + return true; } - return processProjectFile(appName, projectFile); -} - -static void getCommandLineArg(QString arg, int &argNum, CommandLineArguments &args) -{ - if (arg.startsWith(QLatin1String("--"))) { - arg.remove(0, 2); - const int split = arg.indexOf(QLatin1Char('=')); - if (split < 0) { - args.options.insert(arg, QString()); - return; - } - const QString option = arg.left(split); - const QString value = arg.mid(split + 1).trimmed(); - if (option == includePathOption() || option == frameworkIncludePathOption() - || option == systemIncludePathOption() || option == typesystemPathOption()) { - args.addToOptionsPathList(option, value); - } else if (option == apiVersionOption()) { - args.addToOptionsList(apiVersionOption(), value, apiVersionSplitter); - } else if (option == dropTypeEntriesOption()) { - args.addToOptionsList(dropTypeEntriesOption(), value, dropTypeEntriesSplitter); - } else if (option == clangOptionOption()) { - args.addToOptionsList(clangOptionsOption(), value); - } else if (option == clangOptionsOption()) { - args.addToOptionsList(clangOptionsOption(), value, clangOptionsSplitter); - } else { - args.options.insert(option, value); - } - return; + if (key == u"diff") { + FileOut::setDiff(true); + return true; } - if (arg.startsWith(QLatin1Char('-'))) { - arg.remove(0, 1); - if (arg.startsWith(QLatin1Char('I'))) // Shorthand path arguments -I/usr/include... - args.addToOptionsPathList(includePathOption(), arg.mid(1)); - else if (arg.startsWith(QLatin1Char('F'))) - args.addToOptionsPathList(frameworkIncludePathOption(), arg.mid(1)); - else if (arg.startsWith(QLatin1String("isystem"))) - args.addToOptionsPathList(systemIncludePathOption(), arg.mid(7)); - else if (arg.startsWith(QLatin1Char('T'))) - args.addToOptionsPathList(typesystemPathOption(), arg.mid(1)); - else if (arg == QLatin1String("h")) - args.options.insert(helpOption(), QString()); - else if (arg.startsWith(QLatin1String("std="))) - args.options.insert(languageLevelOption(), arg.mid(4)); - else - args.options.insert(arg, QString()); - return; + if (key == u"dry-run") { + FileOut::setDryRun(true); + return true; + } + if (key == u"silent") { + ReportHandler::setSilent(true); + return true; + } + if (key == u"log-unmatched") { + m_options->logUnmatched = true; + return true; + } + if (key == u"print-builtin-types") { + m_options->printBuiltinTypes = true; + return true; } - if (argNum < args.positionalArguments.size()) - args.positionalArguments[argNum] = arg; - else - args.positionalArguments.append(arg); - ++argNum; -} - -static void getCommandLineArgs(CommandLineArguments &args) -{ - const QStringList arguments = QCoreApplication::arguments(); - int argNum = 0; - for (int i = 1, size = arguments.size(); i < size; ++i) - getCommandLineArg(arguments.at(i).trimmed(), argNum, args); -} -static inline Generators docGenerators() -{ - Generators result; -#ifdef DOCSTRINGS_ENABLED - result.append(GeneratorPtr(new QtDocGenerator)); -#endif - return result; + return false; } -static inline Generators shibokenGenerators() +bool CommonOptionsParser::handleOption(const QString &key, const QString &value, + OptionSource source) { - Generators result; - result << GeneratorPtr(new CppGenerator) << GeneratorPtr(new HeaderGenerator); - return result; -} + if (source == OptionSource::CommandLineSingleDash) + return false; + + if (key == u"generator-set" || key == u"generatorSet" /* legacy */) { + m_options->generatorSet = value; + return true; + } + if (key == u"license-file") { + QFile licenseFile(value); + if (!licenseFile.open(QIODevice::ReadOnly)) + throw Exception(msgCannotOpenForReading(licenseFile)); + m_options->licenseComment = QString::fromUtf8(licenseFile.readAll()); + return true; + } + if (key == u"debug-level") { + if (!ReportHandler::setDebugLevelFromArg(value)) + throw Exception(u"Invalid debug level: "_s + value); + return true; + } + if (key == u"output-directory") { + m_options->outputDirectory = value; + return true; + } + if (key == u"compiler") { + if (!clang::setCompiler(value)) + throw Exception(u"Invalid value \""_s + value + u"\" passed to --compiler"_s); + return true; + } + if (key == u"compiler-path") { + clang::setCompilerPath(value); + return true; + } + if (key == u"platform") { + if (!clang::setPlatform(value)) + throw Exception(u"Invalid value \""_s + value + u"\" passed to --platform"_s); + return true; + } + + if (source == OptionSource::ProjectFile) { + if (key == u"header-file") { + m_options->headers.append(value); + return true; + } + if (key == u"typesystem-file") { + m_options->typeSystemFileName = value; + return true; + } + } -static inline QString languageLevelDescription() -{ - return QLatin1String("C++ Language level (c++11..c++17, default=") - + QLatin1String(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel())) - + QLatin1Char(')'); + return false; } void printUsage() { - const QChar pathSplitter = QDir::listSeparator(); + const auto generatorOptions = Generator::options(); + QTextStream s(stdout); s << "Usage:\n " - << "shiboken [options] header-file(s) typesystem-file\n\n" - << "General options:\n"; - QString pathSyntax; - QTextStream(&pathSyntax) << "<path>[" << pathSplitter << "<path>" - << pathSplitter << "...]"; - OptionDescriptions generalOptions = { - {QLatin1String("api-version=<\"package mask\">,<\"version\">"), - QLatin1String("Specify the supported api version used to generate the bindings")}, - {QLatin1String("debug-level=[sparse|medium|full]"), - QLatin1String("Set the debug level")}, - {QLatin1String("documentation-only"), - QLatin1String("Do not generates any code, just the documentation")}, - {QLatin1String("drop-type-entries=\"<TypeEntry0>[;TypeEntry1;...]\""), - QLatin1String("Semicolon separated list of type system entries (classes, namespaces,\n" - "global functions and enums) to be dropped from generation.")}, - {clangOptionOption(), - QLatin1String("Option to be passed to clang")}, - {clangOptionsOption(), - QLatin1String("A comma-separated list of options to be passed to clang")}, - {QLatin1String("-F<path>"), {} }, - {QLatin1String("framework-include-paths=") + pathSyntax, - QLatin1String("Framework include paths used by the C++ parser")}, - {QLatin1String("-isystem<path>"), {} }, - {QLatin1String("system-include-paths=") + pathSyntax, - QLatin1String("System include paths used by the C++ parser")}, - {QLatin1String("generator-set=<\"generator module\">"), - QLatin1String("generator-set to be used. e.g. qtdoc")}, - {skipDeprecatedOption(), - QLatin1String("Skip deprecated functions")}, - {diffOption(), QLatin1String("Print a diff of wrapper files")}, - {dryrunOption(), QLatin1String("Dry run, do not generate wrapper files")}, - {QLatin1String("-h"), {} }, - {helpOption(), QLatin1String("Display this help and exit")}, - {QLatin1String("-I<path>"), {} }, - {QLatin1String("include-paths=") + pathSyntax, - QLatin1String("Include paths used by the C++ parser")}, - {languageLevelOption() + QLatin1String("=, -std=<level>"), - languageLevelDescription()}, - {QLatin1String("license-file=<license-file>"), - QLatin1String("File used for copyright headers of generated files")}, - {QLatin1String("no-suppress-warnings"), - QLatin1String("Show all warnings")}, - {QLatin1String("output-directory=<path>"), - QLatin1String("The directory where the generated files will be written")}, - {QLatin1String("project-file=<file>"), - QLatin1String("text file containing a description of the binding project.\n" - "Replaces and overrides command line arguments")}, - {QLatin1String("silent"), QLatin1String("Avoid printing any message")}, - {QLatin1String("-T<path>"), {} }, - {QLatin1String("typesystem-paths=") + pathSyntax, - QLatin1String("Paths used when searching for typesystems")}, - {QLatin1String("version"), - QLatin1String("Output version information and exit")} - }; - printOptions(s, generalOptions); - - const Generators generators = shibokenGenerators() + docGenerators(); - for (const GeneratorPtr &generator : generators) { - const OptionDescriptions options = generator->options(); - if (!options.isEmpty()) { - s << Qt::endl << generator->name() << " options:\n\n"; - printOptions(s, generator->options()); - } - } + << "shiboken [options] header-file(s) typesystem-file\n\n" + << "General options:\n" + << CommonOptionsParser::optionDescriptions() + << ApiExtractor::options() + << TypeDatabase::options() + << "\nSource generator options:\n\n" << generatorOptions + << ShibokenGenerator::options(); + +#ifdef DOCSTRINGS_ENABLED + s << "\nDocumentation Generator options:\n\n" + << generatorOptions << QtDocGenerator::options(); +#endif } static inline void printVerAndBanner() { - std::cout << "shiboken v" SHIBOKEN_VERSION << std::endl; + std::cout << appName << " v" << SHIBOKEN_VERSION << std::endl; std::cout << "Copyright (C) 2016 The Qt Company Ltd." << std::endl; } -static inline void errorPrint(const QString &s) +static inline void errorPrint(const QString &s, const QStringList &arguments) { - QStringList arguments = QCoreApplication::arguments(); - arguments.pop_front(); - std::cerr << "shiboken: " << qPrintable(s) - << "\nCommand line: " << qPrintable(arguments.join(QLatin1Char(' '))) << '\n'; -} - -static void parseIncludePathOption(const QString &option, HeaderType headerType, - CommandLineArguments &args, - ApiExtractor &extractor) -{ - const auto it = args.options.find(option); - if (it != args.options.end()) { - const auto includePathListList = it.value().toStringList(); - args.options.erase(it); - for (const QString &s : includePathListList) { - auto path = QFile::encodeName(QDir::cleanPath(s)); - extractor.addIncludePath(HeaderPath{path, headerType}); - } - } + std::cerr << appName << ": " << qPrintable(s) << "\nCommand line:\n"; + for (const auto &argument : arguments) + std::cerr << " \"" << qPrintable(argument) << "\"\n"; } -int main(int argc, char *argv[]) +int shibokenMain(const QStringList &argV) { // PYSIDE-757: Request a deterministic ordering of QHash in the code model // and type system. - qSetGlobalQHashSeed(0); - // needed by qxmlpatterns - QCoreApplication app(argc, argv); + QHashSeed::setDeterministicGlobalSeed(); + ReportHandler::install(); if (ReportHandler::isDebug(ReportHandler::SparseDebug)) - qCInfo(lcShiboken()).noquote().nospace() << QCoreApplication::arguments().join(QLatin1Char(' ')); - - // Store command arguments in a map - const auto projectFileArgumentsOptional = getProjectFileArguments(); - if (!projectFileArgumentsOptional.has_value()) - return EXIT_FAILURE; + qCInfo(lcShiboken()).noquote().nospace() << appName << ' ' << argV.join(u' '); - const CommandLineArguments projectFileArguments = projectFileArgumentsOptional.value(); - CommandLineArguments args = projectFileArguments; - getCommandLineArgs(args); - Generators generators; + Options options; + options.setOptions(argV); - auto ait = args.options.find(QLatin1String("version")); - if (ait != args.options.end()) { - args.options.erase(ait); + CommonOptions commonOptions; + { + CommonOptionsParser parser(&commonOptions); + parser.process(&options); + } + if (commonOptions.version) { printVerAndBanner(); return EXIT_SUCCESS; } - - QString generatorSet; - ait = args.options.find(QLatin1String("generator-set")); - if (ait == args.options.end()) // Also check QLatin1String("generatorSet") command line argument for backward compatibility. - ait = args.options.find(QLatin1String("generatorSet")); - if (ait != args.options.end()) { - generatorSet = ait.value().toString(); - args.options.erase(ait); + if (commonOptions.help) { + printUsage(); + return EXIT_SUCCESS; } + Generators generators; + + OptionsParserList optionParser; + optionParser.append(Generator::createOptionsParser()); + optionParser.append(TypeDatabase::instance()->createOptionsParser()); + ApiExtractor extractor; + optionParser.append(extractor.createOptionsParser()); + // Pre-defined generator sets. - if (generatorSet == QLatin1String("qtdoc")) { + if (commonOptions.generatorSet == u"qtdoc") { generators = docGenerators(); if (generators.isEmpty()) { - errorPrint(QLatin1String("Doc strings extractions was not enabled in this shiboken build.")); + errorPrint(u"Doc strings extractions was not enabled in this shiboken build."_s, argV); return EXIT_FAILURE; } - } else if (generatorSet.isEmpty() || generatorSet == QLatin1String("shiboken")) { +#ifdef DOCSTRINGS_ENABLED + optionParser.append(QtDocGenerator::createOptionsParser()); +#endif + } else if (commonOptions.generatorSet.isEmpty() || commonOptions.generatorSet == u"shiboken") { generators = shibokenGenerators(); + optionParser.append(ShibokenGenerator::createOptionsParser()); } else { - errorPrint(QLatin1String("Unknown generator set, try \"shiboken\" or \"qtdoc\".")); + errorPrint(u"Unknown generator set, try \"shiboken\" or \"qtdoc\"."_s, argV); return EXIT_FAILURE; } - ait = args.options.find(QLatin1String("help")); - if (ait != args.options.end()) { - args.options.erase(ait); - printUsage(); - return EXIT_SUCCESS; - } - - ait = args.options.find(diffOption()); - if (ait != args.options.end()) { - args.options.erase(ait); - FileOut::diff = true; - } - - ait = args.options.find(dryrunOption()); - if (ait != args.options.end()) { - args.options.erase(ait); - FileOut::dummy = true; - } - - QString licenseComment; - ait = args.options.find(QLatin1String("license-file")); - if (ait != args.options.end()) { - QFile licenseFile(ait.value().toString()); - args.options.erase(ait); - if (licenseFile.open(QIODevice::ReadOnly)) { - licenseComment = QString::fromUtf8(licenseFile.readAll()); - } else { - errorPrint(QStringLiteral("Could not open the file \"%1\" containing the license heading: %2"). - arg(QDir::toNativeSeparators(licenseFile.fileName()), licenseFile.errorString())); - return EXIT_FAILURE; - } - } - - QString outputDirectory = QLatin1String("out"); - ait = args.options.find(QLatin1String("output-directory")); - if (ait != args.options.end()) { - outputDirectory = ait.value().toString(); - args.options.erase(ait); - } - - if (!QDir(outputDirectory).exists()) { - if (!QDir().mkpath(outputDirectory)) { + if (!QDir(commonOptions.outputDirectory).exists()) { + if (!QDir().mkpath(commonOptions.outputDirectory)) { qCWarning(lcShiboken).noquote().nospace() - << "Can't create output directory: " << QDir::toNativeSeparators(outputDirectory); + << "Can't create output directory: " + << QDir::toNativeSeparators(commonOptions.outputDirectory); return EXIT_FAILURE; } } // Create and set-up API Extractor - ApiExtractor extractor; - extractor.setLogDirectory(outputDirectory); - ait = args.options.find(skipDeprecatedOption()); - if (ait != args.options.end()) { - extractor.setSkipDeprecated(true); - args.options.erase(ait); - } - - ait = args.options.find(QLatin1String("silent")); - if (ait != args.options.end()) { - extractor.setSilent(true); - args.options.erase(ait); - } else { - ait = args.options.find(QLatin1String("debug-level")); - if (ait != args.options.end()) { - const QString value = ait.value().toString(); - if (!ReportHandler::setDebugLevelFromArg(value)) { - errorPrint(QLatin1String("Invalid debug level: ") + value); - return EXIT_FAILURE; - } - args.options.erase(ait); - } - } - ait = args.options.find(QLatin1String("no-suppress-warnings")); - if (ait != args.options.end()) { - args.options.erase(ait); - extractor.setSuppressWarnings(false); - } - ait = args.options.find(apiVersionOption()); - if (ait != args.options.end()) { - const QStringList &versions = ait.value().toStringList(); - args.options.erase(ait); - for (const QString &fullVersion : versions) { - QStringList parts = fullVersion.split(QLatin1Char(',')); - QString package; - QString version; - package = parts.count() == 1 ? QLatin1String("*") : parts.constFirst(); - version = parts.constLast(); - if (!extractor.setApiVersion(package, version)) { - errorPrint(msgInvalidVersion(package, version)); - return EXIT_FAILURE; - } + extractor.setLogDirectory(commonOptions.outputDirectory); + + if (commonOptions.typeSystemFileName.isEmpty() && commonOptions.headers.isEmpty()) { + if (options.positionalArguments.size() < 2) { + errorPrint(u"Insufficient positional arguments, specify header-file and typesystem-file."_s, + argV); + std::cout << '\n'; + printUsage(); + return EXIT_FAILURE; } - } - - ait = args.options.find(dropTypeEntriesOption()); - if (ait != args.options.end()) { - extractor.setDropTypeEntries(ait.value().toStringList()); - args.options.erase(ait); - } - - ait = args.options.find(typesystemPathOption()); - if (ait != args.options.end()) { - extractor.addTypesystemSearchPath(ait.value().toStringList()); - args.options.erase(ait); - } - - ait = args.options.find(clangOptionsOption()); - if (ait != args.options.end()) { - extractor.setClangOptions(ait.value().toStringList()); - args.options.erase(ait); - } - parseIncludePathOption(includePathOption(), HeaderType::Standard, - args, extractor); - parseIncludePathOption(frameworkIncludePathOption(), HeaderType::Framework, - args, extractor); - parseIncludePathOption(systemIncludePathOption(), HeaderType::System, - args, extractor); - - if (args.positionalArguments.size() < 2) { - errorPrint(QLatin1String("Insufficient positional arguments, specify header-file and typesystem-file.")); - std::cout << '\n'; - printUsage(); - return EXIT_FAILURE; + commonOptions.typeSystemFileName = options.positionalArguments.takeLast(); + commonOptions.headers = options.positionalArguments; } - const QString typeSystemFileName = args.positionalArguments.takeLast(); - QString messagePrefix = QFileInfo(typeSystemFileName).baseName(); - if (messagePrefix.startsWith(QLatin1String("typesystem_"))) + QString messagePrefix = QFileInfo(commonOptions.typeSystemFileName).baseName(); + if (messagePrefix.startsWith(u"typesystem_")) messagePrefix.remove(0, 11); - ReportHandler::setPrefix(QLatin1Char('(') + messagePrefix + QLatin1Char(')')); + ReportHandler::setPrefix(u'(' + messagePrefix + u')'); QFileInfoList cppFileNames; - for (const QString &cppFileName : qAsConst(args.positionalArguments)) { + for (const QString &cppFileName : std::as_const(commonOptions.headers)) { const QFileInfo cppFileNameFi(cppFileName); if (!cppFileNameFi.isFile() && !cppFileNameFi.isSymLink()) { - errorPrint(QLatin1Char('"') + cppFileName + QLatin1String("\" does not exist.")); + errorPrint(u'"' + cppFileName + u"\" does not exist."_s, argV); return EXIT_FAILURE; } cppFileNames.append(cppFileNameFi); } - // Pass option to all generators (Cpp/Header generator have the same options) - for (ait = args.options.begin(); ait != args.options.end(); ) { - bool found = false; - for (const GeneratorPtr &generator : qAsConst(generators)) - found |= generator->handleOption(ait.key(), ait.value().toString()); - if (found) - ait = args.options.erase(ait); - else - ++ait; - } - - ait = args.options.find(languageLevelOption()); - if (ait != args.options.end()) { - const QByteArray languageLevelBA = ait.value().toString().toLatin1(); - args.options.erase(ait); - const LanguageLevel level = clang::languageLevelFromOption(languageLevelBA.constData()); - if (level == LanguageLevel::Default) { - std::cout << "Invalid argument for language level: \"" - << languageLevelBA.constData() << "\"\n" << helpHint; - return EXIT_FAILURE; - } - extractor.setLanguageLevel(level); - } + optionParser.process(&options); + optionParser.clear(); - /* Make sure to remove the project file's arguments (if any) and - * --project-file, also the arguments of each generator before - * checking if there isn't any existing arguments in argsHandler. - */ - args.options.remove(QLatin1String("project-file")); - for (auto it = projectFileArguments.options.cbegin(), end = projectFileArguments.options.cend(); - it != end; ++it) { - args.options.remove(it.key()); - } - - if (!args.options.isEmpty()) { - errorPrint(msgLeftOverArguments(args.options)); + if (!options.boolOptions.isEmpty() || !options.valueOptions.isEmpty()) { + errorPrint(msgLeftOverArguments(options.msgUnprocessedOptions(), argV), argV); std::cout << helpHint; return EXIT_FAILURE; } - if (typeSystemFileName.isEmpty()) { + if (commonOptions.typeSystemFileName.isEmpty()) { std::cout << "You must specify a Type System file." << std::endl << helpHint; return EXIT_FAILURE; } extractor.setCppFileNames(cppFileNames); - extractor.setTypeSystem(typeSystemFileName); - - auto shibokenGenerator = dynamic_cast<const ShibokenGenerator *>(generators.constFirst().data()); - const bool usePySideExtensions = shibokenGenerator && shibokenGenerator->usePySideExtensions(); + extractor.setTypeSystem(commonOptions.typeSystemFileName); - const std::optional<ApiExtractorResult> apiOpt = extractor.run(usePySideExtensions); + ApiExtractorFlags apiExtractorFlags; + if (generators.constFirst()->usePySideExtensions()) + apiExtractorFlags.setFlag(ApiExtractorFlag::UsePySideExtensions); + if (generators.constFirst()->avoidProtectedHack()) + apiExtractorFlags.setFlag(ApiExtractorFlag::AvoidProtectedHack); + const std::optional<ApiExtractorResult> apiOpt = extractor.run(apiExtractorFlags); if (!apiOpt.has_value()) { - errorPrint(QLatin1String("Error running ApiExtractor.")); + errorPrint(u"Error running ApiExtractor."_s, argV); return EXIT_FAILURE; } @@ -681,21 +376,60 @@ int main(int argc, char *argv[]) << "\n\nType datase:\n" << *TypeDatabase::instance(); } - for (const GeneratorPtr &g : qAsConst(generators)) { - g->setOutputDirectory(outputDirectory); - g->setLicenseComment(licenseComment); - ReportHandler::startProgress(QByteArray("Running ") + g->name() + "..."); + if (commonOptions.printBuiltinTypes) + TypeDatabase::instance()->formatBuiltinTypes(qInfo()); + + for (const GeneratorPtr &g : std::as_const(generators)) { + g->setOutputDirectory(commonOptions.outputDirectory); + g->setLicenseComment(commonOptions.licenseComment); + ReportHandler::startProgress("Ran "_ba + g->name() + '.'); const bool ok = g->setup(apiOpt.value()) && g->generate(); ReportHandler::endProgress(); if (!ok) { - errorPrint(QLatin1String("Error running generator: ") - + QLatin1String(g->name()) + QLatin1Char('.')); + errorPrint(u"Error running generator: "_s + + QLatin1StringView(g->name()) + u'.', argV); return EXIT_FAILURE; } } + if (commonOptions.logUnmatched) + TypeDatabase::instance()->logUnmatched(); + const QByteArray doneMessage = ReportHandler::doneMessage(); std::cout << doneMessage.constData() << std::endl; return EXIT_SUCCESS; } + +#ifndef Q_OS_WIN + +static inline QString argvToString(const char *arg) +{ + return QString::fromLocal8Bit(arg); +} + +int main(int argc, char *argv[]) +#else + +static inline QString argvToString(const wchar_t *arg) +{ + return QString::fromWCharArray(arg); +} + +int wmain(int argc, wchar_t *argv[]) +#endif +{ + int ex = EXIT_SUCCESS; + + QStringList argV; + argV.reserve(argc - 1); + std::transform(argv + 1, argv + argc, std::back_inserter(argV), argvToString); + + try { + ex = shibokenMain(argV); + } catch (const std::exception &e) { + std::cerr << appName << " error: " << e.what() << std::endl; + ex = EXIT_FAILURE; + } + return ex; +} |