summaryrefslogtreecommitdiffstats
path: root/src/tools/moc
diff options
context:
space:
mode:
authorDavid Faure <faure@kde.org>2013-07-24 14:07:39 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-10 19:06:56 +0200
commitb508dc98a5085df6ea44b154177fbb6d8b0e8434 (patch)
tree6571128dac8b907e64aff57ded1d19e082e2c247 /src/tools/moc
parent4ff6951550cb6e39c3b31895c3af57037e90c9ac (diff)
Port moc to QCommandLineParser
This required special care because of @option-file where additional args can be read from. Found again one undocumented option, --ignore-option-clashes. Usage: moc [options] [header-file] [@option-file] Qt Meta Object Compiler version 67 (Qt 5.2.0) Options: -h, --help Displays this help. -v, --version Displays version information. -o <file> Write output to file rather than stdout. -I <dir> Add dir to the include path for header files. -F <framework> Add Mac framework to the include path for header fil es. -E Preprocess only; do not generate meta object code. -D <macro[=def]> Define macro, with optional definition. -U <macro> Undefine macro. -i Do not generate an #include statement. -p <path> Path prefix for included file. -f <file> Force #include [optional <file>] (overwrite default) . -b <file> Prepend #include <file> (preserve default include). -n <which> Do not display notes (-nn) or warnings (-nw). Compat ibility option. --no-notes Do not display notes. --no-warnings Do not display warnings (implies --no-notes). --ignore-option-clashes Ignore all options that conflict with compilers, lik e -pthread conflicting with moc's -p option. Arguments: [header-file] Header file to read from, otherwise stdin. [@option-file] Read additional options from option-file. Change-Id: I0dfa8e029f95ad8084832530d701e30f315df98e Reviewed-by: Olivier Goffart <ogoffart@woboq.com> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/tools/moc')
-rw-r--r--src/tools/moc/main.cpp420
-rw-r--r--src/tools/moc/preprocessor.cpp7
-rw-r--r--src/tools/moc/preprocessor.h1
3 files changed, 202 insertions, 226 deletions
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index 431c8dd46c..d5218571f5 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -50,6 +50,10 @@
#include <stdlib.h>
#include <ctype.h>
+#include <qcoreapplication.h>
+#include <qcommandlineoption.h>
+#include <qcommandlineparser.h>
+
QT_BEGIN_NAMESPACE
/*
@@ -63,10 +67,10 @@ QT_BEGIN_NAMESPACE
/tmp/abc, xyz/klm -> /tmp/abc
*/
-static QByteArray combinePath(const QByteArray &infile, const QByteArray &outfile)
+static QByteArray combinePath(const QString &infile, const QString &outfile)
{
- QFileInfo inFileInfo(QDir::current(), QFile::decodeName(infile));
- QFileInfo outFileInfo(QDir::current(), QFile::decodeName(outfile));
+ QFileInfo inFileInfo(QDir::current(), infile);
+ QFileInfo outFileInfo(QDir::current(), outfile);
const QByteArray relativePath = QFile::encodeName(outFileInfo.dir().relativeFilePath(inFileInfo.filePath()));
#ifdef Q_OS_WIN
// It's a system limitation.
@@ -83,21 +87,6 @@ void error(const char *msg = "Invalid argument")
{
if (msg)
fprintf(stderr, "moc: %s\n", msg);
- fprintf(stderr, "Usage: moc [options] <header-file>\n"
- " -o<file> write output to file rather than stdout\n"
- " -I<dir> add dir to the include path for header files\n"
- " -E preprocess only; do not generate meta object code\n"
- " -D<macro>[=<def>] define macro, with optional definition\n"
- " -U<macro> undefine macro\n"
- " -i do not generate an #include statement\n"
- " -p<path> path prefix for included file\n"
- " -f[<file>] force #include, optional file name (overwrite default)\n"
- " -b<file> prepend #include <file> (preserve default include)\n"
- " -nn do not display notes\n"
- " -nw do not display warnings\n"
- " @<file> read additional options from file\n"
- " -v display version of moc\n");
- exit(1);
}
@@ -161,9 +150,43 @@ QByteArray composePreprocessorOutput(const Symbols &symbols) {
return output;
}
+static QStringList argumentsFromCommandLineAndFile(const QStringList &arguments)
+{
+ QStringList allArguments = arguments;
+ int n = 0;
+ while (n < allArguments.count()) {
+ // "@file" doesn't start with a '-' so we can't use QCommandLineParser for it
+ if (arguments.at(n).startsWith(QLatin1Char('@'))) {
+ QString optionsFile = arguments.at(n);
+ optionsFile.remove(0, 1);
+ if (optionsFile.isEmpty()) {
+ error("The @ option requires an input file");
+ return QStringList();
+ }
+ QFile f(optionsFile);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ error("Cannot open options file specified with @");
+ return QStringList();
+ }
+ allArguments.removeAt(n);
+ while (!f.atEnd()) {
+ QString line = QString::fromLocal8Bit(f.readLine().trimmed());
+ if (!line.isEmpty())
+ allArguments.insert(n++, line);
+ }
+ } else {
+ ++n;
+ }
+ }
+ return allArguments;
+}
+
-int runMoc(int _argc, char **_argv)
+int runMoc(int argc, char **argv)
{
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_VERSION_STR));
+
bool autoInclude = true;
bool defaultInclude = true;
Preprocessor pp;
@@ -178,199 +201,165 @@ int runMoc(int _argc, char **_argv)
dummyVariadicFunctionMacro.arguments += Symbol(0, PP_IDENTIFIER, "__VA_ARGS__");
pp.macros["__attribute__"] = dummyVariadicFunctionMacro;
- QByteArray filename;
- QByteArray output;
- FILE *in = 0;
+ QString filename;
+ QString output;
+ QFile in;
FILE *out = 0;
- bool ignoreConflictingOptions = false;
-
- QVector<QByteArray> argv;
- argv.resize(_argc - 1);
- for (int n = 1; n < _argc; ++n)
- argv[n - 1] = _argv[n];
- int argc = argv.count();
- for (int n = 0; n < argv.count(); ++n) {
- if (argv.at(n).startsWith('@')) {
- QByteArray optionsFile = argv.at(n);
- optionsFile.remove(0, 1);
- if (optionsFile.isEmpty())
- error("The @ option requires an input file");
- QFile f(QString::fromLatin1(optionsFile.constData()));
- if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
- error("Cannot open options file specified with @");
- argv.remove(n);
- while (!f.atEnd()) {
- QByteArray line = f.readLine().trimmed();
- if (!line.isEmpty())
- argv.insert(n++, line);
- }
- }
+ // Note that moc isn't translated.
+ // If you use this code as an example for a translated app, make sure to translate the strings.
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QStringLiteral("Qt Meta Object Compiler version %1 (Qt %2)")
+ .arg(mocOutputRevision).arg(QString::fromLatin1(QT_VERSION_STR)));
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ QCommandLineOption outputOption(QStringLiteral("o"));
+ outputOption.setDescription(QStringLiteral("Write output to file rather than stdout."));
+ outputOption.setValueName(QStringLiteral("file"));
+ parser.addOption(outputOption);
+
+ QCommandLineOption includePathOption(QStringLiteral("I"));
+ includePathOption.setDescription(QStringLiteral("Add dir to the include path for header files."));
+ includePathOption.setValueName(QStringLiteral("dir"));
+ parser.addOption(includePathOption);
+
+ QCommandLineOption macFrameworkOption(QStringLiteral("F"));
+ macFrameworkOption.setDescription(QStringLiteral("Add Mac framework to the include path for header files."));
+ macFrameworkOption.setValueName(QStringLiteral("framework"));
+ parser.addOption(macFrameworkOption);
+
+ QCommandLineOption preprocessOption(QStringLiteral("E"));
+ preprocessOption.setDescription(QStringLiteral("Preprocess only; do not generate meta object code."));
+ parser.addOption(preprocessOption);
+
+ QCommandLineOption defineOption(QStringLiteral("D"));
+ defineOption.setDescription(QStringLiteral("Define macro, with optional definition."));
+ defineOption.setValueName(QStringLiteral("macro[=def]"));
+ parser.addOption(defineOption);
+
+ QCommandLineOption undefineOption(QStringLiteral("U"));
+ undefineOption.setDescription(QStringLiteral("Undefine macro."));
+ undefineOption.setValueName(QStringLiteral("macro"));
+ parser.addOption(undefineOption);
+
+ QCommandLineOption noIncludeOption(QStringLiteral("i"));
+ noIncludeOption.setDescription(QStringLiteral("Do not generate an #include statement."));
+ parser.addOption(noIncludeOption);
+
+ QCommandLineOption pathPrefixOption(QStringLiteral("p"));
+ pathPrefixOption.setDescription(QStringLiteral("Path prefix for included file."));
+ pathPrefixOption.setValueName(QStringLiteral("path"));
+ parser.addOption(pathPrefixOption);
+
+ QCommandLineOption forceIncludeOption(QStringLiteral("f"));
+ forceIncludeOption.setDescription(QStringLiteral("Force #include [optional <file>] (overwrite default)."));
+ forceIncludeOption.setValueName(QStringLiteral("file"));
+ parser.addOption(forceIncludeOption);
+
+ QCommandLineOption prependIncludeOption(QStringLiteral("b"));
+ prependIncludeOption.setDescription(QStringLiteral("Prepend #include <file> (preserve default include)."));
+ prependIncludeOption.setValueName(QStringLiteral("file"));
+ parser.addOption(prependIncludeOption);
+
+ QCommandLineOption noNotesWarningsCompatOption(QStringLiteral("n"));
+ noNotesWarningsCompatOption.setDescription(QStringLiteral("Do not display notes (-nn) or warnings (-nw). Compatibility option."));
+ noNotesWarningsCompatOption.setValueName(QStringLiteral("which"));
+ parser.addOption(noNotesWarningsCompatOption);
+
+ QCommandLineOption noNotesOption(QStringLiteral("no-notes"));
+ noNotesOption.setDescription(QStringLiteral("Do not display notes."));
+ parser.addOption(noNotesOption);
+
+ QCommandLineOption noWarningsOption(QStringLiteral("no-warnings"));
+ noWarningsOption.setDescription(QStringLiteral("Do not display warnings (implies --no-notes)."));
+ parser.addOption(noWarningsOption);
+
+ QCommandLineOption ignoreConflictsOption(QStringLiteral("ignore-option-clashes"));
+ ignoreConflictsOption.setDescription(QStringLiteral("Ignore all options that conflict with compilers, like -pthread conflicting with moc's -p option."));
+ parser.addOption(ignoreConflictsOption);
+
+ parser.addPositionalArgument(QStringLiteral("[header-file]"),
+ QStringLiteral("Header file to read from, otherwise stdin."));
+ parser.addPositionalArgument(QStringLiteral("[@option-file]"),
+ QStringLiteral("Read additional options from option-file."));
+
+ const QStringList arguments = argumentsFromCommandLineAndFile(app.arguments());
+
+ parser.process(arguments);
+
+ const QStringList files = parser.positionalArguments();
+ if (files.count() > 1) {
+ error("Too many input files specified");
+ parser.showHelp(1);
+ } else if (!files.isEmpty()) {
+ filename = files.first();
}
- argc = argv.count();
-
- for (int n = 0; n < argc; ++n) {
- QByteArray arg(argv[n]);
- if (arg[0] != '-') {
- if (filename.isEmpty()) {
- filename = arg;
- continue;
- }
- error("Too many input files specified");
- }
- QByteArray opt = arg.mid(1);
- bool more = (opt.size() > 1);
- switch (opt[0]) {
- case 'o': // output redirection
- if (!more) {
- if (!(n < argc-1))
- error("Missing output file name");
- output = argv[++n];
- } else
- output = opt.mid(1);
- break;
- case 'E': // only preprocessor
- pp.preprocessOnly = true;
- break;
- case 'i': // no #include statement
- if (more)
- error();
- moc.noInclude = true;
- autoInclude = false;
- break;
- case 'f': // produce #include statement
- if (ignoreConflictingOptions)
- break;
- moc.noInclude = false;
+ const bool ignoreConflictingOptions = parser.isSet(ignoreConflictsOption);
+ output = parser.value(outputOption);
+ pp.preprocessOnly = parser.isSet(preprocessOption);
+ if (parser.isSet(noIncludeOption)) {
+ moc.noInclude = true;
+ autoInclude = false;
+ }
+ if (!ignoreConflictingOptions) {
+ if (parser.isSet(forceIncludeOption)) {
+ moc.noInclude = false;
autoInclude = false;
- if (opt[1]) { // -fsomething.h
- moc.includeFiles.append(opt.mid(1));
+ foreach (const QString &include, parser.values(forceIncludeOption)) {
+ moc.includeFiles.append(QFile::encodeName(include));
defaultInclude = false;
- }
- break;
- case 'b':
- if (ignoreConflictingOptions)
- break;
- if (!more) {
- if (!(n < argc-1))
- error("Missing file name for the -b option.");
- moc.includeFiles.prepend(argv[++n]);
- } else if (opt[1]) {
- moc.includeFiles.prepend(opt.mid(1));
- }
- break;
- case 'p': // include file path
- if (ignoreConflictingOptions)
- break;
- if (!more) {
- if (!(n < argc-1))
- error("Missing path name for the -p option.");
- moc.includePath = argv[++n];
- } else {
- moc.includePath = opt.mid(1);
- }
- break;
- case 'I': // produce #include statement
- if (!more) {
- if (!(n < argc-1))
- error("Missing path name for the -I option.");
- pp.includes += Preprocessor::IncludePath(argv[++n]);
- } else {
- pp.includes += Preprocessor::IncludePath(opt.mid(1));
- }
- break;
- case 'F': // minimalistic framework support for the mac
- if (!more) {
- if (!(n < argc-1))
- error("Missing path name for the -F option.");
- Preprocessor::IncludePath p(argv[++n]);
- p.isFrameworkPath = true;
- pp.includes += p;
- } else {
- Preprocessor::IncludePath p(opt.mid(1));
- p.isFrameworkPath = true;
- pp.includes += p;
- }
- break;
- case 'D': // define macro
- {
- QByteArray name;
- QByteArray value("1");
- if (!more) {
- if (n < argc-1)
- name = argv[++n];
- } else
- name = opt.mid(1);
- int eq = name.indexOf('=');
- if (eq >= 0) {
- value = name.mid(eq + 1);
- name = name.left(eq);
- }
- if (name.isEmpty())
- error("Missing macro name");
- Macro macro;
- macro.symbols += Symbol(0, PP_IDENTIFIER, value);
- pp.macros.insert(name, macro);
-
- }
- break;
- case 'U':
- {
- QByteArray macro;
- if (!more) {
- if (n < argc-1)
- macro = argv[++n];
- } else
- macro = opt.mid(1);
- if (macro.isEmpty())
- error("Missing macro name");
- pp.macros.remove(macro);
-
- }
- break;
- case 'v': // version number
- if (more && opt != "version")
- error();
- fprintf(stderr, "Qt Meta Object Compiler version %d (Qt %s)\n",
- mocOutputRevision, QT_VERSION_STR);
- return 1;
- case 'n': // don't display warnings
- if (ignoreConflictingOptions)
- break;
- if (opt == "nw")
- moc.displayWarnings = moc.displayNotes = false;
- else if (opt == "nn")
- moc.displayNotes = false;
- else
- error();
- break;
- case 'h': // help
- if (more && opt != "help")
- error();
- else
- error(0); // 0 means usage only
- break;
- case '-':
- if (more && arg == "--ignore-option-clashes") {
- // -- ignore all following moc specific options that conflict
- // with for example gcc, like -pthread conflicting with moc's
- // -p option.
- ignoreConflictingOptions = true;
- break;
- }
- // fall through
- default:
- error();
+ }
}
+ foreach (const QString &include, parser.values(prependIncludeOption))
+ moc.includeFiles.prepend(QFile::encodeName(include));
+ if (parser.isSet(pathPrefixOption))
+ moc.includePath = QFile::encodeName(parser.value(pathPrefixOption));
}
-
+ foreach (const QString &path, parser.values(includePathOption))
+ pp.includes += Preprocessor::IncludePath(QFile::encodeName(path));
+ foreach (const QString &path, parser.values(macFrameworkOption)) {
+ // minimalistic framework support for the mac
+ Preprocessor::IncludePath p(QFile::encodeName(path));
+ p.isFrameworkPath = true;
+ pp.includes += p;
+ }
+ foreach (const QString &arg, parser.values(defineOption)) {
+ QByteArray name = arg.toLocal8Bit();
+ QByteArray value("1");
+ int eq = name.indexOf('=');
+ if (eq >= 0) {
+ value = name.mid(eq + 1);
+ name = name.left(eq);
+ }
+ if (name.isEmpty()) {
+ error("Missing macro name");
+ parser.showHelp(1);
+ }
+ Macro macro;
+ macro.symbols += Symbol(0, PP_IDENTIFIER, value);
+ pp.macros.insert(name, macro);
+ }
+ foreach (const QString &arg, parser.values(undefineOption)) {
+ QByteArray macro = arg.toLocal8Bit();
+ if (macro.isEmpty()) {
+ error("Missing macro name");
+ parser.showHelp(1);
+ }
+ pp.macros.remove(macro);
+ }
+ const QStringList noNotesCompatValues = parser.values(noNotesWarningsCompatOption);
+ if (parser.isSet(noNotesOption) || noNotesCompatValues.contains(QStringLiteral("n")))
+ moc.displayNotes = false;
+ if (parser.isSet(noWarningsOption) || noNotesCompatValues.contains(QStringLiteral("w")))
+ moc.displayWarnings = moc.displayNotes = false;
if (autoInclude) {
- int spos = filename.lastIndexOf(QDir::separator().toLatin1());
- int ppos = filename.lastIndexOf('.');
+ int spos = filename.lastIndexOf(QDir::separator());
+ int ppos = filename.lastIndexOf(QLatin1Char('.'));
// spos >= -1 && ppos > spos => ppos >= 0
- moc.noInclude = (ppos > spos && tolower(filename[ppos + 1]) != 'h');
+ moc.noInclude = (ppos > spos && filename[ppos + 1].toLower() != QLatin1Char('h'));
}
if (defaultInclude) {
if (moc.includePath.isEmpty()) {
@@ -378,7 +367,7 @@ int runMoc(int _argc, char **_argv)
if (output.size())
moc.includeFiles.append(combinePath(filename, output));
else
- moc.includeFiles.append(filename);
+ moc.includeFiles.append(QFile::encodeName(filename));
}
} else {
moc.includeFiles.append(combinePath(filename, filename));
@@ -386,27 +375,22 @@ int runMoc(int _argc, char **_argv)
}
if (filename.isEmpty()) {
- filename = "standard input";
- in = stdin;
+ filename = QStringLiteral("standard input");
+ in.open(stdin, QIODevice::ReadOnly);
} else {
-#if defined(_MSC_VER) && _MSC_VER >= 1400
- if (fopen_s(&in, filename.data(), "rb")) {
-#else
- in = fopen(filename.data(), "rb");
- if (!in) {
-#endif
- fprintf(stderr, "moc: %s: No such file\n", filename.constData());
+ in.setFileName(filename);
+ if (!in.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, "moc: %s: No such file\n", qPrintable(filename));
return 1;
}
- moc.filename = filename;
+ moc.filename = filename.toLocal8Bit();
}
- moc.currentFilenames.push(filename);
+ moc.currentFilenames.push(filename.toLocal8Bit());
moc.includes = pp.includes;
// 1. preprocess
- moc.symbols = pp.preprocessed(moc.filename, in);
- fclose(in);
+ moc.symbols = pp.preprocessed(moc.filename, &in);
if (!pp.preprocessOnly) {
// 2. parse
@@ -417,13 +401,13 @@ int runMoc(int _argc, char **_argv)
if (output.size()) { // output file specified
#if defined(_MSC_VER) && _MSC_VER >= 1400
- if (fopen_s(&out, output.data(), "w"))
+ if (fopen_s(&out, QFile::encodeName(output).constData(), "w"))
#else
- out = fopen(output.data(), "w"); // create output file
+ out = fopen(QFile::encodeName(output).constData(), "w"); // create output file
if (!out)
#endif
{
- fprintf(stderr, "moc: Cannot create %s\n", output.constData());
+ fprintf(stderr, "moc: Cannot create %s\n", QFile::encodeName(output).constData());
return 1;
}
} else { // use stdout
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 06758e67bd..3615262b67 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -1172,13 +1172,6 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
currentFilenames.pop();
}
-Symbols Preprocessor::preprocessed(const QByteArray &filename, FILE *file)
-{
- QFile qfile;
- qfile.open(file, QFile::ReadOnly);
- return preprocessed(filename, &qfile);
-}
-
Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file)
{
QByteArray input = file->readAll();
diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h
index 72d02a3292..dc7c98de85 100644
--- a/src/tools/moc/preprocessor.h
+++ b/src/tools/moc/preprocessor.h
@@ -75,7 +75,6 @@ public:
QList<QByteArray> frameworks;
QSet<QByteArray> preprocessedIncludes;
Macros macros;
- Symbols preprocessed(const QByteArray &filename, FILE *file);
Symbols preprocessed(const QByteArray &filename, QIODevice *device);
void parseDefineArguments(Macro *m);