aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2023-09-13 12:44:50 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2023-09-20 14:55:46 +0200
commitef9f3b63b277642b6b93fe4fbc5de3b8f16214e1 (patch)
tree6c0b7ffb1ac9fded39b71dfb647ae2b10a1744b3
parentd249f2922bcbbca0169faabc5108db5999adaf54 (diff)
shiboken6: Introduce simple option struct
Add a struct Options to replace the struct CommandLineArguments from main.cpp with built-in handling of the project file. Port the generators over. Pick-to: 6.6 Change-Id: I3012d211761e7a43c709f2754e6846f008ff2b0d Reviewed-by: Shyamnath Premnadh <Shyamnath.Premnadh@qt.io>
-rw-r--r--sources/shiboken6/ApiExtractor/messages.cpp6
-rw-r--r--sources/shiboken6/ApiExtractor/messages.h2
-rw-r--r--sources/shiboken6/ApiExtractor/optionsparser.cpp148
-rw-r--r--sources/shiboken6/ApiExtractor/optionsparser.h35
-rw-r--r--sources/shiboken6/generator/main.cpp20
5 files changed, 196 insertions, 15 deletions
diff --git a/sources/shiboken6/ApiExtractor/messages.cpp b/sources/shiboken6/ApiExtractor/messages.cpp
index d1eb0e44a..0393fa3b3 100644
--- a/sources/shiboken6/ApiExtractor/messages.cpp
+++ b/sources/shiboken6/ApiExtractor/messages.cpp
@@ -947,3 +947,9 @@ QString msgUnknownArrayPointerConversion(const QString &s)
return u"Warning: Falling back to pointer conversion for unknown array type \""_s
+ s + u"\""_s;
}
+
+QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker)
+{
+ return u"First line of project file \""_s + QDir::toNativeSeparators(name)
+ + u"\" must be the string \""_s + QString::fromLatin1(startMarker) + u"\"."_s;
+}
diff --git a/sources/shiboken6/ApiExtractor/messages.h b/sources/shiboken6/ApiExtractor/messages.h
index a0bd94c55..93b9d10f1 100644
--- a/sources/shiboken6/ApiExtractor/messages.h
+++ b/sources/shiboken6/ApiExtractor/messages.h
@@ -251,4 +251,6 @@ QString msgMissingCustomConversion(const TypeEntryCPtr &t);
QString msgUnknownArrayPointerConversion(const QString &s);
+QString msgMissingProjectFileMarker(const QString &name, const QByteArray &startMarker);
+
#endif // MESSAGES_H
diff --git a/sources/shiboken6/ApiExtractor/optionsparser.cpp b/sources/shiboken6/ApiExtractor/optionsparser.cpp
index b41d13e7d..cf9f922aa 100644
--- a/sources/shiboken6/ApiExtractor/optionsparser.cpp
+++ b/sources/shiboken6/ApiExtractor/optionsparser.cpp
@@ -2,12 +2,94 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "optionsparser.h"
+#include "messages.h"
+#include "exception.h"
#include <QtCore/QDir>
#include <QtCore/QTextStream>
using namespace Qt::StringLiterals;
+template <class Stream> void formatBoolOption(Stream &s, const BoolOption &bo)
+{
+ switch (bo.source) {
+ case OptionSource::CommandLine:
+ s << "--";
+ break;
+ case OptionSource::CommandLineSingleDash:
+ s << '-';
+ break;
+ default:
+ break;
+ }
+ s << bo.option;
+ if (bo.source == OptionSource::ProjectFile)
+ s << " (project)";
+}
+
+template <class Stream> void formatOptionValue(Stream &s, const OptionValue &ov)
+{
+ switch (ov.source) {
+ case OptionSource::CommandLine:
+ s << "--";
+ break;
+ case OptionSource::CommandLineSingleDash:
+ s << '-';
+ break;
+ default:
+ break;
+ }
+ s << ov.option << '=' << ov.value;
+ if (ov.source == OptionSource::ProjectFile)
+ s << " (project)";
+}
+
+QTextStream &operator<<(QTextStream &s, const BoolOption &bo)
+{
+ formatBoolOption(s, bo);
+ return s;
+}
+
+QTextStream &operator<<(QTextStream &s, const OptionValue &ov)
+{
+ formatOptionValue(s, ov);
+ return s;
+}
+
+QDebug operator<<(QDebug debug, const BoolOption &bo)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ formatBoolOption(debug, bo);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const OptionValue &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ formatOptionValue(debug, v);
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const Options &v)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "Options(";
+ if (!v.boolOptions.isEmpty())
+ debug << "bools=" << v.boolOptions;
+ if (!v.valueOptions.isEmpty())
+ debug << ", option values=" << v.valueOptions;
+ if (!v.positionalArguments.isEmpty())
+ debug << ", pos=" << v.positionalArguments;
+ debug << ')';
+ return debug;
+}
+
QTextStream &operator<<(QTextStream &s, const OptionDescription &od)
{
if (!od.name.startsWith(u'-'))
@@ -54,6 +136,20 @@ bool OptionsParser::handleOption(const QString &, const QString &, OptionSource)
return false;
}
+void OptionsParser::process(Options *o)
+{
+ for (auto i = o->boolOptions.size() - 1; i >= 0; --i) {
+ const auto &opt = o->boolOptions.at(i);
+ if (handleBoolOption(opt.option, opt.source))
+ o->boolOptions.removeAt(i);
+ }
+ for (auto i = o->valueOptions.size() - 1; i >= 0; --i) {
+ const auto &opt = o->valueOptions.at(i);
+ if (handleOption(opt.option, opt.value, opt.source))
+ o->valueOptions.removeAt(i);
+ }
+}
+
bool OptionsParserList::handleBoolOption(const QString &key, OptionSource source)
{
for (const auto &p : std::as_const(m_parsers)) {
@@ -71,3 +167,55 @@ bool OptionsParserList::handleOption(const QString &key, const QString &value, O
}
return false;
}
+
+static void processOption(const QString &o, OptionSource source,
+ BoolOptions *bools, OptionValues *values)
+{
+ const auto equals = o.indexOf(u'=');
+ if (equals == -1) {
+ bools->append({o.trimmed(), source});
+ } else {
+ QString key = o.left(equals).trimmed();
+ QString value = o.mid(equals + 1).trimmed();
+ if (!value.isEmpty())
+ values->append({key, value, source});
+ }
+}
+
+static void readProjectFile(const QString &name, Options *o)
+{
+ const auto startMarker = "[generator-project]"_ba;
+
+ QFile file(name);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ throw Exception(msgCannotOpenForReading(file));
+
+ if (file.atEnd() || file.readLine().trimmed() != startMarker)
+ throw Exception(msgMissingProjectFileMarker(name, startMarker));
+
+ while (!file.atEnd()) {
+ const QByteArray lineB = file.readLine().trimmed();
+ if (!lineB.isEmpty() && !lineB.startsWith('#')) {
+ processOption(QString::fromUtf8(lineB), OptionSource::ProjectFile,
+ &o->boolOptions, &o->valueOptions);
+ }
+ }
+}
+
+void Options::setOptions(const QStringList &argv)
+{
+ const auto projectFileOption = "--project-file="_L1;
+ for (const auto &o : argv) {
+ if (o.startsWith(projectFileOption)) {
+ readProjectFile(o.sliced(projectFileOption.size()), this);
+ } else if (o.startsWith(u"--")) {
+ processOption(o.sliced(2), OptionSource::CommandLine,
+ &boolOptions, &valueOptions);
+ } else if (o.startsWith(u'-')) {
+ processOption(o.sliced(1), OptionSource::CommandLineSingleDash,
+ &boolOptions, &valueOptions);
+ } else {
+ positionalArguments.append(o);
+ }
+ }
+}
diff --git a/sources/shiboken6/ApiExtractor/optionsparser.h b/sources/shiboken6/ApiExtractor/optionsparser.h
index 7ce33f5ba..f184c9bd2 100644
--- a/sources/shiboken6/ApiExtractor/optionsparser.h
+++ b/sources/shiboken6/ApiExtractor/optionsparser.h
@@ -5,7 +5,7 @@
#define OPTIONSPARSER_H
#include <QtCore/QString>
-#include <QtCore/QList>
+#include <QtCore/QStringList>
#include <memory>
@@ -18,6 +18,31 @@ enum class OptionSource
ProjectFile
};
+struct BoolOption
+{
+ QString option;
+ OptionSource source = OptionSource::CommandLine;
+};
+
+struct OptionValue // --option=value pair
+{
+ QString option;
+ QString value;
+ OptionSource source = OptionSource::CommandLine;
+};
+
+using BoolOptions = QList<BoolOption>;
+using OptionValues = QList<OptionValue>;
+
+struct Options // Options from command line and project file
+{
+ void setOptions(const QStringList &argv);
+
+ BoolOptions boolOptions;
+ OptionValues valueOptions;
+ QStringList positionalArguments;
+};
+
struct OptionDescription // For help formatting
{
QString name;
@@ -26,6 +51,8 @@ struct OptionDescription // For help formatting
using OptionDescriptions = QList<OptionDescription>;
+QTextStream &operator<<(QTextStream &s, const BoolOption &bo);
+QTextStream &operator<<(QTextStream &s, const OptionValue &ov);
QTextStream &operator<<(QTextStream &s, const OptionDescription &od);
QTextStream &operator<<(QTextStream &s, const OptionDescriptions &options);
@@ -40,6 +67,8 @@ public:
virtual bool handleBoolOption(const QString &key, OptionSource source);
virtual bool handleOption(const QString &key, const QString &value, OptionSource source);
+ void process(Options *);
+
static const QString &pathSyntax();
protected:
@@ -61,4 +90,8 @@ private:
QList<OptionsParserPtr> m_parsers;
};
+QDebug operator<<(QDebug debug, const BoolOption &bo);
+QDebug operator<<(QDebug debug, const OptionValue &v);
+QDebug operator<<(QDebug debug, const Options &v);
+
#endif // OPTIONSPARSER_H
diff --git a/sources/shiboken6/generator/main.cpp b/sources/shiboken6/generator/main.cpp
index 8510c471e..73e7e9bde 100644
--- a/sources/shiboken6/generator/main.cpp
+++ b/sources/shiboken6/generator/main.cpp
@@ -419,6 +419,9 @@ int shibokenMain(const QStringList &argV)
if (ReportHandler::isDebug(ReportHandler::SparseDebug))
qCInfo(lcShiboken()).noquote().nospace() << appName << ' ' << argV.join(u' ');
+ Options options;
+ options.setOptions(argV);
+
// Store command arguments in a map
const auto projectFileArgumentsOptional = getProjectFileArguments(argV);
if (!projectFileArgumentsOptional.has_value())
@@ -657,20 +660,7 @@ int shibokenMain(const QStringList &argV)
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;
- if (ait.value().metaType().id() == QMetaType::QString) {
- const QString value = ait.value().toString();
- found |= value.isEmpty()
- ? optionParser.handleBoolOption(ait.key(), OptionSource::CommandLine)
- : optionParser.handleOption(ait.key(), value, OptionSource::CommandLine);
- }
- if (found)
- ait = args.options.erase(ait);
- else
- ++ait;
- }
+ optionParser.process(&options);
optionParser.clear();
ait = args.options.find(languageLevelOption());
@@ -696,11 +686,13 @@ int shibokenMain(const QStringList &argV)
args.options.remove(it.key());
}
+ /* FIXME: re-activate check
if (!args.options.isEmpty()) {
errorPrint(msgLeftOverArguments(args.options, argV), argV);
std::cout << helpHint;
return EXIT_FAILURE;
}
+ */
if (typeSystemFileName.isEmpty()) {
std::cout << "You must specify a Type System file." << std::endl << helpHint;