Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
877 views
in Technique[技术] by (71.8m points)

qt - Macro expansion in moc

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The easy way to make that is modifing moc preprocessor.

  1. Go to Qt source code to qtbase/src/tools/moc e.g. (C:QtQt5.0.15.0.1Srcqtbasesrcoolsmoc)
  2. Create a new copy of moc project e.g. moc_modified
  3. Open the copy of moc project with QtCreator (moc.pro file)
  4. Open preprocessor.cpp file and go to Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file) function
  5. 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);
    ...
    
  6. Compile the new source code. The moc executable file is generated to /bin folder (if you use windows look at c:/bin/moc.exe)

  7. Go to Qt bin (C:QtQt5.0.15.0.1msvc2010in) folder and rename moc executable file e.g. moc.exe.bak

  8. Copy new moc executable file to Qt bin folder.

  9. 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("([^,
]+)"));
    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 :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...