where "c" is the name of the class that owns the method, and "name" is the name of the method you want to find.

Note that this returns a Smoke::ModuleIndex, not just a Smoke::Index. The ModuleIndex is defined as:

Note that this returns a Smoke::ModuleIndex, not just a Smoke::Index. The ModuleIndex is defined as:

Line 30:

Line 31:

};

};

</pre>

</pre>

+

This struct pairs a given smoke object with a specific index. If you have multiple Smoke objects, a specific Smoke::Index only has meaning within the context of the Smoke object to which it belongs.

−

However, you can't just give it the class name and the method name. That's not enough information for Smoke to find the correct method. You also have to supply Smoke with some information about the number and types of arguments. This information gets tacked onto the end of the method name, using the following mapping:

+

However, you can't just give findMethod() the raw the method name. That's not enough information for Smoke to find the correct method. You also have to supply Smoke with some information about the number and types of arguments that the method accepts. This information gets tacked onto the end of the method name, using the following mapping:

{|

{|

|Scalar variable

|Scalar variable

Line 77:

Line 79:

</pre>

</pre>

−

This gives the index into Smoke's array of methods.

+

methodIdx is now the index into Smoke's array of methods.

==Building the argument stack==

==Building the argument stack==

Line 143:

Line 145:

</pre>

</pre>

−

The reason we pass 0 for the 2nd argument in this example is that we're calling a constructor, so we're not operating on an object.

+

In this example, we pass 0 as the second argument. This argument is for the object being operated on. We pass 0 in this instance because we're calling a constructor, so we're not operating on an object. If we were going to call a method like "label->show()", then we would instead write

Revision as of 05:28, 9 April 2010

Contents

Introduction

This page aims to document how the Smoke API works outside of the bounds of any target language specific (Ruby, Perl, etc) details.

What is Smoke?

Smoke was designed to make writing bindings to a given library have a common interface. It parses a library's header files, and indexes a complete list of methods, classes, and types that are defined by the library. It also includes a other meta info, like if a method call is declared static or const, if the method is a constructor or destructor, etc.

Smoke is not Qt specific. However, it is commonly used to write bindings to the Qt library.

Since Smoke just provides a common interface to a library, it means that multiple language bindings can use the same Smoke object to interface with that library.

Getting started with Smoke

When making a method call, regardless of language specific syntax, you're always going to have a method name, an object to operate on, and some arguments. You pass the object straight to Smoke as a void pointer, but we'll discuss the other two parts next.

Finding the method index

Smoke stores a giant array of methods. In order to make a method call, you give Smoke the index into this array that corresponds to the method you want to call. Each index is of type Smoke::Index, which is just typedef'd to a short. Obviously, most of the time you're just going to know the name of the method, not whatever Smoke's internal index is. So, Smoke provides the findMethod method:

inline ModuleIndex findMethod(const char *c, const char *name)

where "c" is the name of the class that owns the method, and "name" is the name of the method you want to find.

Note that this returns a Smoke::ModuleIndex, not just a Smoke::Index. The ModuleIndex is defined as:

struct ModuleIndex {
Smoke* smoke;
Index index;
};

This struct pairs a given smoke object with a specific index. If you have multiple Smoke objects, a specific Smoke::Index only has meaning within the context of the Smoke object to which it belongs.

However, you can't just give findMethod() the raw the method name. That's not enough information for Smoke to find the correct method. You also have to supply Smoke with some information about the number and types of arguments that the method accepts. This information gets tacked onto the end of the method name, using the following mapping:

Scalar variable

$

Array or hash variable

@

Object

#

For instance, if we wanted to instantiate a QLabel with Smoke, we'd first get the Smoke::Index for the "QLabel::QLabel" method. If we look at the Qt documentation, we can see we can construct a QLabel like so:

We already know the class name ("QLabel"), but how do we determine what to pass for the method name/argument info combo? Well, it starts with the method name, and then there's 3 arguments, a QString (scalar), a QWidget* (object), and an enum Qt::WindowFlags (scalar). So that's scalar,object,scalar, which corresponds to $#$. So the method name we pass to findMethod() is "QLabel$#$".

Smoke::ModuleIndex mi = smoke->findMethod( "QLabel", "QLabel$#$" );

This however does not give us the Smoke::Index we need in order to call a method. For some methods, the "munged" method name, aka "QLabel$#$" in our example, is not unique enough to resolve to a single method. These methods require further processing to determine the correct method to call, which is beyond the scope of this intro document. Just remember for now that the return value can be interpreted as follows:

One important thing to note is that Smoke uses the Smoke::Stack's 0'th element for the method call's return value. So, when declaring your Smoke::Stack, you have to give it a size of <number of arguments>+1.

Continuing with our QLabel example, we can construct the Smoke::StackItem like this:

Smoke::StackItem stack[4];
stack[1].s_voidp = (void*)"Hello, World!";
// A null value for the parent will construct a top-level widget
stack[2].s_voidp = 0;
// Qt::Dialog is declared in the Qt::WindowType enum and WindowFlags type is a typedef for QFlags<WindowType>.
stack[3].s_enum = Qt::Dialog;

Making a method call

Now we have all the information we need to make a method call. There's 2 new structs that Smoke defines to keep track of info about methods and classes, and one new typedef we're interested in:

The Class::classFn element gives a function pointer that actually dispatches the method call for us. We get that by looking up what class this method call belongs to. We can then pass our data to that method call.

In this example, we pass 0 as the second argument. This argument is for the object being operated on. We pass 0 in this instance because we're calling a constructor, so we're not operating on an object. If we were going to call a method like "label->show()", then we would instead write

fn(m->method, (void*)label, stack);

Getting the return value

As mentioned previously, callMethod() will put the return value of the method call on the 0'th element of the Smoke::Stack provided to it. So to get our QLabel back, we can do this: