您的位置:首页 > 编程语言 > Qt开发

Qt 之实用程序 moc 学习

2011-08-06 11:56 471 查看
本文关注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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息