问题
I'd like to store some class info using Q_CLASSINFO macro. However I would like to wrap it in my own macro, for example:
#define DB_TABLE( TABLE ) \
Q_CLASSINFO( "db_table", #TABLE )
#define DB_FIELD( PROPERTY, COLUMN ) \
Q_CLASSINFO( "dbcol_" #PROPERTY, #COLUMN )
class Foo : public QObject
{
Q_OBJECT
DB_TABLE( some_table )
DB_FIELD( clientName, client_name )
}
Unfortunately, moc doesn't expand macros so the Q_CLASSINFO is not added.
I've tried to feed moc with already preprocessed source, but it failes on some included Qt classes.
Do you know any workaround for this?
回答1:
Other than rolling your own pre-moc preprocessor, no. That is what MeeGo Touch does, for example. Since Nokia themselves are doing it, I believe there is no other way.
In your case, it would only involve translating your own declarations into Q_CLASSINFO, so it shouldn't be too hard. If you use qmake, it can be added to the build sequence, too.
回答2:
The easy way to make that is modifing moc preprocessor.
- Go to Qt source code to qtbase/src/tools/moc e.g. (C:\Qt\Qt5.0.1\5.0.1\Src\qtbase\src\tools\moc)
- Create a new copy of moc project e.g. moc_modified
- Open the copy of moc project with QtCreator (moc.pro file)
- Open preprocessor.cpp file and go to Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file) function
Search the line:
// phase 1: get rid of backslash-newlines input = cleaned(input); // <- insert your code to modify input variable // input is a QByteArray object that contents the source code of .h file than moc is processing // I had created the replaceCustomMacros function, see next line replaceCustomMacros(input); ...
Compile the new source code. The moc executable file is generated to /bin folder (if you use windows look at c:/bin/moc.exe)
Go to Qt bin (C:\Qt\Qt5.0.1\5.0.1\msvc2010\bin) folder and rename moc executable file e.g. moc.exe.bak
Copy new moc executable file to Qt bin folder.
In your current app you need to create a Macro for example:
#ifndef Q_MOC_RUN #define DB_FIELD( PROPERTY, COLUMN ) #endif //or in my case #ifndef Q_MOC_RUN #define Q_SERVICE_INFO(method, path, type) #endif
Finally I let you my own source code of function replaceCustomMacros:
This function convert Q_SERVICE_INFO(method, path, type) macro to Q_CLASSINFO("srv://method", "type:path")
void Preprocessor::replaceCustomMacros(QByteArray &source)
{
QString str(QLatin1String(source.data()));
QString param_exp(QLatin1String("([^,\n]+)"));
QByteArray expression("Q_SERVICE_INFO\\s*\\(");
expression
.append(param_exp.toLatin1())
.append(",")
.append(param_exp.toLatin1())
.append("(,")
.append(param_exp.toLatin1())
.append(")?\\)");
QRegExp *reg_ex = new QRegExp(QLatin1String(expression));
int pos = -1, offset = -1, len = str.length();
while ((offset = reg_ex->lastIndexIn(str, pos)) != -1)
{
reg_ex->cap(1);
pos = -(len - offset) - 1;
QString capturedString = reg_ex->capturedTexts().at(0);
QString pattern = capturedString;
pattern.remove(0, pattern.indexOf(QLatin1String("(")) + 1);
pattern.remove(pattern.length() - 1, 1);
QStringList params = pattern.split(QLatin1String(","));
QString method = params.at(0).trimmed();
method = method.mid(1, method.length() - 2);
QString type;
if (params.length() < 3)
{
type.append(QLatin1String("GET"));
}
else
{
type = params.at(2).trimmed();
type = type.mid(1, type.length() - 2);
}
QString path = params.at(1).trimmed();
path = path.mid(1, path.length() - 2);
source.replace(offset, capturedString.length(), QString(QLatin1String("Q_CLASSINFO(\"srv://%1\",\"%2:%3\")")).arg(method, type, path).toLatin1());
}
delete reg_ex;
}
I have not found any specific solution on Internet then I have posted this solution.
Good Luck :)
来源:https://stackoverflow.com/questions/4119688/macro-expansion-in-moc