|
Packit |
ae235b |
|
|
Packit |
ae235b |
<html>
|
|
Packit |
ae235b |
<head>
|
|
Packit |
ae235b |
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
Packit |
ae235b |
<title>Exporting a C API: GObject Reference Manual</title>
|
|
Packit |
ae235b |
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
|
|
Packit |
ae235b |
<link rel="home" href="index.html" title="GObject Reference Manual">
|
|
Packit |
ae235b |
<link rel="up" href="chapter-intro.html" title="Background">
|
|
Packit |
ae235b |
<link rel="prev" href="chapter-intro.html" title="Background">
|
|
Packit |
ae235b |
<link rel="next" href="chapter-gtype.html" title="The GLib Dynamic Type System">
|
|
Packit |
ae235b |
<meta name="generator" content="GTK-Doc V1.27 (XML mode)">
|
|
Packit |
ae235b |
<link rel="stylesheet" href="style.css" type="text/css">
|
|
Packit |
ae235b |
</head>
|
|
Packit |
ae235b |
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Exporting a C API
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
C APIs are defined by a set of functions and global variables which are usually exported from a
|
|
Packit |
ae235b |
binary. C functions have an arbitrary number of arguments and one return value. Each function is thus
|
|
Packit |
ae235b |
uniquely identified by the function name and the set of C types which describe the function arguments
|
|
Packit |
ae235b |
and return value. The global variables exported by the API are similarly identified by their name and
|
|
Packit |
ae235b |
their type.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
A C API is thus merely defined by a set of names to which a set of types are associated. If you know the
|
|
Packit |
ae235b |
function calling convention and the mapping of the C types to the machine types used by the platform you
|
|
Packit |
ae235b |
are on, you can resolve the name of each function to find where the code associated to this function
|
|
Packit |
ae235b |
is located in memory, and then construct a valid argument list for the function. Finally, all you have to
|
|
Packit |
ae235b |
do is trigger a call to the target C function with the argument list.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
For the sake of discussion, here is a sample C function and the associated 32 bit x86
|
|
Packit |
ae235b |
assembly code generated by GCC on a Linux computer:
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
1
|
|
Packit |
ae235b |
2
|
|
Packit |
ae235b |
3
|
|
Packit |
ae235b |
4
|
|
Packit |
ae235b |
5
|
|
Packit |
ae235b |
6
|
|
Packit |
ae235b |
7
|
|
Packit |
ae235b |
8
|
|
Packit |
ae235b |
9
|
|
Packit |
ae235b |
10
|
|
Packit |
ae235b |
11
|
|
Packit |
ae235b |
12
|
|
Packit |
ae235b |
13
|
|
Packit |
ae235b |
14
|
|
Packit |
ae235b |
15
|
|
Packit |
ae235b |
16
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
function_foo (int foo)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
int
|
|
Packit |
ae235b |
main (int argc,
|
|
Packit |
ae235b |
char *argv[])
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
function_foo (10);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
push $0xa
|
|
Packit |
ae235b |
call 0x80482f4 <function_foo>
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
The assembly code shown above is pretty straightforward: the first instruction pushes
|
|
Packit |
ae235b |
the hexadecimal value 0xa (decimal value 10) as a 32-bit integer on the stack and calls
|
|
Packit |
ae235b |
function_foo . As you can see, C function calls are implemented by
|
|
Packit |
ae235b |
GCC as native function calls (this is probably the fastest implementation possible).
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Now, let's say we want to call the C function function_foo from
|
|
Packit |
ae235b |
a Python program. To do this, the Python interpreter needs to:
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Find where the function is located. This probably means finding the binary generated by the C compiler
|
|
Packit |
ae235b |
which exports this function.
|
|
Packit |
ae235b |
Load the code of the function in executable memory.
|
|
Packit |
ae235b |
Convert the Python parameters to C-compatible parameters before calling
|
|
Packit |
ae235b |
the function.
|
|
Packit |
ae235b |
Call the function with the right calling convention.
|
|
Packit |
ae235b |
Convert the return values of the C function to Python-compatible
|
|
Packit |
ae235b |
variables to return them to the Python code.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
The process described above is pretty complex and there are a lot of ways to make it entirely automatic
|
|
Packit |
ae235b |
and transparent to C and Python programmers:
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
The first solution is to write by hand a lot of glue code, once for each function exported or imported,
|
|
Packit |
ae235b |
which does the Python-to-C parameter conversion and the C-to-Python return value conversion. This glue code is then
|
|
Packit |
ae235b |
linked with the interpreter which allows Python programs to call Python functions which delegate work to
|
|
Packit |
ae235b |
C functions.
|
|
Packit |
ae235b |
Another, nicer solution is to automatically generate the glue code, once for each function exported or
|
|
Packit |
ae235b |
imported, with a special compiler which
|
|
Packit |
ae235b |
reads the original function signature.
|
|
Packit |
ae235b |
The solution used by GLib is to use the GType library which holds at runtime a description of
|
|
Packit |
ae235b |
all the objects manipulated by the programmer. This so-called dynamic type
|
|
Packit |
ae235b |
<sup class="footnote">[1]</sup>
|
|
Packit |
ae235b |
library is then used by special generic glue code to automatically convert function parameters and
|
|
Packit |
ae235b |
function calling conventions between different runtime domains.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
|
|
Packit |
ae235b |
boundaries is written once: the figure below states this more clearly.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Figure 1.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
|
|
Packit |
ae235b |
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
|
|
Packit |
ae235b |
is no need to generate huge amounts of glue code either automatically or by hand.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Although that goal was arguably laudable, its pursuit has had a major influence on
|
|
Packit |
ae235b |
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
|
|
Packit |
ae235b |
of the features exposed in the following chapters if they forget that the GType/GObject library
|
|
Packit |
ae235b |
was not only designed to offer OO-like features to C programmers but also transparent
|
|
Packit |
ae235b |
cross-language interoperability.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
There are numerous different implementations of dynamic type systems: all C++
|
|
Packit |
ae235b |
compilers have one, Java and .NET have one too. A dynamic type system allows you
|
|
Packit |
ae235b |
to get information about every instantiated object at runtime. It can be implemented
|
|
Packit |
ae235b |
by a process-specific database: every new object created registers the characteristics
|
|
Packit |
ae235b |
of its associated type in the type system. It can also be implemented by introspection
|
|
Packit |
ae235b |
interfaces. The common point between all these different type systems and implementations
|
|
Packit |
ae235b |
is that they all allow you to query for object metadata at runtime.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Generated by GTK-Doc V1.27
|
|
Packit |
ae235b |
</body>
|
|
Packit |
ae235b |
</html>
|