5

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 クラスで失敗します。

これに対する回避策を知っていますか?

4

2 に答える 2

11

これを作る簡単な方法は、moc プリプロセッサを変更することです。

  1. Qt ソース コードをqtbase/src/tools/mocに移動します(例: (C:\Qt\Qt5.0.1\5.0.1\Src\qtbase\src\tools\moc))。
  2. moc プロジェクトの新しいコピーを作成します。例: moc_modified
  3. moc プロジェクトのコピーを QtCreator で開きます (moc.pro ファイル)
  4. preprocessor.cpp ファイルを開き、Symbols Preprocessor::preprocessed(const QByteArray &filename, QIODevice *file)関数に移動します。
  5. 次の行を検索します。

    // 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. 新しいソース コードをコンパイルします。moc 実行可能ファイルが /bin フォルダーに生成されます (Windows を使用している場合は、c:/bin/moc.exe を参照してください)。

  7. Qt bin (C:\Qt\Qt5.0.1\5.0.1\msvc2010\bin) フォルダーに移動し、moc 実行可能ファイルの名前を変更します (例: moc.exe.bak)。

  8. 新しい moc 実行可能ファイルを Qt bin フォルダーにコピーします。

  9. 現在のアプリでは、たとえば次のようにマクロを作成する必要があります。

    #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
    

最後に、関数 replaceCustomMacros の独自のソース コードを示します。

この関数は、Q_SERVICE_INFO(メソッド、パス、タイプ)マクロを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;

}

インターネットで特定の解決策が見つからなかったので、この解決策を投稿しました。

幸運を :)

于 2013-02-09T02:39:29.290 に答える
4

独自のプリモックプリプロセッサをローリングする以外は、できません。たとえば、MeeGoTouchはそれを実行します。ノキア自身がやっているので、他に方法はないと思います。

あなたの場合、それはあなた自身の宣言をQ_CLASSINFOに変換することだけを含むでしょう、それでそれはそれほど難しくないはずです。qmakeを使用する場合は、ビルドシーケンスに追加することもできます。

于 2010-11-08T18:42:31.263 に答える