Qt 之实用程序 moc 学习

来源:互联网 发布:js运行 编辑:程序博客网 时间:2024/05/18 10:48

本文关注Qt的工具程序 moc 本身。

moc : 元对象编译器(Meta-Object Compiler)

命令行选项

moc -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED hled.h -o moc_hled.cpp

运行 moc -h 或者查看Manual关注几个选项:

-I<dir>

add dir to the include path for header files

-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 name

其中:

  • -D -U

    • 定义和反定义宏, (注:内部默认定义Q_MOC_RUN__cplusplus两个宏)

  • -i -f

    • 控制是否包含include语句,默认是自动(对比Q_OBJECT这个宏分别出现在*.h和*.cpp时生成的文件的不同)

moc 的处理分两个阶段(共3个步骤):

  • Preprocessor
  • Moc
    • parse
    • generate

    Preprocessor pp;    Moc moc;    pp.macros["Q_MOC_RUN"];    pp.macros["__cplusplus"];...    // 1. preprocess    moc.symbols = pp.preprocessed(moc.filename, in);    fclose(in);    if (!pp.preprocessOnly) {        // 2. parse        moc.parse();    }    // 3. and output meta object code    if (pp.preprocessOnly) {        fprintf(out, "%s\n", composePreprocessorOutput(moc.symbols).constData());    } else {        moc.generate(out);    }

词法分析

lexical analysis

moc 将输入文件解析成一个 Token (即symbols) 的列表

moc.symbols = pp.preprocessed(moc.filename, in);

词法分析的基础是一个有限状态机(fix me?),源码位于 $QTDIR/src/tools/moc 下的

  • keywords.cpp
  • ppkeywords.cpp

这两个文件是由$QTDIR/src/tools/moc/util下的工具程序生成的,generate_keywords.cpp 文件中是原始的(可读的) 关键词和Token的对应关系

...    { "while", "WHILE" },    { "do", "DO" },    { "for", "FOR" },    { "break", "BREAK" },    { "continue", "CONTINUE" },    { "goto", "GOTO" },    { "return", "RETURN" },    { "Q_OBJECT", "Q_OBJECT_TOKEN" },    { "Q_GADGET", "Q_GADGET_TOKEN" },    { "Q_PROPERTY", "Q_PROPERTY_TOKEN" },    { "Q_ENUMS", "Q_ENUMS_TOKEN" },    { "Q_FLAGS", "Q_FLAGS_TOKEN" },    { "Q_DECLARE_FLAGS", "Q_DECLARE_FLAGS_TOKEN" },    { "Q_DECLARE_INTERFACE", "Q_DECLARE_INTERFACE_TOKEN" },...

语法分析(?)

在 Tokenization 之后,需要parse某些我们关注的Token,此时需要处理Token之间的关系。

moc.parse();

比如:对于 Q_DECLARE_METATYPE

void Moc::parseDeclareMetatype(){    next(LPAREN);    QByteArray typeName = lexemUntil(RPAREN);    typeName.remove(0, 1);    typeName.chop(1);    metaTypes.append(typeName);}

对于 signals

void Moc::parseSignals(ClassDef *def){    next(COLON);    while (inClass(def) && hasNext()) {...        FunctionDef funcDef;        funcDef.access = FunctionDef::Protected;        parseFunction(&funcDef);        if (funcDef.isVirtual)            warning("Signals cannot be declared virtual");        if (funcDef.inlineCode)            error("Not a signal declaration");        def->signalList += funcDef;        while (funcDef.arguments.size() > 0 && funcDef.arguments.last().isDefault) {            funcDef.wasCloned = true;            funcDef.arguments.removeLast();            def->signalList += funcDef;        }    }}

output

moc.generate(out);

将metatype信息转换成代码并输出是通过另一个类来完成的:

    for (i = 0; i < classList.size(); ++i) {        Generator generator(&classList[i], metaTypes, out);        generator.generateCode();    }

从类定义大致可以猜出它做了什么

class Generator{    FILE *out;    ClassDef *cdef;    QVector<uint> meta_data;public:    Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, FILE *outfile = 0);    void generateCode();    QMetaObject *generateMetaObject(bool ignoreProperties);private:    void generateClassInfos();    void generateFunctions(QList<FunctionDef> &list, const char *functype, int type);    void generateEnums(int index);    void generateProperties();    void generateMetacall();    void generateStaticMetacall(const QByteArray &prefix);    void generateSignal(FunctionDef *def, int index);...

参考

  • http://doc.qt.nokia.com/4.7/moc.html


原创粉丝点击