moc中的宏扩展

时间:2010-11-07 21:05:49

标签: qt qt4 preprocessor moc

我想使用Q_CLASSINFO宏存储一些类信息。但是我想将它包装在我自己的宏中,例如:

#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 )
}

不幸的是,moc不会扩展宏,因此不会添加Q_CLASSINFO。

我已尝试使用已经预处理的源提供moc,但它在某些包含的Qt类中失败。

您知道任何解决方法吗?

2 个答案:

答案 0 :(得分:11)

简单的方法是修改moc预处理器。

  1. 转到Qt源代码 qtbase / src / tools / moc ,例如(C:\ Qt的\ Qt5.0.1 \ 5.0.1 \ SRC \ qtbase \ SRC \工具\ MOC)
  2. 创建moc项目的新副本,例如moc_modified
  3. 使用QtCreator(moc.pro文件)
  4. 打开moc项目的副本
  5. 打开preprocessor.cpp文件并转到 Symbols Preprocessor :: preprocessed(const QByteArray& filename,QIODevice * file)功能
  6. 搜索专栏:

    // 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);
    ...
    
  7. 编译新的源代码。 moc可执行文件生成到/ bin文件夹(如果你使用windows查看c:/bin/moc.exe)

  8. 转到Qt bin(C:\ Qt \ Qt5.0.1 \ 5.0.1 \ msvc2010 \ bin)文件夹并重命名moc可执行文件,例如moc.exe.bak

  9. 将新的moc可执行文件复制到Qt bin文件夹。

  10. 在您当前的应用中,您需要创建一个宏,例如:

    #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
    
  11. 最后我告诉你我自己的函数replaceCustomMacros的源代码:

    此函数将 Q_SERVICE_INFO(方法,路径,类型)宏转换为 Q_CLASSINFO(&#34; srv://方法&#34;,&#34;类型:路径&#34 ;)

    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;
    
    }
    

    我没有在互联网上找到任何特定的解决方案,然后我发布了这个解决方案。

    祝你好运:)

答案 1 :(得分:4)

除了滚动你自己的pre-moc预处理器之外,没有。例如,MeeGo Touch就是这样做的。由于诺基亚自己也在这样做,我相信别无他法。

在你的情况下,它只涉及将你自己的声明翻译成Q_CLASSINFO,所以它不应该太难。如果你使用qmake,它也可以添加到构建序列中。