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>
This commit is contained in:
parent
4ff6951550
commit
b508dc98a5
@ -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;
|
||||
}
|
||||
|
||||
|
||||
int runMoc(int _argc, char **_argv)
|
||||
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)
|
||||
{
|
||||
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();
|
||||
// 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();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
QCommandLineOption outputOption(QStringLiteral("o"));
|
||||
outputOption.setDescription(QStringLiteral("Write output to file rather than stdout."));
|
||||
outputOption.setValueName(QStringLiteral("file"));
|
||||
parser.addOption(outputOption);
|
||||
|
||||
argc = argv.count();
|
||||
QCommandLineOption includePathOption(QStringLiteral("I"));
|
||||
includePathOption.setDescription(QStringLiteral("Add dir to the include path for header files."));
|
||||
includePathOption.setValueName(QStringLiteral("dir"));
|
||||
parser.addOption(includePathOption);
|
||||
|
||||
for (int n = 0; n < argc; ++n) {
|
||||
QByteArray arg(argv[n]);
|
||||
if (arg[0] != '-') {
|
||||
if (filename.isEmpty()) {
|
||||
filename = arg;
|
||||
continue;
|
||||
}
|
||||
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();
|
||||
}
|
||||
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();
|
||||
|
||||
const bool ignoreConflictingOptions = parser.isSet(ignoreConflictsOption);
|
||||
output = parser.value(outputOption);
|
||||
pp.preprocessOnly = parser.isSet(preprocessOption);
|
||||
if (parser.isSet(noIncludeOption)) {
|
||||
moc.noInclude = true;
|
||||
autoInclude = false;
|
||||
break;
|
||||
case 'f': // produce #include statement
|
||||
if (ignoreConflictingOptions)
|
||||
break;
|
||||
}
|
||||
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);
|
||||
foreach (const QString &include, parser.values(prependIncludeOption))
|
||||
moc.includeFiles.prepend(QFile::encodeName(include));
|
||||
if (parser.isSet(pathPrefixOption))
|
||||
moc.includePath = QFile::encodeName(parser.value(pathPrefixOption));
|
||||
}
|
||||
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));
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 'D': // define macro
|
||||
{
|
||||
QByteArray name;
|
||||
foreach (const QString &arg, parser.values(defineOption)) {
|
||||
QByteArray name = arg.toLocal8Bit();
|
||||
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())
|
||||
if (name.isEmpty()) {
|
||||
error("Missing macro name");
|
||||
parser.showHelp(1);
|
||||
}
|
||||
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())
|
||||
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);
|
||||
|
||||
}
|
||||
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")
|
||||
const QStringList noNotesCompatValues = parser.values(noNotesWarningsCompatOption);
|
||||
if (parser.isSet(noNotesOption) || noNotesCompatValues.contains(QStringLiteral("n")))
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user