本文关注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);
...
7545

被折叠的 条评论
为什么被折叠?



